Repository navigation
Pass a call on to every delegate the plugin replaced, once each - #20
Merged
Merged
Conversation
The plugin takes the notification center at registration, in a build where Flutwire has run before, and again when Dart starts, and each time it remembered the one delegate it replaced. Firebase Messaging takes the center from a delegate that is not the app's Flutter delegate, keeps it as the delegate to pass every call on to, and does that once. When it does that between the plugin's two takes, the plugin's second take replaces Firebase Messaging and remembers it, while Firebase Messaging remembers the plugin, and a tap on a notification that was not Flutwire's went back and forth between the two until the stack ran out. A first launch of a build has no early take, so the loop needs a second launch, and a build that never starts Flutwire never takes the center. The plugin now keeps every delegate it replaces, newest first, in DelegateChain, and hands a call to the newest one that implements it and that the call has not reached yet. A delegate that hands the call back gets the next one down, so the app's own delegate is still reached and none gets the same call twice.
The Swift half had no check beyond building it, and the notification delegates meet only on a device. The model holds the three that met in the crash, each as its source behaves, and runs the plugin over seven orders in which they can take the center: once as it passed calls on in 1.0.1, which has to loop where Firebase Messaging replaces it between its two takes, and once with the chain, which has to reach every delegate once. It is compiled with swiftc next to the real DelegateChain.swift, so it needs neither a device nor Flutter, and the Apple job runs it. CONTRIBUTING.md says where it is.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tapping a notification that was not Flutwire's closed an app that also uses Firebase Messaging. It was seen on iOS in a test build that starts Flutwire: the stack in the crash report goes from Flutwire into the notification response handler of Firebase Messaging, and is too deep for the report to show. The same code handles a notification that arrives while the app is open, so that one should loop in the same way, though nobody has seen it.
The plugin takes the notification center twice, at registration in a build where Flutwire has run before and again when Dart starts, and each time it remembered the one delegate it replaced. Firebase Messaging takes the center from a delegate that is not the app's Flutter delegate, keeps it as the delegate to pass every call on to, and does that once. When it does that between the plugin's two takes, the second take replaces Firebase Messaging and remembers it, while Firebase Messaging remembers the plugin. Each hands the call to the other until the stack ends. A first launch of a build has no early take, so the loop needs a second launch, and a build that never starts Flutwire never takes the center at all.
The plugin now keeps every delegate it replaces, newest first, in a small class of its own, and hands a call to the newest one that implements it and that this call has not reached yet. A delegate that hands the call back gets the next one down. In the order above that is the plugin, Firebase Messaging, the plugin again and then the app, each delegate once. Another plugin that keeps the delegate it replaces comes out the same. How the plugin handles its own notification does not change.
CI has no device, so the second commit adds a model of the three delegates, each as its source behaves, and runs the plugin over seven orders in which they can take the center, once as in 1.0.1 and once with the chain. The 1.0.1 version loops in the two orders where Firebase Messaging replaces the plugin between its takes, and the chain reaches every delegate once in all seven. Two simpler fixes failed the same model and were left out: taking the center once per launch loses the plugin's own notification in an app that sets its delegate after the plugins register, and a guard against coming back into the plugin ends the loop but never reaches the app's delegate, so the app shows no banner for a push that arrives while it is open. The model is compiled with swiftc next to the real DelegateChain.swift and runs in the Apple job.
The plugin typechecks against the iOS and macOS frameworks of the Flutter SDK, the model passes, and the new step of the Apple job runs as written. No Dart changed. It was not run on a device, and the model is built from the sources of the three delegates, not from the delegates themselves, so the check that matters is on a device: a second launch of a build that starts Flutwire, then a tap on a push notification. Nothing in the public API changes. Targets 1.0.2, as one Fixed entry and one Internal entry in the changelog.