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

Dynamically add certain AppDelegate methods. #8843

Merged
merged 13 commits into from
May 30, 2019

Conversation

cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented May 3, 2019

Issue:
flutter/flutter#9984

Reason
We implemented all the possible AppDelegate methods in FlutterAppDelegate. They are used for plugins that needs to listen to certain life cycle messages.

2 of those methods requires users to set corresponding keys in info.plist in their app. (didReceiveRemoteNotification and performFetchWithCompletionHandle). For FirebaseMessaging implemented didReceiveRemoteNotification)
For people who doesn't use plugins that uses either of these 2 methods, they don't need to add the corresponding keys in the info.plist. And If they don't, they get a warning email from Apple when submitting their app.

Current solution for our user
As for now, the workaround for our users is that for every APP, regardless what plugins they use.

What does this PR do
This PR dynamically adding the implementation of these 2 methods based on if plugins registered implemented any of these methods.
(Update: Using respondsToSelector/forwardingTargetForSelector)

Thoughs
Using method swizzling in OBJC is usually not encouraged since it can have all sorts of issues. We might want to find a better solution if we can. We also want to analyze the trade off between "adding this fix" and "ask our users to always add the keys in the info.plist"
(Update: Not using method swizzling anymore, now using respondsToSelector/forwardingTargetForSelector for a solution. Thanks to @jamesderlin)

Testing
If we have to merge this in, I think before merge this in, we want to set up engine to have objc tests and have strong test case for this implementation. The engine unit testing for iOS is tracked here flutter/flutter#31288
We also need to add E2E test in the plugins that uses either of the 2 methods.

CC @collinjackson @cbracken

/**
* Get all registered plugins;
*/
- (NSPointerArray*)allPluginsDelegates;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a readonly property?

Copy link
Contributor Author

@cyanglaz cyanglaz May 4, 2019

Choose a reason for hiding this comment

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

I thought NSPointerArray was immutable.

@jamesderlin
Copy link
Contributor

