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

New Plugin API PR4: Adds Lifecycle support to the new plugin system. #9049

Merged

Conversation

matthew-carroll
Copy link
Contributor

New Plugin API PR4: Adds Lifecycle support to the new plugin system.

I still need to send in a real Lifecycle from FlutterFragment, but this PR creates the behavior within the new plugin system to respond to Lifecycle events.

This PR adds 2 Android libs to the engine:

  • lifecycle-common-java8, which complements our existing lifecycle-common by adding one class that is needed for Java 8 compliance
  • lifecycle-runtime, which was needed to utilize PluginRegistry.

Intended lifecycle behavior
When there is no backing lifecycle, e.g., Activity or Service, the FlutterEngine reports itself in the CREATED state. When either an Activity or a Service is attached to the FlutterEngine, the FlutterEngine defers to whatever the lifecycle of that component reports. The only caveat to this behavior is that even if the backing Activity or Service is destroyed, the FlutterEngine will not send a destruction event. This is because any Lifecycle that emits a destruction event is obligated to never send any future events, which would be inappropriate in our case.

Copy link
Contributor

@mklim mklim left a comment

Choose a reason for hiding this comment

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

LGTM

* {@code ContentProvider}, or {@code BroadcastReceiver}. In these cases, this lifecycle reports
* itself in the {@link Lifecycle.State#CREATED} state.
* <p>
* Regardless of what happens to a backing {@code Activity} or @{code Service}, this lifecycle
Copy link
Contributor

Choose a reason for hiding this comment

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

It's unexpected to me that onDestroyed would be special cased to the FlutterEngine specifically and that it's impossible to get an onDestroyed callback for the actual underlying lifecycle. Any way we could propagate this information life normal without breaking any kind of Engine contract? Add in an onEngineDestroyed method just for this class to handle the final engine destruction?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The contract that we're trying not to violate is the Lifecycle contract, not the FlutterEngine contract: https://developer.android.com/reference/android/arch/lifecycle/Lifecycle.State#destroyed

The unique thing about FlutterEngine is that its backing Lifecycle can change over time. It goes from Activity to Service to nothing to Activity again. There is nothing preventing us from forwarding an Activity's ON_DESTROY event, but then any other code that is designed to understand Lifecycle events will have undefined behavior when the FlutterEngine's Lifecycle turns right around and emits an ON_CREATED event. Additionally, it is also conceptually incorrect to send that ON_DESTROY event because even though the Activity has been destroyed, the FlutterEngine remains, and at the end of the day this Lifecycle is truly owned by the FlutterEngine, it just temporarily takes on the Lifecycle of various Android components.

Does that make sense?

@matthew-carroll matthew-carroll force-pushed the 31589_new_plugin_api_pr4 branch from 32cb12c to 8312cd7 Compare May 23, 2019 06:49
@matthew-carroll matthew-carroll force-pushed the 31589_new_plugin_api_pr4 branch from 8312cd7 to e0c044c Compare May 23, 2019 21:47
@matthew-carroll matthew-carroll merged commit cfa524f into flutter:master May 25, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 25, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 25, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 25, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 25, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 25, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 26, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 26, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 27, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 27, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 27, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 29, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 29, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 29, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 30, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 30, 2019
engine-flutter-autoroll added a commit to flutter/flutter that referenced this pull request May 30, 2019
flutter/engine@8dc3a4c...4c4c0f8

git log 8dc3a4c..4c4c0f8 --no-merges --oneline
4c4c0f8 Add plugin shim to facilitate old plugins in new embedding (#33478). (flutter/engine#9120)
e8c2b17 Added support for transparent FlutterActivitys (#32740). (flutter/engine#9115)
19c5029 Roll src/third_party/skia 29e013deb476..1013ecfb3421 (3 commits) (flutter/engine#9130)
45d39e1 Revert &#34;Roll src/third_party/dart fee615c5a5..d5405d06f4 (21 commits) (#9127)&#34; (flutter/engine#9135)
44f1b44 Revert &#34;Use track-widget-creation transformer included in the sdk. (#9085)&#34; (flutter/engine#9134)
ae14c5a Roll src/third_party/dart fee615c5a5..d5405d06f4 (21 commits) (flutter/engine#9127)
3ea7ac8 Roll src/third_party/skia 633db4db7672..29e013deb476 (3 commits) (flutter/engine#9128)
8ad0e2f Roll src/third_party/skia 25b63f91b3b4..633db4db7672 (4 commits) (flutter/engine#9125)
37e6e0c Roll src/third_party/skia 8f88b2da05d5..25b63f91b3b4 (2 commits) (flutter/engine#9121)
37b367e Allow specifying both Dart and non-Dart fixtures in engine unit-tests. (flutter/engine#9113)
28f2c05 Roll src/third_party/skia 1f02e8488551..8f88b2da05d5 (3 commits) (flutter/engine#9116)
0932008 Remove outdated TODOs (flutter/engine#9114)
c880ca2 Roll src/third_party/dart 50b0d85804..fee615c5a5 (4 commits)
6e51513 Removing unused imports (flutter/engine#9108)
9ee2697 Roll src/third_party/skia d04aaa3a841a..1f02e8488551 (8 commits) (flutter/engine#9109)
fa2e2d9 Add checks to constructors and add missing constructor members (flutter/engine#9106)
7e1788a Fix unopt variants of profile and release builds. (flutter/engine#9107)
867120c Better help message. (flutter/engine#9097)
e27c6e8 Forward custom IDE flags to GN. (flutter/engine#9023)
6b4ca8d Roll src/third_party/skia 176b214f91bc..d04aaa3a841a (7 commits) (flutter/engine#9105)
a207318 Roll src/third_party/dart ec4d48e241..50b0d85804 (87 commits)
0a6aeb3 Roll src/third_party/skia 213aa46af167..176b214f91bc (2 commits) (flutter/engine#9100)
f2e22aa Roll src/third_party/skia 7730d7cb8fb2..213aa46af167 (3 commits) (flutter/engine#9098)
557db42 Roll src/third_party/skia de7e074e8190..7730d7cb8fb2 (2 commits) (flutter/engine#9096)
64a4a0e Roll src/third_party/skia f06b6d5469a5..de7e074e8190 (1 commits) (flutter/engine#9094)
fdee625 Roll src/third_party/skia 7e5a64f517e4..f06b6d5469a5 (2 commits) (flutter/engine#9093)
daf47f0 Roll src/third_party/skia dc01a84ae098..7e5a64f517e4 (1 commits) (flutter/engine#9092)
41e10f0 Fix internal break since listing contents can return null (flutter/engine#9078)
cf1b203 Roll src/third_party/skia f33c95cd6f55..dc01a84ae098 (3 commits) (flutter/engine#9091)
2404cdc Rename macOS FLEPlugin* to FlutterPlugin* (flutter/engine#9074)
509a43f Apply minor cleanups to Android embedding (flutter/engine#9088)
0a0f330 Removed outdated deprecation comments (flutter/engine#9087)
a44cbbf Delete BSDiff sources (flutter/engine#9086)
0f1ff3b Correct typos, adopt US spellings (flutter/engine#9081)
651c904 Use track-widget-creation transformer included in the sdk. (flutter/engine#9085)
cfa524f New Plugin API PR4: Adds Lifecycle support to the new plugin system. (flutter/engine#9049)
6b8ac18 Roll src/third_party/skia d9430297e74a..f33c95cd6f55 (5 commits) (flutter/engine#9082)
11408ef Update macOS podspec version requirement (flutter/engine#9077)
66c6ae4 Roll src/third_party/skia a4b837971c4b..d9430297e74a (30 commits) (flutter/engine#9080)
9151b37 Roll src/third_party/skia 9339a8a61af0..a4b837971c4b (34 commits) (flutter/engine#9076)
ee6a9c4 Fix unchecked operation warnings in FlutterMain (flutter/engine#9073)
333042c Roll third_party/dart/tools/sdks to 2.3.0 (flutter/engine#9072)
01b8c07 Roll src/third_party/skia f77dbd04b926..9339a8a61af0 (12 commits) (flutter/engine#9065)
26b4fb5 Roll src/third_party/dart e3edfd36b2..ec4d48e241 (7 commits)
9d2d58a Add mouse button support to the macOS shell (flutter/engine#9054)
...
kiku-jw pushed a commit to kiku-jw/flutter that referenced this pull request Jun 14, 2019
flutter/engine@8dc3a4c...4c4c0f8

git log 8dc3a4c..4c4c0f8 --no-merges --oneline
4c4c0f8 Add plugin shim to facilitate old plugins in new embedding (flutter#33478). (flutter/engine#9120)
e8c2b17 Added support for transparent FlutterActivitys (flutter#32740). (flutter/engine#9115)
19c5029 Roll src/third_party/skia 29e013deb476..1013ecfb3421 (3 commits) (flutter/engine#9130)
45d39e1 Revert &flutter#34;Roll src/third_party/dart fee615c5a5..d5405d06f4 (21 commits) (flutter#9127)&flutter#34; (flutter/engine#9135)
44f1b44 Revert &flutter#34;Use track-widget-creation transformer included in the sdk. (flutter#9085)&flutter#34; (flutter/engine#9134)
ae14c5a Roll src/third_party/dart fee615c5a5..d5405d06f4 (21 commits) (flutter/engine#9127)
3ea7ac8 Roll src/third_party/skia 633db4db7672..29e013deb476 (3 commits) (flutter/engine#9128)
8ad0e2f Roll src/third_party/skia 25b63f91b3b4..633db4db7672 (4 commits) (flutter/engine#9125)
37e6e0c Roll src/third_party/skia 8f88b2da05d5..25b63f91b3b4 (2 commits) (flutter/engine#9121)
37b367e Allow specifying both Dart and non-Dart fixtures in engine unit-tests. (flutter/engine#9113)
28f2c05 Roll src/third_party/skia 1f02e8488551..8f88b2da05d5 (3 commits) (flutter/engine#9116)
0932008 Remove outdated TODOs (flutter/engine#9114)
c880ca2 Roll src/third_party/dart 50b0d85804..fee615c5a5 (4 commits)
6e51513 Removing unused imports (flutter/engine#9108)
9ee2697 Roll src/third_party/skia d04aaa3a841a..1f02e8488551 (8 commits) (flutter/engine#9109)
fa2e2d9 Add checks to constructors and add missing constructor members (flutter/engine#9106)
7e1788a Fix unopt variants of profile and release builds. (flutter/engine#9107)
867120c Better help message. (flutter/engine#9097)
e27c6e8 Forward custom IDE flags to GN. (flutter/engine#9023)
6b4ca8d Roll src/third_party/skia 176b214f91bc..d04aaa3a841a (7 commits) (flutter/engine#9105)
a207318 Roll src/third_party/dart ec4d48e241..50b0d85804 (87 commits)
0a6aeb3 Roll src/third_party/skia 213aa46af167..176b214f91bc (2 commits) (flutter/engine#9100)
f2e22aa Roll src/third_party/skia 7730d7cb8fb2..213aa46af167 (3 commits) (flutter/engine#9098)
557db42 Roll src/third_party/skia de7e074e8190..7730d7cb8fb2 (2 commits) (flutter/engine#9096)
64a4a0e Roll src/third_party/skia f06b6d5469a5..de7e074e8190 (1 commits) (flutter/engine#9094)
fdee625 Roll src/third_party/skia 7e5a64f517e4..f06b6d5469a5 (2 commits) (flutter/engine#9093)
daf47f0 Roll src/third_party/skia dc01a84ae098..7e5a64f517e4 (1 commits) (flutter/engine#9092)
41e10f0 Fix internal break since listing contents can return null (flutter/engine#9078)
cf1b203 Roll src/third_party/skia f33c95cd6f55..dc01a84ae098 (3 commits) (flutter/engine#9091)
2404cdc Rename macOS FLEPlugin* to FlutterPlugin* (flutter/engine#9074)
509a43f Apply minor cleanups to Android embedding (flutter/engine#9088)
0a0f330 Removed outdated deprecation comments (flutter/engine#9087)
a44cbbf Delete BSDiff sources (flutter/engine#9086)
0f1ff3b Correct typos, adopt US spellings (flutter/engine#9081)
651c904 Use track-widget-creation transformer included in the sdk. (flutter/engine#9085)
cfa524f New Plugin API PR4: Adds Lifecycle support to the new plugin system. (flutter/engine#9049)
6b8ac18 Roll src/third_party/skia d9430297e74a..f33c95cd6f55 (5 commits) (flutter/engine#9082)
11408ef Update macOS podspec version requirement (flutter/engine#9077)
66c6ae4 Roll src/third_party/skia a4b837971c4b..d9430297e74a (30 commits) (flutter/engine#9080)
9151b37 Roll src/third_party/skia 9339a8a61af0..a4b837971c4b (34 commits) (flutter/engine#9076)
ee6a9c4 Fix unchecked operation warnings in FlutterMain (flutter/engine#9073)
333042c Roll third_party/dart/tools/sdks to 2.3.0 (flutter/engine#9072)
01b8c07 Roll src/third_party/skia f77dbd04b926..9339a8a61af0 (12 commits) (flutter/engine#9065)
26b4fb5 Roll src/third_party/dart e3edfd36b2..ec4d48e241 (7 commits)
9d2d58a Add mouse button support to the macOS shell (flutter/engine#9054)
...
@amirh
Copy link
Contributor

amirh commented Oct 17, 2019

I'm trying to use this lifecycle for the GoogleMaps plugin, when the plugin is initialized it needs to know the current state of the activity, drive the backing Google Map to the state, and forward activity lifecycle events to the backing Google Map.

I guess the way to do that with the current API is to make the plugin ActivityAware, and treat the "current" activity as "destroyed" if it's not attached and only if it is attached use the lifecycle from the plugin binding as the source of the activity lifecycle?

What do you think about providing a lifecycle object for the current "attached" activity as part of the ActivityAware interface, and a lifecycle object for the current service as part of ServiceAware instead of providing a single lifecycle object that may be backed by different lifecycles depending on the attachment state?

@mklim @matthew-carroll

@matthew-carroll
Copy link
Contributor Author

The idea behind providing a single Lifecycle is that it shouldn't matter which component backs it. My guess is that most cases don't care, so splitting out multiple Lifecycle objects for Activity vs Service vs App ends up creating more work for the common case.

@amirh
Copy link
Contributor

amirh commented Oct 17, 2019

The concrete cases in flutter/plugins that need lifecycle (local_auth, and google maps) both care about the activity lifecycle. Do you have some samples about plugins that care about the lifecycle but don't care if it's activity/service?

I think it's worth providing an activity lifecycle object for ActivityAware plugins to keep the plugin code cleaner and less error prone, if it's indeed common to need the lifecycle of an "activity or a service" I guess we can provide both lifecycle objects.

@matthew-carroll
Copy link
Contributor Author

Unfortunately I don't have concrete alternative examples because we just don't cover enough interesting use-cases in 1P at this point. But I would say, would sensors ever care which lifecycle they're listening to? e.g., BLE? Or how about analytics? Or databases? I could be wrong in my analysis, and I'm happy to reconsider, but I figured that most plugins over time will be used for non-UI purposes, because Flutter brings most UI capabilities and plugins need to fill in the non-UI details. For non-UI cases, it seems unlikely that a plugin would care about whether we're dealing with a Service or an Activity.

If we do want to give a difference lifecycle for ActivityAware, then I think we should bite the bullet and offer it for ActivityAware and ServiceAware and not offer one at all in the standard binding. However confusing it might appear now, it would be doubly confusing to have overlap between the Lifecycle in the standard binding and the Lifecycle in ActivityAware.

So I think at this point the question is, how do we effectively determine if an API change is in our best interest? I understand that it looks good in the 2 or so cases we've seen, but how can we ensure we do our due diligence for the general case? And if it is, how does this change impact the plugin extension/migration effort?

CC @mklim

@mklim
Copy link
Contributor

mklim commented Oct 17, 2019

If we do want to give a difference lifecycle for ActivityAware, then I think we should bite the bullet and offer it for ActivityAware and ServiceAware and not offer one at all in the standard binding.

This makes sense to me too.

So I think at this point the question is, how do we effectively determine if an API change is in our best interest? I understand that it looks good in the 2 or so cases we've seen, but how can we ensure we do our due diligence for the general case?

@matthew-carroll my understanding is that a driving reason behind migrating the 1P plugins now is that we want to test the v2 embedding API as soon as possible and make sure that it's covering all of the ecosystem's needs. Given a hypothetical argument for an API surface and actual concrete plugins needing it to expose a different service like we're seeing now, I think it makes more sense to change it to support the known real use cases.

And if it is, how does this change impact the plugin extension/migration effort?

This comes back to the versioning problem again. I think we probably want to hold off on migrating them for now and wait until the API change rolls into stable.

@matthew-carroll
Copy link
Contributor Author

@mklim if we wait for it go stable then our "concrete" use-cases remain nearly as hypothetical as the hypothetical use-cases. The most difficult issues tend to be the ones that seem to appear from nowhere when we attempt to actually write the code. Our attempt to migrate these plugins may have shown an API improvement, but I have a difficult time trusting that improvement until we literally see it solve the problem...

@mklim
Copy link
Contributor

mklim commented Oct 17, 2019

@matthew-carroll I don't follow. In this case @amirh actively started writing out a PR now and identified a problem as he was working on a PR today, so I don't think the use case is hypothetical.

I do see how it's frustrating to have such a long tail on when we can use the API from its development. Flutter plugins try to guarantee support for Flutter stable as our minimum baseline. If we write the plugin to depend on a new API surface it'll be a compile time breakage unless we wait that long for it to roll, at least for as long as the v2 embedding is bundled into the Flutter SDK. Theoretically we could reflect on the new surface to avoid it being a compile time breakage, but that wouldn't help verify that the API surface better suits our use case. If we could depend on the v2 embedding outside of the Flutter SDK we wouldn't be limited to the latest stable roll.

@matthew-carroll
Copy link
Contributor Author

The problem may be very real. But the solution is hypothetical until we apply it. There could be alternative solutions, right? And there could be weird Android race conditions that we won't see until we try it. This Lifecycle API surface seems to be the greatest cause for concern in the entire plugin surface. Just because we make an adjustment doesn't mean that we've shaken out all the issues. In fact, I think the fact that we want to make a significant change to it is a great reason to make sure we exercise the new solution thoroughly.

@amirh
Copy link
Contributor

amirh commented Oct 17, 2019

I'd suggest we first determine, given the information we have right now, what we think the API should look like.

After we've done that we can talk about timelines, migrations, and potential compromises.

@matthew-carroll
Copy link
Contributor Author

Sure. Happy to talk about the API. It seems like we're all pretty close on that expectation, though. We can solidify the proposal, but then all of my concerns point towards us exercising that API.

@amirh
Copy link
Contributor

amirh commented Oct 17, 2019

To make sure I understand you correctly - you're theoretically support splitting into 2 lifecycle objects if we had no timeline considerations?

@matthew-carroll
Copy link
Contributor Author

Yes, I'm open to giving a Lifecycle to ActivityAware and ServiceAware, and removing it from FlutterPluginBinding, if the ecosystem team believes that is a better experience for the entire ecosystem.

I am very concerned with making that change and not completely validating it before the next stable. I understand the rationale that we have to believe it will be OK, but this whole exercise is about direct validation. And I do believe in the importance of direct validation.

@mklim
Copy link
Contributor

mklim commented Oct 17, 2019

What if we wrote a PR tentatively using the new interface as soon as it was available and tested it locally with master, but waited on merging it until it was in stable? It's not perfect but that would at least locally validate the API before waiting for an entire roll cycle.

@matthew-carroll
Copy link
Contributor Author

That's definitely a step in the right direction. There was previously a lot of discouragement about creating staging branches. But I don't have any problem with staging branches.

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.

4 participants