Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@gaaclarke
Copy link
Member

@gaaclarke gaaclarke commented Nov 30, 2021

This removes explicit references to application:didReceiveRemoteNotification:fetchCompletionHandler: from the engine and adds it at runtime. This will remove the false positive emails users receive about entitlements. If the user is using a plugin that implements -[NSPlugin application:didReceiveRemoteNotification:fetchCompletionHandler:] that should trigger the warning email since that plugin will be linked in and that symbol will show up for the plugin.

This is based off of what firebase does: https://github.com/firebase/firebase-ios-sdk/blob/7eb1747e4b9be195ea9908b9da28b1d0f818afe3/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m#L98

fixes flutter/flutter#9984

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on
    writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@gaaclarke
Copy link
Member Author

I haven't tested it by uploading an app yet. The remedy is based on the information linked in the issue. The problematic selector never shows up as a symbol in the engine and is never created with an @selector, it only appears as a string literal. That could potentially still trigger the warning, but that doesn't seem to be the case based on what people have said in the issue and the firebase code.

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static const SEL selectorsHandledByPlugins[] = {
@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:),
NSSelectorFromString(kApplicationDidReceiveRemoteNotificationFetchCompletionHandler),
@selector(application:performFetchWithCompletionHandler:)};
Copy link
Member

@jmagman jmagman Nov 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does application:performFetchWithCompletionHandler: have a similar problem for the fetch background mode?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe so. It isn't listed in the issue or the pasted in message from the App Store. The documentation for it doesn't list a need for entitlements.

* Calls all plugins registered for `UIApplicationDelegate` callbacks.
*/
- (void)application:(UIApplication*)application
- (void)performApplication:(UIApplication*)application
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be a breaking change for plugins that have implemented this method?

What about application:didRegisterForRemoteNotificationsWithDeviceToken? didFailToRegisterForRemoteNotificationsWithError? etc
https://github.com/firebase/firebase-ios-sdk/blob/7eb1747e4b9be195ea9908b9da28b1d0f818afe3/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m#L111-L112

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be a breaking change for plugins that have implemented this method?

I'm not sure what you have in mind. This is on the FlutterPluginAppLifeCycleDelegate. Do you mean the usage of _cmd? The modification of the class at runtime takes care of that as demonstrated in the test.

application:didRegisterForRemoteNotificationsWithDeviceToken

Yea, I'll do that one too, thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be a breaking change for plugins that have implemented this method?

If a plugin has application:didReceiveRemoteNotification:fetchCompletionHandler: implemented like this:
https://github.com/blackmenthor/flutter-branch-io/blob/39746a23dcacca266cc8af98efda7687643bed89/ios/Classes/SwiftFlutterBranchIoPlugin.swift#L173-L176

It's not implementing performApplication:didReceiveRemoteNotification:fetchCompletionHandler:, but the implementation has been swapped out in +load. Would their implementation be called? Is there a way we can make sure that delegates that already respond to application:didReceiveRemoteNotification:fetchCompletionHandler: don't break?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, let me write up some tests for that use case. It's hard to know what will happen without trying it.

I've added application:didRegisterForRemoteNotificationsWithDeviceToken and backfilled tests to FlutterAppDelegate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Firebase also did didFailToRegisterForRemoteNotificationsWithError I'll do that one too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so I looked into the use case for subclassing FlutterPluginAppLifeCycleDelegate like in the example provided.
It is using the override annotation so removing application:didReceiveRemoteNotification:fetchCompletionHandler: will be a problem since its removal is necessary in order to fix the problem. I've added a test to show that subclassing and overriding performApplication:didReceiveRemoteNotification:fetchCompletionHandler: behaves as expected. So this plugin will break in the best way possible, at compilation time when the override annotation doesn't make any sense. They'll have to rename their method to have the perform prefix. For objc subclasses this shouldn't be a problem since there is no "override" analog. I don't believe this is technically a breaking change since it doesn't break any tests. I'm not sure if this is different criteria for plugins.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-referencing firebase/firebase-ios-sdk#2835

So this plugin will break in the best way possible, at compilation time when the override annotation doesn't make any sense.

Fortunately I doubt this feature is used by many plugins.

For objc subclasses this shouldn't be a problem since there is no "override" analog.

The problem there is that it wouldn't break, and they wouldn't know they need to rename the method. Could we detect that case in +load and NSAssert? Or just avoid the swapping?

I don't believe this is technically a breaking change since it doesn't break any tests