Did you verify that if an app does want to receive notifications that enabling them works? IIRC, one issue I ran into in my earlier attempt to address (#6086) this was that the OS caches whether the app responds to application:didReceiveRemoteNotification:fetchCompletionHandler: (and I could not find a way to refresh it).

@cyanglaz
Copy link
Contributor Author

cyanglaz commented May 4, 2019

Did you verify that if an app does want to receive notifications that enabling them works? IIRC, one issue I ran into in my earlier attempt to address (#6086) this was that the OS caches whether the app responds to application:didReceiveRemoteNotification:fetchCompletionHandler: (and I could not find a way to refresh it).

I haven't verity it with a real push notification yet. I have been having trouble to set it up with our flutter app id. I only tested with manually calling the methods.
I do need to test with the actual notification but I think they should perform the same. As long as the methods were added before the UIApplication received the notification.

@cyanglaz
Copy link
Contributor Author

cyanglaz commented May 6, 2019

I have updated this PR to use respondsToSelector/forwardingTargetForSelector to handle the dynamism. Thanks to @jamesderlin
Now we don't use the nasty class_addMethod to handle the problem anymore.
There was a PR doing similar things previously #6259

Copy link
Contributor

@collinjackson collinjackson left a comment

Choose a reason for hiding this comment

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

this looks like an improvement over the current situation. a few nits about comments

@cyanglaz cyanglaz requested a review from chinmaygarde May 8, 2019 18:02
@cyanglaz
Copy link
Contributor Author

cyanglaz commented May 8, 2019

@chinmaygarde Could you also take a look at this?

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

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

Seems reasonable as a restricted subset of the previous approach. @chinmaygarde may have further thoughts.

@"application:performFetchWithCompletionHandler:], but you still need to add \"fetch\" "
@"to the list of your supported UIBackgroundModes in your Info.plist.");
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This feels potentially high-maintenance. If Apple ever changes the SDK to add more of these, we won't know. That said, these aren't grouped into a protocol of any sort that we could check against so I'm not sure there's much we can do about it.

No actual action here, unless you can think of some way to mitigate that.

Copy link
Member

@chinmaygarde chinmaygarde left a comment

Choose a reason for hiding this comment

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

lgtm with nits.

/**
* Check whether the selector should be handled dynamically.
*/
- (BOOL)isSelectorAddedDynamically:(SEL)selector;
Copy link
Member

Choose a reason for hiding this comment

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

Does this have to be in the public header?

- (void)logCapabilityConfigurationWarningIfNeeded:(SEL)selector {
NSArray* backgroundModesArray =
[[NSBundle mainBundle] objectForInfoDictionaryKey:kUIBackgroundMode];
NSSet* backgroundModesSet = [[NSSet alloc] initWithArray:backgroundModesArray];
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Just autorelease this instead of adding the release later. Just in case we refactor this to add an early return or something.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 30, 2019
dnfield pushed a commit to flutter/flutter that referenced this pull request May 30, 2019
* 49b6de8 Dynamically add certain iOS AppDelegate methods. (flutter/engine#8843)

* 75da3d4 Roll src/third_party/dart fee615c5a5..39ec9fc4f3 (46 commits)

* ba6cc8c Fix type mismatches in C++ standard codec (flutter/engine#9112)

* 37b31ca Roll src/third_party/skia 69aaee0ff927..f62e575bab08 (11 commits) (flutter/engine#9142)
daohoangson added a commit to daohoangson/flutter-tinhte_demo that referenced this pull request Jun 6, 2019
huqiuser pushed a commit to huqiuser/engine that referenced this pull request Jun 12, 2019
kiku-jw pushed a commit to kiku-jw/flutter that referenced this pull request Jun 14, 2019
* 49b6de8 Dynamically add certain iOS AppDelegate methods. (flutter/engine#8843)

* 75da3d4 Roll src/third_party/dart fee615c5a5..39ec9fc4f3 (46 commits)

* ba6cc8c Fix type mismatches in C++ standard codec (flutter/engine#9112)

* 37b31ca Roll src/third_party/skia 69aaee0ff927..f62e575bab08 (11 commits) (flutter/engine#9142)
@ronaldmaymone
Copy link

ronaldmaymone commented Apr 28, 2020

Issue:
flutter/flutter#9984

Reason
We implemented all the possible AppDelegate methods in FlutterAppDelegate. They are used for plugins that needs to listen to certain life cycle messages.

2 of those methods requires users to set corresponding keys in info.plist in their app. (didReceiveRemoteNotification and performFetchWithCompletionHandle). For FirebaseMessaging implemented didReceiveRemoteNotification)
For people who doesn't use plugins that uses either of these 2 methods, they don't need to add the corresponding keys in the info.plist. And If they don't, they get a warning email from Apple when submitting their app.

Current solution for our user
As for now, the workaround for our users is that for every APP, regardless what plugins they use.

What does this PR do
This PR dynamically adding the implementation of these 2 methods based on if plugins registered implemented any of these methods.
(Update: Using respondsToSelector/forwardingTargetForSelector)

Thoughs
Using method swizzling in OBJC is usually not encouraged since it can have all sorts of issues. We might want to find a better solution if we can. We also want to analyze the trade off between "adding this fix" and "ask our users to always add the keys in the info.plist"
(Update: Not using method swizzling anymore, now using respondsToSelector/forwardingTargetForSelector for a solution. Thanks to @jamesderlin)

Testing
If we have to merge this in, I think before merge this in, we want to set up engine to have objc tests and have strong test case for this implementation. The engine unit testing for iOS is tracked here flutter/flutter#31288
We also need to add E2E test in the plugins that uses either of the 2 methods.

CC @collinjackson @cbracken

Sorry for commenting here but how did you implement the didReceiveRemoteNotification on FlutterAppDelegate? Has this merge changed the way you implemented?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants