From fc94fa3935ae0190e0af1152c298f661cd946429 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 19 Aug 2021 21:36:38 +0100 Subject: [PATCH] Replace deprecated NSNotificationCentre with UNNotificationCentre Sadly this requires the apps to be signed, so it only really works for store-distributed apps. But it's required because of the deprecations. Fixes #1833 --- app/app_darwin.go | 74 ++++++++++++------------------------- app/app_darwin.m | 78 +++++++++++++++++++-------------------- app/app_desktop_darwin.go | 54 +++++++++++++++++++++++++++ app/app_desktop_darwin.m | 18 +++++++++ app/app_mobile_ios.go | 9 ----- app/app_mobile_ios.m | 37 ------------------- 6 files changed, 132 insertions(+), 138 deletions(-) create mode 100644 app/app_desktop_darwin.go create mode 100644 app/app_desktop_darwin.m diff --git a/app/app_darwin.go b/app/app_darwin.go index bca7a56726..29c9144a75 100644 --- a/app/app_darwin.go +++ b/app/app_darwin.go @@ -1,75 +1,39 @@ // +build !ci -// +build !ios - package app /* #cgo CFLAGS: -x objective-c -#cgo LDFLAGS: -framework Foundation +#cgo LDFLAGS: -framework Foundation -framework UserNotifications -#include +#include +#include bool isBundled(); -bool isDarkMode(); -void sendNotification(const char *title, const char *content); -void watchTheme(); +void sendNotification(char *title, char *content); */ import "C" import ( "fmt" - "net/url" - "os" - "path/filepath" "strings" "unsafe" "fyne.io/fyne/v2" - "fyne.io/fyne/v2/theme" - "golang.org/x/sys/execabs" ) -func defaultVariant() fyne.ThemeVariant { - if C.isDarkMode() { - return theme.VariantDark - } - return theme.VariantLight -} - -func rootConfigDir() string { - homeDir, _ := os.UserHomeDir() - - desktopConfig := filepath.Join(filepath.Join(homeDir, "Library"), "Preferences") - return filepath.Join(desktopConfig, "fyne") -} - -func (a *fyneApp) OpenURL(url *url.URL) error { - cmd := a.exec("open", url.String()) - cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr - return cmd.Run() -} - func (a *fyneApp) SendNotification(n *fyne.Notification) { if C.isBundled() { - title := C.CString(n.Title) - defer C.free(unsafe.Pointer(title)) - content := C.CString(n.Content) - defer C.free(unsafe.Pointer(content)) + titleStr := C.CString(n.Title) + defer C.free(unsafe.Pointer(titleStr)) + contentStr := C.CString(n.Content) + defer C.free(unsafe.Pointer(contentStr)) - C.sendNotification(title, content) + C.sendNotification(titleStr, contentStr) return } - title := escapeNotificationString(n.Title) - content := escapeNotificationString(n.Content) - template := `display notification "%s" with title "%s"` - script := fmt.Sprintf(template, content, title) - - err := execabs.Command("osascript", "-e", script).Start() - if err != nil { - fyne.LogError("Failed to launch darwin notify script", err) - } + fallbackNotification(n.Title, n.Content) } func escapeNotificationString(in string) string { @@ -77,11 +41,19 @@ func escapeNotificationString(in string) string { return strings.ReplaceAll(noSlash, "\"", "\\\"") } -//export themeChanged -func themeChanged() { - fyne.CurrentApp().Settings().(*settings).setupTheme() +//export fallbackSend +func fallbackSend(cTitle, cContent *C.char) { + title := C.GoString(cTitle) + content := C.GoString(cContent) + fallbackNotification(title, content) } -func watchTheme() { - C.watchTheme() +func fallbackNotification(title, content string) { + template := `display notification "%s" with title "%s"` + script := fmt.Sprintf(template, escapeNotificationString(content), escapeNotificationString(title)) + + err := execabs.Command("osascript", "-e", script).Start() + if err != nil { + fyne.LogError("Failed to launch darwin notify script", err) + } } diff --git a/app/app_darwin.m b/app/app_darwin.m index 3f69392ba2..da7c63f487 100644 --- a/app/app_darwin.m +++ b/app/app_darwin.m @@ -1,55 +1,51 @@ // +build !ci -// +build !ios -extern void themeChanged(); +#import -#import +static int notifyNum = 0; -@interface FyneUserNotificationCenterDelegate : NSObject +extern void fallbackSend(char *cTitle, char *cBody); -- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center - shouldPresentNotification:(NSUserNotification*)notification; +void doSendNotification(UNUserNotificationCenter *center, NSString *title, NSString *body) { + UNMutableNotificationContent *content = [UNMutableNotificationContent new]; + [content autorelease]; + content.title = title; + content.body = body; -@end + notifyNum++; + NSString *identifier = [NSString stringWithFormat:@"fyne-notify-%d", notifyNum]; + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier + content:content trigger:nil]; -@implementation FyneUserNotificationCenterDelegate - -- (BOOL)userNotificationCenter:(NSUserNotificationCenter*)center - shouldPresentNotification:(NSUserNotification*)notification -{ - return YES; + [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { + if (error != nil) { + NSLog(@"Could not send notification: %@", error); + } + }]; } -@end - -void sendNSUserNotification(const char *, const char *); - bool isBundled() { return [[NSBundle mainBundle] bundleIdentifier] != nil; } -bool isDarkMode() { - NSString *style = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; - return [@"Dark" isEqualToString:style]; -} - -void sendNotification(const char *title, const char *body) { - NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; - if (center.delegate == nil) { - center.delegate = [[FyneUserNotificationCenterDelegate new] autorelease]; - } - - NSString *uuid = [[NSUUID UUID] UUIDString]; - NSUserNotification *notification = [[NSUserNotification new] autorelease]; - notification.title = [NSString stringWithUTF8String:title]; - notification.informativeText = [NSString stringWithUTF8String:body]; - notification.identifier = [NSString stringWithFormat:@"%@-fyne-notify-%@", [[NSBundle mainBundle] bundleIdentifier], uuid]; - [center scheduleNotification:notification]; -} - -void watchTheme() { - [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification" object:nil queue:nil - usingBlock:^(NSNotification *note) { - themeChanged(); // calls back into Go - }]; +void sendNotification(char *cTitle, char *cBody) { + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + NSString *title = [NSString stringWithUTF8String:cTitle]; + NSString *body = [NSString stringWithUTF8String:cBody]; + + UNAuthorizationOptions options = UNAuthorizationOptionAlert; + [center requestAuthorizationWithOptions:options + completionHandler:^(BOOL granted, NSError *_Nullable error) { + if (!granted) { + if (error != NULL) { + NSLog(@"Error asking for permission to send notifications %@", error); + // this happens if our app was not signed, so do it the old way + fallbackSend((char *)[title UTF8String], (char *)[body UTF8String]); + } else { + NSLog(@"Unable to get permission to send notifications"); + } + } else { + doSendNotification(center, title, body); + } + }]; } diff --git a/app/app_desktop_darwin.go b/app/app_desktop_darwin.go new file mode 100644 index 0000000000..8e723d832f --- /dev/null +++ b/app/app_desktop_darwin.go @@ -0,0 +1,54 @@ +// +build !ci + +// +build !ios + +package app + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation + +#include + +bool isBundled(); +bool isDarkMode(); +void watchTheme(); +*/ +import "C" +import ( + "net/url" + "os" + "path/filepath" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" +) + +func defaultVariant() fyne.ThemeVariant { + if C.isDarkMode() { + return theme.VariantDark + } + return theme.VariantLight +} + +func rootConfigDir() string { + homeDir, _ := os.UserHomeDir() + + desktopConfig := filepath.Join(filepath.Join(homeDir, "Library"), "Preferences") + return filepath.Join(desktopConfig, "fyne") +} + +func (a *fyneApp) OpenURL(url *url.URL) error { + cmd := a.exec("open", url.String()) + cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr + return cmd.Run() +} + +//export themeChanged +func themeChanged() { + fyne.CurrentApp().Settings().(*settings).setupTheme() +} + +func watchTheme() { + C.watchTheme() +} diff --git a/app/app_desktop_darwin.m b/app/app_desktop_darwin.m new file mode 100644 index 0000000000..8011cc4659 --- /dev/null +++ b/app/app_desktop_darwin.m @@ -0,0 +1,18 @@ +// +build !ci +// +build !ios + +extern void themeChanged(); + +#import + +bool isDarkMode() { + NSString *style = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; + return [@"Dark" isEqualToString:style]; +} + +void watchTheme() { + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification" object:nil queue:nil + usingBlock:^(NSNotification *note) { + themeChanged(); // calls back into Go + }]; +} diff --git a/app/app_mobile_ios.go b/app/app_mobile_ios.go index bff14cc240..a93c8bcd4b 100644 --- a/app/app_mobile_ios.go +++ b/app/app_mobile_ios.go @@ -36,15 +36,6 @@ func (a *fyneApp) OpenURL(url *url.URL) error { return nil } -func (a *fyneApp) SendNotification(n *fyne.Notification) { - titleStr := C.CString(n.Title) - defer C.free(unsafe.Pointer(titleStr)) - contentStr := C.CString(n.Content) - defer C.free(unsafe.Pointer(contentStr)) - - C.sendNotification(titleStr, contentStr) -} - func defaultVariant() fyne.ThemeVariant { return systemTheme } diff --git a/app/app_mobile_ios.m b/app/app_mobile_ios.m index 82ff41f4b2..fff5c7630e 100644 --- a/app/app_mobile_ios.m +++ b/app/app_mobile_ios.m @@ -3,7 +3,6 @@ // +build ios #import -#import void openURL(char *urlStr) { UIApplication *app = [UIApplication sharedApplication]; @@ -11,42 +10,6 @@ void openURL(char *urlStr) { [app openURL:url options:@{} completionHandler:nil]; } -static int notifyNum = 0; - -void doSendNotification(UNUserNotificationCenter *center, NSString *title, NSString *body) { - UNMutableNotificationContent *content = [UNMutableNotificationContent new]; - [content autorelease]; - content.title = title; - content.body = body; - - notifyNum++; - NSString *identifier = [NSString stringWithFormat:@"fyne-notify-%d", notifyNum]; - UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier - content:content trigger:nil]; - - [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { - if (error != nil) { - NSLog(@"Could not send notification: %@", error); - } - }]; -} - -void sendNotification(char *cTitle, char *cBody) { - UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; - NSString *title = [NSString stringWithUTF8String:cTitle]; - NSString *body = [NSString stringWithUTF8String:cBody]; - - UNAuthorizationOptions options = UNAuthorizationOptionAlert; - [center requestAuthorizationWithOptions:options - completionHandler:^(BOOL granted, NSError *_Nullable error) { - if (!granted) { - NSLog(@"Unable to get permission to send notifications"); - } else { - doSendNotification(center, title, body); - } - }]; -} - char *documentsPath() { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = paths.firstObject;