A remote notification test would be difficult, but if we had one it would break, but point taken.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added didFailToRegisterForRemoteNotificationsWithError.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem there is that it wouldn't break, and they wouldn't know they need to rename the method. Could we detect that case in +load and NSAssert? Or just avoid the swapping?

For objc the hypothetical subclasser wouldn't have to rename it, it would just work if the implementation is like the example provided above. If they are calling [super application:didReceiveRemoteNotification:fetchCompletionHandler:] in the subclass it will create a warning or error depending on their compilation settings but would execute fine.

Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is what was there before even work? flutter/flutter#52895 https://github.com/Bathant/PushNotificationFlutterExample/blob/master/ios/Runner/AppDelegate.swift https://stackoverflow.com/questions/60760123/flutter-didreceiveremotenotification-not-called

I'd like more validation that this actually works since it seems like what's on main may not actually work? This PR is hopefully fixing the validation error, but if the feature doesn't work at all we should either fix it or maybe delete it instead of all the swizzling.

* Calls all plugins registered for `UIApplicationDelegate` callbacks.
*/
- (void)application:(UIApplication*)application
- (void)performApplication:(UIApplication*)application
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be a breaking change for plugins that have implemented this method?

If a plugin has application:didReceiveRemoteNotification:fetchCompletionHandler: implemented like this:
https://github.com/blackmenthor/flutter-branch-io/blob/39746a23dcacca266cc8af98efda7687643bed89/ios/Classes/SwiftFlutterBranchIoPlugin.swift#L173-L176

It's not implementing performApplication:didReceiveRemoteNotification:fetchCompletionHandler:, but the implementation has been swapped out in +load. Would their implementation be called? Is there a way we can make sure that delegates that already respond to application:didReceiveRemoteNotification:fetchCompletionHandler: don't break?

* Calls all plugins registered for `UIApplicationDelegate` callbacks.
*/
- (void)application:(UIApplication*)application
- (void)performApplication:(UIApplication*)application
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-referencing firebase/firebase-ios-sdk#2835

So this plugin will break in the best way possible, at compilation time when the override annotation doesn't make any sense.

Fortunately I doubt this feature is used by many plugins.

For objc subclasses this shouldn't be a problem since there is no "override" analog.

The problem there is that it wouldn't break, and they wouldn't know they need to rename the method. Could we detect that case in +load and NSAssert? Or just avoid the swapping?

I don't believe this is technically a breaking change since it doesn't break any tests

A remote notification test would be difficult, but if we had one it would break, but point taken.

@gaaclarke
Copy link
Member Author

I'd like more validation that this actually works since it seems like what's on main may not actually work? This PR is hopefully fixing the validation error, but if the feature doesn't work at all we should either fix it or maybe delete it instead of all the swizzling.

I've added backfill tests for the FlutterAppDelegate. If it previously worked, the tests should prove it it doesn't deviate from that. If it was broken, this won't fix it, but it will fix the linked issue.

@gaaclarke gaaclarke requested a review from jmagman November 30, 2021 19:37
Copy link
Member

@jmagman jmagman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it previously worked, the tests should prove it it doesn't deviate from that. If it was broken, this won't fix it, but it will fix the linked issue.

True, but if it just doesn't work at all then removing this totally may be a better "fix" for the App Store verification issue than claiming to support something and just have it not work at all. We'd have to set up remote notifications to test (and yikes: https://developer.apple.com/documentation/usernotifications/sending_push_notifications_using_command-line_tools), hopefully our users can help us out testing it. 🙂

Thanks for digging into this, LGTM

@gaaclarke gaaclarke force-pushed the notification-warning-email branch from aeb2574 to 3161ff0 Compare November 30, 2021 22:04
@gaaclarke
Copy link
Member Author

The shell_test failure is unrelated, rebasing to see if that fixes the issue.

@Stratovarius93
Copy link

I must update to Flutter 2.8 to get solution ?

@jmagman
Copy link
Member

jmagman commented Dec 15, 2021

I must update to Flutter 2.8 to get solution ?

No, this PR was reverted, and it's not available on 2.8.

@esDotDev
Copy link

I'm on the latest master, just submitted, and got the email. Not sure if this is expected or not...

Flutter version 2.9.0-1.0.pre.187

@jmagman
Copy link
Member

jmagman commented Jan 4, 2022

I'm on the latest master, just submitted, and got the email. Not sure if this is expected or not...

This PR was reverted, so this is expected.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugins could avoid warnings by installing UIApplicationDelegate methods dynamically

4 participants