diff --git a/v3/pkg/services/notifications/notifications_darwin.go b/v3/pkg/services/notifications/notifications_darwin.go index 2789324ae..426b7a411 100644 --- a/v3/pkg/services/notifications/notifications_darwin.go +++ b/v3/pkg/services/notifications/notifications_darwin.go @@ -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) diff --git a/v3/pkg/services/notifications/notifications_darwin.h b/v3/pkg/services/notifications/notifications_darwin.h index c6bacaf79..6848dc68e 100644 --- a/v3/pkg/services/notifications/notifications_darwin.h +++ b/v3/pkg/services/notifications/notifications_darwin.h @@ -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); diff --git a/v3/pkg/services/notifications/notifications_darwin.m b/v3/pkg/services/notifications/notifications_darwin.m index 5ac99c0a3..8329cdc26 100644 --- a/v3/pkg/services/notifications/notifications_darwin.m +++ b/v3/pkg/services/notifications/notifications_darwin.m @@ -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); } }]; }