8000 Android Add to App: Single Engine going from FlutterFragment->FlutterActivity and back · Issue #95877 · flutter/flutter · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Android Add to App: Single Engine going from FlutterFragment->FlutterActivity and back #95877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ryanneuroflow opened this issue Dec 27, 2021 · 10 comments
Labels
r: duplicate Issue is closed as a duplicate of an existing issue

Comments

@ryanneuroflow
Copy link
ryanneuroflow commented Dec 27, 2021
  • I'm using a single FlutterEngine in an Add to App architecture.
  • In the app, I have a FlutterFragment embedded in a tab bar.
  • I then open up a new full screen FlutterActivity.
  • When I navigate back to the tab bar screen, the FlutterFragment is no longer associated with the FlutterEngine, and so won't draw itself or respond to events.
  • How can I re-associate the FlutterEngine with my FlutterFragment, without recreating the FlutterFragment? Or would recreating it be the best practice? On iOS I can set the FlutterEngine's viewController property, and everything works nicely. Can't find an equivalent in Android that is publicly accessible.

I believe this may be related to: #93905

Thank you!

@willlockwood
Copy link
Contributor
willlockwood commented Dec 27, 2021

I believe you're running into the same problem as detailed here: #49950

Essentially, I believe it's an intentional decision to discourage the association of multiple flutter view components with a single cached engine on Android. It seems like the direction they're going in is to encourage the creation of multiple lightweight flutter engines if you need multiple instances of flutter in an add-to-app use case. Here's the original design doc: https://docs.google.com/document/d/1fdKRufqUzQvERcqNIUSq-GdabXc4k8VIsClzRElJ6KY/edit#

I ran into this at my job where we were migrating a native app to Flutter and we had some hybrid navigation, and since we were expecting it to be a temporary situation for us, we ended up essentially forking the embedding library and following the customizations that were used to solve this problem in the thaw library: https://github.com/littleGnAl/thaw (this was suggested in a comment in the issue linked above). We then just have to run a diff whenever each time we upgrade flutter to resolve conflicts and make sure that our custom implementation is going to continue to work with the new embeddings.

There are other things you can do that help but aren't as thorough. For example, you technically could override detachFromFlutterEngine on FlutterActivity or FlutterFragment with an empty function—this will prevent the activity or fragment from calling release internally, which will keep your flutter experience alive when navigating.

The downside there is that you currently can't prevent the engine from detaching from the plugins your flutter app is using (which can be an easy bug to overlook). Going with the solutions in the thaw library above will help you with that.

@willlockwood
Copy link
Contributor

Ooh actually just saw this on that issue—looks like something was merged in the past month that might help make this not a problem in an upcoming flutter release: flutter/engine#30202.

Doesn't solve your problem immediately, but from what I can tell on an initial read of that code, it seems to be aiming to fix this particular problem, which is phenomenal because it's a huge pain to work around this

@0xZOne
Copy link
Member
0xZOne commented Dec 28, 2021
  • I'm using a single FlutterEngine in an Add to App architecture.
  • In the app, I have a FlutterFragment embedded in a tab bar.
  • I then open up a new full screen FlutterActivity.
  • When I navigate back to the tab bar screen, the FlutterFragment is no longer associated with the FlutterEngine, and so won't draw itself or respond to events.
  • How can I re-associate the FlutterEngine with my FlutterFragment, without recreating the FlutterFragment? Or would recreating it be the best practice? On iOS I can set the FlutterEngine's viewController property, and everything works nicely. Can't find an equivalent in Android that is publicly accessible.

I believe this may be related to: #93905

Thank you!

You can refer to the implementation of FlutterBoostFragment.

@darshankawar darshankawar added the in triage Presently being triaged by the triage team label Dec 28, 2021
@darshankawar
Copy link
Member

@ryanneuroflow
Along with above linked issues and explaination, I think you are hitting this issue. Check the same and see if it helps to answer your question.

@darshankawar darshankawar added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Dec 28, 2021
@ryanneuroflow
Copy link
Author

"intentional decision to discourage the association of multiple flutter view components with a single cached engine on Android"

@willlockwood
Thank you very much for the response! Curious on your take: Our eventual goal is to migrate the entire app to Flutter, and my current understanding of one of the downsides of using multiple engines, is they don't talk to each other. For example, if I were to use one Engine per Activity/Fragment, and I make a network request in Flutter to my server, but I want that response model object to be accessible between all the different Engines, the only current way to do that would be to use native ios/android code as an intermediary and share the model object using method channels by going FlutterEngine1->Native->FlutterEngine2. Does that sound correct?

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Dec 28, 2021
@ryanneuroflow
Copy link
Author
ryanneuroflow commented Dec 28, 2021

You can refer to the implementation of FlutterBoostFragment.

@0xZOne
Thank you very much! I see that FlutterBoostFragment uses the following line, which now appears to not be possible:
getFlutterEngine().getActivityControlSurface().attachToActivity(getActivity(), getLifecycle());

Type mismatch. Required: ExclusiveAppComponent<Activity!> Found: FragmentActivity?

@0xZOne
Copy link
Member
0xZOne commented Dec 29, 2021

You can refer to the implementation of FlutterBoostFragment.

@0xZOne Thank you very much! I see that FlutterBoostFragment uses the following line, which now appears to not be possible: getFlutterEngine().getActivityControlSurface().attachToActivity(getActivity(), getLifecycle());

Type mismatch. Required: ExclusiveAppComponent<Activity!> Found: FragmentActivity?

Before the official accepts this PR or proposes a new solution, the following workaround can be considered:

diff --git a/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostActivity.java b/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostActivity.java
index ab28533..1608eb5 100644
--- a/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostActivity.java
+++ b/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostActivity.java
@@ -152,7 +152,7 @@ public class FlutterBoostActivity extends FlutterActivity implements FlutterView
     private void performAttach() {
         if (!isAttached) {
             // Attach plugins to the activity.
-            getFlutterEngine().getActivityControlSurface().attachToActivity(getActivity(), getLifecycle());
+            getFlutterEngine().getActivityControlSurface().attachToActivity(delegate, getLifecycle());
 
             if (platformPlugin == null) {
                 platformPlugin = new PlatformPlugin(getActivity(), getFlutterEngine().getPlatformChannel());
diff --git a/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostFragment.java b/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostFragment.java
index b4ead66..5f954e6 100644
--- a/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostFragment.java
+++ b/android/src/main/java/com/idlefish/flutterboost/containers/FlutterBoostFragment.java
@@ -43,6 +43,17 @@ public class FlutterBoostFragment extends FlutterFragment implements FlutterView
     private boolean isAttached = false;
     private boolean isFinishing = false;
 
+    class FakeExclusiveAppComponent implements io.flutter.embedding.android.ExclusiveAppComponent<Activity> {
+        public void detachFromFlutterEngine() {
+            // do nothing.
+        }
+
+        public Activity getAppComponent() {
+            return getActivity();
+        }
+    }
+    private FakeExclusiveAppComponent fakeAppComponent = new FakeExclusiveAppComponent();
+
     // @Override
     public void detachFromFlutterEngine() {
         /**
@@ -303,7 +314,7 @@ public class FlutterBoostFragment extends FlutterFragment implements FlutterView
     private void performAttach() {
         if (!isAttached) {
             // Attach plugins to the activity.
-            getFlutterEngine().getActivityControlSurface().attachToActivity(getActivity(), getLifecycle());
+            getFlutterEngine().getActivityControlSurface().attachToActivity(fakeAppComponent, getLifecycle());
 
             if (platformPlugin == null) {
                 platformPlugin = new PlatformPlugin(getActivity(), getFlutterEngine().getPlatformChannel());

@darshankawar
Copy link
Member

@ryanneuroflow
Please follow-up in #93905, #49950 and #67011 for further updates on your use case.
Closing from here in favor of above linked issues.
If anyone disagrees, write in comments and I'll reopen it.

@darshankawar darshankawar added r: duplicate Issue is closed as a duplicate of an existing issue and removed in triage Presently being triaged by the triage team labels Dec 29, 2021
@willlockwood
Copy link
Contributor

Thank you very much for the response! Curious on your take: Our eventual goal is to migrate the entire app to Flutter, and my current understanding of one of the downsides of using multiple engines, is they don't talk to each other. For example, if I were to use one Engine per Activity/Fragment, and I make a network request in Flutter to my server, but I want that response model object to be accessible between all the different Engines, the only current way to do that would be to use native ios/android code as an intermediary and share the model object using method channels by going FlutterEngine1->Native->FlutterEngine2. Does that sound correct?

@ryanneuroflow Yes that sounds correct to me. That's pretty much the same position we were in. In my opinion, multiple engines isn't a good solution there because once you migrate that middle part of your flow to Flutter, you're going to have to rewrite/refactor a lot of stuff to merge those two separate engine experiences into one Flutter app. It was really a non-starter option for us, and I'd suggest that you find a way to work around the single-engine limitation as well, especially given that it looks like they're in progress on a fix.

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
r: duplicate Issue is closed as a duplicate of an existing issue
Projects
None yet
Development

No branches or pull requests

4 participants
0