-
Notifications
You must be signed in to change notification settings - Fork 6k
Add capability to add AppDelegate as UNUserNotificationCenterDelegate #9864
Changes from 8 commits
d48d4a2
a42883a
a5a3ac3
151293c
ccc9b64
e6f6b57
6af5edd
5e1c0c8
bd8ea05
e33de17
e2b0ab8
abd3bc6
c6c2eea
5618d26
7d82637
204d8b1
168c674
8e0def6
2501158
8875d35
108155f
fb05b3a
4ab5307
d4415f4
1002702
e9f5d00
3e299e4
5a84f3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,6 +107,13 @@ NS_ASSUME_NONNULL_BEGIN | |
| (void (^)(UNNotificationPresentationOptions options))completionHandler | ||
| API_AVAILABLE(ios(10)); | ||
|
|
||
| /** | ||
| * Calls all plugins registered for `UNUserNotificationCenterDelegate` callbacks. | ||
| */ | ||
| - (void)userNotificationCenter:(UNUserNotificationCenter*)center | ||
|
dnfield marked this conversation as resolved.
Outdated
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now you don't need this because its conforming to UNUserNotificationCenterDelegate so you get it for free.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FlutterAppDelegate is calling and _lifeCycleDelegate is a Instead of explicitly declaring Up to you though! |
||
| didReceiveNotificationResponse:(UNNotificationResponse*)response | ||
| withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10)); | ||
|
|
||
| /** | ||
| * Called if this has been registered for `UIApplicationDelegate` callbacks. | ||
| * | ||
|
|
@@ -375,6 +382,13 @@ typedef void (*FlutterPluginRegistrantCallback)(NSObject<FlutterPluginRegistry>* | |
| */ | ||
| @protocol FlutterAppLifeCycleProvider | ||
| - (void)addApplicationLifeCycleDelegate:(NSObject<FlutterApplicationLifeCycleDelegate>*)delegate; | ||
|
|
||
| /** | ||
| * Implement this in the `UIAppDelegate` of your app to enable Flutter plugins to receive | ||
| * calls as `UNUserNotificationCenterDelegate` when they are added to | ||
| * `addApplicationLifeCycleDelegate`. | ||
| */ | ||
| - (void)registerAsUserNotificationCenterDelegate; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also should have a But is this thin convenience method necessary? It seems like it would be better for callers to explicitly set the delegate if that's what they want instead of implying there's some additional magic going on. It also hides that calling this will stomp any previous delegates set on the notification center.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The UNUserNotificationCenter is a shared object, so there can only be one UNUserNotificationCenterDelegate. The problem we have now is if two plugins (e.g. firebase_messaging and flutter_local_notifications) need the app to receive notifications, they would both set this delegate and one of the plugins wouldn't receive notifications. This PR tries to create a shared delegate that all plugins can listen to. More detail is in this issue flutter/flutter#22099 |
||
| @end | ||
|
|
||
| NS_ASSUME_NONNULL_END; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,6 +92,19 @@ - (void)userNotificationCenter:(UNUserNotificationCenter*)center | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Calls all plugins registered for `UNUserNotificationCenterDelegate` callbacks. | ||
| */ | ||
| - (void)userNotificationCenter:(UNUserNotificationCenter*)center | ||
| didReceiveNotificationResponse:(UNNotificationResponse*)response | ||
| withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need the API_AVAILABLE in the .mm. |
||
| if (@available(iOS 10.0, *)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you need this anymore - have you tested compilation on something targetting iOS 9?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The API_AVAILABLE in the header is enough to give the warning. Are you trying to guard against people ignoring the warning and calling it anyway with a nil center and response? |
||
| [_lifeCycleDelegate userNotificationCenter:center | ||
| didReceiveNotificationResponse:response | ||
| withCompletionHandler:completionHandler]; | ||
| } | ||
| } | ||
|
|
||
| - (BOOL)application:(UIApplication*)application | ||
| openURL:(NSURL*)url | ||
| options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options { | ||
|
|
@@ -177,6 +190,14 @@ - (void)addApplicationLifeCycleDelegate:(NSObject<FlutterPlugin>*)delegate { | |
| [_lifeCycleDelegate addDelegate:delegate]; | ||
| } | ||
|
|
||
| - (void)registerAsUserNotificationCenterDelegate { | ||
| if ([UNUserNotificationCenter class] != nil) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need this if you add availability to registerAsUserNotificationCenterDelegate. |
||
| // iOS 10 or later | ||
| // For iOS 10 display notification (sent via APNS) | ||
| [UNUserNotificationCenter currentNotificationCenter].delegate = self; | ||
| } | ||
| } | ||
|
|
||
| #pragma mark - UIApplicationDelegate method dynamic implementation | ||
|
|
||
| - (BOOL)respondsToSelector:(SEL)selector { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -290,6 +290,23 @@ - (void)userNotificationCenter:(UNUserNotificationCenter*)center | |
| } | ||
| } | ||
|
|
||
| - (void)userNotificationCenter:(UNUserNotificationCenter*)center | ||
| didReceiveNotificationResponse:(UNNotificationResponse*)response | ||
| withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10)) { | ||
| if (@available(iOS 10.0, *)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, no API_AVAILABLE in the implementation, and you don't need the @availabile check because the header is decorated with the API availability. |
||
| for (id<FlutterPlugin> plugin in _pluginDelegates) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this was renamed to _delegates in 273f4cf#diff-71f628ed3f0d51c80d58e053985f8a81R22? Does this code compile? |
||
| if (!plugin) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You don't need this nil check because |
||
| continue; | ||
| } | ||
| if ([plugin respondsToSelector:_cmd]) { | ||
| [plugin userNotificationCenter:center | ||
| didReceiveNotificationResponse:response | ||
| withCompletionHandler:completionHandler]; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| - (BOOL)application:(UIApplication*)application | ||
| openURL:(NSURL*)url | ||
| options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would need to be guarded, it's iOS 10+.
I thought @cyanglaz made this stuff happen dynamically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe this would cause a crash on iOS < 10. The documentation for Firebase Messaging gives instructions on how to add it to your app. Even despite supporting 8+. I also tested this on a 9.0 iOS simulator and the app still compiled and installed on device.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, @cyanglaz and I talked offline. He was able to dynamically add methods, but not implementing protocols.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UNUserNotificationCenterDelegate wasn't added until IOS10. We'll have to guard this, otherwise warnings will get displayed and people using -Werror will fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an if statement, but I'm confident I didn't implement it correctly. How would I go about doing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just wrap the macro around the one protocol you need to add instead of duplicating the entire class. Also, use
__IPHONE_10_0instead of 100000.