mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
refactor macos
This commit is contained in:
parent
d9af6dec32
commit
833d8ec7dc
3 changed files with 29 additions and 77 deletions
|
|
@ -9,13 +9,10 @@ package notifications
|
|||
*/
|
||||
import "C"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
type notificationChannel struct {
|
||||
|
|
@ -28,13 +25,21 @@ var (
|
|||
notificationChannelsLock sync.Mutex
|
||||
nextChannelID int
|
||||
)
|
||||
var BundleIdentifierError = fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
|
||||
const AppleDefaultActionIdentifier = "com.apple.UNNotificationDefaultActionIdentifier"
|
||||
|
||||
// Creates a new Notifications Service.
|
||||
// Your app must be packaged and signed for this feature to work.
|
||||
func New() *Service {
|
||||
if !CheckBundleIdentifier() {
|
||||
panic("\nError: Cannot use the notification API in development mode on macOS.\n" +
|
||||
"Notifications require the app to be properly bundled with a bundle identifier and signed.\n" +
|
||||
"To use the notification API on macOS:\n" +
|
||||
" 1. Build and package your app using 'wails3 package'\n" +
|
||||
" 2. Sign the packaged .app\n" +
|
||||
" 3. Run the signed .app bundle")
|
||||
}
|
||||
|
||||
notificationServiceLock.Lock()
|
||||
defer notificationServiceLock.Unlock()
|
||||
|
||||
|
|
@ -44,29 +49,12 @@ func New() *Service {
|
|||
return NotificationService
|
||||
}
|
||||
|
||||
// ServiceStartup is called when the service is loaded.
|
||||
func (ns *Service) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return BundleIdentifierError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServiceShutdown is called when the service is unloaded.
|
||||
func (ns *Service) ServiceShutdown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckBundleIdentifier() bool {
|
||||
return bool(C.checkBundleIdentifier())
|
||||
}
|
||||
|
||||
// RequestNotificationAuthorization requests permission for notifications.
|
||||
func (ns *Service) RequestNotificationAuthorization() (bool, error) {
|
||||
if !CheckBundleIdentifier() {
|
||||
return false, BundleIdentifierError
|
||||
}
|
||||
|
||||
id, resultCh := registerChannel()
|
||||
|
||||
C.requestNotificationAuthorization(C.int(id))
|
||||
|
|
@ -77,10 +65,6 @@ func (ns *Service) RequestNotificationAuthorization() (bool, error) {
|
|||
|
||||
// CheckNotificationAuthorization checks current notification permission status.
|
||||
func (ns *Service) CheckNotificationAuthorization() (bool, error) {
|
||||
if !CheckBundleIdentifier() {
|
||||
return false, BundleIdentifierError
|
||||
}
|
||||
|
||||
id, resultCh := registerChannel()
|
||||
|
||||
C.checkNotificationAuthorization(C.int(id))
|
||||
|
|
@ -91,9 +75,6 @@ func (ns *Service) CheckNotificationAuthorization() (bool, error) {
|
|||
|
||||
// SendNotification sends a basic notification with a unique identifier, title, subtitle, and body.
|
||||
func (ns *Service) SendNotification(options NotificationOptions) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
cIdentifier := C.CString(options.ID)
|
||||
cTitle := C.CString(options.Title)
|
||||
cSubtitle := C.CString(options.Subtitle)
|
||||
|
|
@ -106,13 +87,14 @@ func (ns *Service) SendNotification(options NotificationOptions) error {
|
|||
var cDataJSON *C.char
|
||||
if options.Data != nil {
|
||||
jsonData, err := json.Marshal(options.Data)
|
||||
if err == nil {
|
||||
cDataJSON = C.CString(string(jsonData))
|
||||
defer C.free(unsafe.Pointer(cDataJSON))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal notification data: %w", err)
|
||||
}
|
||||
cDataJSON = C.CString(string(jsonData))
|
||||
defer C.free(unsafe.Pointer(cDataJSON))
|
||||
}
|
||||
|
||||
C.sendNotification(cIdentifier, cTitle, cSubtitle, cBody, cDataJSON, nil)
|
||||
C.sendNotification(cIdentifier, cTitle, cSubtitle, cBody, cDataJSON)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -120,9 +102,6 @@ func (ns *Service) SendNotification(options NotificationOptions) error {
|
|||
// A NotificationCategory must be registered with RegisterNotificationCategory first. The `CategoryID` must match the registered category.
|
||||
// If a NotificationCategory is not registered a basic notification will be sent.
|
||||
func (ns *Service) SendNotificationWithActions(options NotificationOptions) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
cIdentifier := C.CString(options.ID)
|
||||
cTitle := C.CString(options.Title)
|
||||
cSubtitle := C.CString(options.Subtitle)
|
||||
|
|
@ -134,31 +113,29 @@ func (ns *Service) SendNotificationWithActions(options NotificationOptions) erro
|
|||
defer C.free(unsafe.Pointer(cBody))
|
||||
defer C.free(unsafe.Pointer(cCategoryID))
|
||||
|
||||
var cActionsJSON *C.char
|
||||
var cDataJSON *C.char
|
||||
if options.Data != nil {
|
||||
jsonData, err := json.Marshal(options.Data)
|
||||
if err == nil {
|
||||
cActionsJSON = C.CString(string(jsonData))
|
||||
defer C.free(unsafe.Pointer(cActionsJSON))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal notification data: %w", err)
|
||||
}
|
||||
cDataJSON = C.CString(string(jsonData))
|
||||
defer C.free(unsafe.Pointer(cDataJSON))
|
||||
}
|
||||
|
||||
C.sendNotificationWithActions(cIdentifier, cTitle, cSubtitle, cBody, cCategoryID, cActionsJSON, nil)
|
||||
C.sendNotificationWithActions(cIdentifier, cTitle, cSubtitle, cBody, cCategoryID, cDataJSON)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterNotificationCategory registers a new NotificationCategory to be used with SendNotificationWithActions.
|
||||
// Registering a category with the same name as a previously registered NotificationCategory will override it.
|
||||
func (ns *Service) RegisterNotificationCategory(category NotificationCategory) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
cCategoryID := C.CString(category.ID)
|
||||
defer C.free(unsafe.Pointer(cCategoryID))
|
||||
|
||||
actionsJSON, err := json.Marshal(category.Actions)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to marshal notification category: %w", err)
|
||||
}
|
||||
cActionsJSON := C.CString(string(actionsJSON))
|
||||
defer C.free(unsafe.Pointer(cActionsJSON))
|
||||
|
|
@ -178,9 +155,6 @@ func (ns *Service) RegisterNotificationCategory(category NotificationCategory) e
|
|||
|
||||
// RemoveNotificationCategory remove a previously registered NotificationCategory.
|
||||
func (ns *Service) RemoveNotificationCategory(categoryId string) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
cCategoryID := C.CString(categoryId)
|
||||
defer C.free(unsafe.Pointer(cCategoryID))
|
||||
|
||||
|
|
@ -190,18 +164,12 @@ func (ns *Service) RemoveNotificationCategory(categoryId string) error {
|
|||
|
||||
// RemoveAllPendingNotifications removes all pending notifications.
|
||||
func (ns *Service) RemoveAllPendingNotifications() error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
C.removeAllPendingNotifications()
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemovePendingNotification removes a pending notification matching the unique identifier.
|
||||
func (ns *Service) RemovePendingNotification(identifier string) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
cIdentifier := C.CString(identifier)
|
||||
defer C.free(unsafe.Pointer(cIdentifier))
|
||||
C.removePendingNotification(cIdentifier)
|
||||
|
|
@ -210,18 +178,12 @@ func (ns *Service) RemovePendingNotification(identifier string) error {
|
|||
|
||||
// RemoveAllDeliveredNotifications removes all delivered notifications.
|
||||
func (ns *Service) RemoveAllDeliveredNotifications() error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
C.removeAllDeliveredNotifications()
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveDeliveredNotification removes a delivered notification matching the unique identifier.
|
||||
func (ns *Service) RemoveDeliveredNotification(identifier string) error {
|
||||
if !CheckBundleIdentifier() {
|
||||
return fmt.Errorf("notifications require a bundled application with a unique bundle identifier")
|
||||
}
|
||||
cIdentifier := C.CString(identifier)
|
||||
defer C.free(unsafe.Pointer(cIdentifier))
|
||||
C.removeDeliveredNotification(cIdentifier)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
bool checkBundleIdentifier(void);
|
||||
void requestNotificationAuthorization(int channelID);
|
||||
void checkNotificationAuthorization(int channelID);
|
||||
void sendNotification(const char *identifier, const char *title, const char *subtitle, const char *body, const char *data_json, void *completion);
|
||||
void sendNotificationWithActions(const char *identifier, const char *title, const char *subtitle, const char *body, const char *categoryId, const char *actions_json, void *completion);
|
||||
void sendNotification(const char *identifier, const char *title, const char *subtitle, const char *body, const char *data_json);
|
||||
void sendNotificationWithActions(const char *identifier, const char *title, const char *subtitle, const char *body, const char *categoryId, const char *actions_json);
|
||||
void registerNotificationCategory(const char *categoryId, const char *actions_json, bool hasReplyField, const char *replyPlaceholder, const char *replyButtonTitle);
|
||||
void removeNotificationCategory(const char *categoryId);
|
||||
void removeAllPendingNotifications(void);
|
||||
|
|
|
|||
|
|
@ -73,12 +73,6 @@ static void ensureDelegateInitialized(void) {
|
|||
bool checkBundleIdentifier(void) {
|
||||
NSBundle *main = [NSBundle mainBundle];
|
||||
if (main.bundleIdentifier == nil) {
|
||||
NSLog(@"Error: Cannot use the notification API in development mode.\n"
|
||||
" Notifications require the app to be properly bundled with a bundle identifier and signed.\n"
|
||||
" To test notifications:\n"
|
||||
" 1. Build and package your app using 'wails3 package'\n"
|
||||
" 2. Sign the packaged .app\n"
|
||||
" 3. Run the signed .app bundle");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -109,7 +103,7 @@ void checkNotificationAuthorization(int channelID) {
|
|||
}];
|
||||
}
|
||||
|
||||
void sendNotification(const char *identifier, const char *title, const char *subtitle, const char *body, const char *data_json, void *completion) {
|
||||
void sendNotification(const char *identifier, const char *title, const char *subtitle, const char *body, const char *data_json) {
|
||||
ensureDelegateInitialized();
|
||||
|
||||
NSString *nsIdentifier = [NSString stringWithUTF8String:identifier];
|
||||
|
|
@ -136,7 +130,6 @@ void sendNotification(const char *identifier, const char *title, const char *sub
|
|||
content.body = nsBody;
|
||||
content.sound = [UNNotificationSound defaultSound];
|
||||
|
||||
// Add custom data if available
|
||||
if (customData.count > 0) {
|
||||
content.userInfo = customData;
|
||||
}
|
||||
|
|
@ -146,15 +139,14 @@ void sendNotification(const char *identifier, const char *title, const char *sub
|
|||
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:nsIdentifier content:content trigger:trigger];
|
||||
|
||||
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
|
||||
if (completion != NULL) {
|
||||
void (^callback)(NSError *) = completion;
|
||||
callback(error);
|
||||
if (error) {
|
||||
NSLog(@"Error scheduling notification: %@", error.localizedDescription);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
void sendNotificationWithActions(const char *identifier, const char *title, const char *subtitle,
|
||||
const char *body, const char *categoryId, const char *actions_json, void *completion) {
|
||||
const char *body, const char *categoryId, const char *actions_json) {
|
||||
ensureDelegateInitialized();
|
||||
|
||||
NSString *nsIdentifier = [NSString stringWithUTF8String:identifier];
|
||||
|
|
@ -185,7 +177,6 @@ void sendNotificationWithActions(const char *identifier, const char *title, cons
|
|||
content.sound = [UNNotificationSound defaultSound];
|
||||
content.categoryIdentifier = nsCategoryId;
|
||||
|
||||
// Add custom data if available
|
||||
if (customData.count > 0) {
|
||||
content.userInfo = customData;
|
||||
}
|
||||
|
|
@ -195,9 +186,8 @@ void sendNotificationWithActions(const char *identifier, const char *title, cons
|
|||
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:nsIdentifier content:content trigger:trigger];
|
||||
|
||||
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
|
||||
if (completion != NULL) {
|
||||
void (^callback)(NSError *) = completion;
|
||||
callback(error);
|
||||
if (error) {
|
||||
NSLog(@"Error scheduling notification: %@", error.localizedDescription);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue