Flutter-Native混合解决方案FlutterBoost浅析

github:
https://github.com/alibaba/flutter_boost

demo:
https://github.com/alibaba/flutter_boost/tree/master/example

主要内容

  • 1、flutter打开native页面
  • 2、native打开flutter页面
  • 3、flutter页面打开flutter页面
  • 4、native打开native页面
  • 5、打开flutter fragment

1、flutter打开native页面

调用入口
simple_page_widgets.dart


                  ///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
                  ///例如:sample://nativePage?aaa=bbb
                  onTap: () => FlutterBoost.singleton
                      .open("sample://nativePage", urlParams: {
                    "query": {"aaa": "bbb"}
                  }),

flutter调用native方法openPage,通过MethodChannel 调用openPage
flutter_boost.dart


  Future<Map<dynamic,dynamic>> open(String url,{Map<dynamic,dynamic> urlParams,Map<dynamic,dynamic> exts}){

    Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
    properties["url"] = url;
    properties["urlParams"] = urlParams;
    properties["exts"] = exts;
    print("invokeMethod open native page "+ url);
    return channel.invokeMethod<Map<dynamic,dynamic>>(
        'openPage', properties);
  }

FlutterBoostPlugin.java


   class BoostMethodHandler implements MethodChannel.MethodCallHandler {

        @Override
        public void onMethodCall(MethodCall methodCall, final MethodChannel.Result result) {

            FlutterViewContainerManager mManager = (FlutterViewContainerManager) FlutterBoost.instance().containerManager();
            switch (methodCall.method) {
                case "pageOnStart": {
                    Map<String, Object> pageInfo = new HashMap<>();

                    try {
                        IContainerRecord record = mManager.getCurrentTopRecord();

                        if (record == null) {
                            record = mManager.getLastGenerateRecord();
                        }

                        if (record != null) {
                            pageInfo.put("name", record.getContainer().getContainerUrl());
                            pageInfo.put("params", record.getContainer().getContainerUrlParams());
                            pageInfo.put("uniqueId", record.uniqueId());
                        }

                        result.success(pageInfo);
                        FlutterBoost.instance().setFlutterPostFrameCallTime(new Date().getTime());


                    } catch (Throwable t) {
                        result.error("no flutter page found!", t.getMessage(), t);
                    }
                }
                break;
                case "openPage": {
                    try {
                        Map<String, Object> params = methodCall.argument("urlParams");
                        Map<String, Object> exts = methodCall.argument("exts");
                        String url = methodCall.argument("url");
                        Log.i("openPageByUrl","BoostMethodHandler openPage  " + url);
                        mManager.openContainer(url, params, exts, new FlutterViewContainerManager.OnResult() {
                            @Override
                            public void onResult(Map<String, Object> rlt) {
                                if (result != null) {
                                    result.success(rlt);
                                }
                            }
                        });
                    } catch (Throwable t) {
                        result.error("open page error", t.getMessage(), t);
                    }
                }
                break;
                case "closePage": {
                    try {
                        String uniqueId = methodCall.argument("uniqueId");
                        Map<String, Object> resultData = methodCall.argument("result");
                        Map<String, Object> exts = methodCall.argument("exts");

                        mManager.closeContainer(uniqueId, resultData, exts);
                        result.success(true);
                    } catch (Throwable t) {
                        result.error("close page error", t.getMessage(), t);
                    }
                }
                break;
                case "onShownContainerChanged": {
                    try {
                        String newId = methodCall.argument("newName");
                        String oldId = methodCall.argument("oldName");

                        mManager.onShownContainerChanged(newId, oldId);
                        result.success(true);
                    } catch (Throwable t) {
                        result.error("onShownContainerChanged", t.getMessage(), t);
                    }
                }
                break;
                default: {
                    result.notImplemented();
                }
            }
        }
    }


FlutterViewContainerManager.java
调用openContainer


    void openContainer(String url, Map<String, Object> urlParams, Map<String, Object> exts,OnResult onResult) {
        Context context = FlutterBoost.instance().currentActivity();
        if(context == null) {
            context = FlutterBoost.instance().platform().getApplication();
        }

        if(urlParams == null) {
            urlParams = new HashMap<>();
        }

        int requestCode = 0;
        final Object v = urlParams.remove("requestCode");
        if(v != null) {
            requestCode = Integer.valueOf(String.valueOf(v));
        }

        final String uniqueId = ContainerRecord.genUniqueId(url);
        urlParams.put(IContainerRecord.UNIQ_KEY,uniqueId);

        IContainerRecord currentTopRecord = getCurrentTopRecord();
        if(onResult != null) {
            mOnResults.put(currentTopRecord.uniqueId(),onResult);
        }

        FlutterBoost.instance().platform().openContainer(context,url,urlParams,requestCode,exts);
    }

MyApplication.java


public class MyApplication extends Application {


    @Override
    public void onCreate() {
        super.onCreate();

        INativeRouter router =new INativeRouter() {
            @Override
            public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
                Log.i("openPageByUrl","openContainer url " + url);
               String  assembleUrl=Utils.assembleUrl(url,urlParams);
                PageRouter.openPageByUrl(context,assembleUrl, urlParams);
            }

        };

        FlutterBoost.BoostPluginsRegister pluginsRegister= new FlutterBoost.BoostPluginsRegister(){

            @Override
            public void registerPlugins(PluginRegistry mRegistry) {
                GeneratedPluginRegistrant.registerWith(mRegistry);
                TextPlatformViewPlugin.register(mRegistry.registrarFor("TextPlatformViewPlugin"));
            }
        };

        Platform platform= new FlutterBoost
                .ConfigBuilder(this,router)
                .isDebug(true)
                .whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
                .renderMode(FlutterView.RenderMode.texture)
                .pluginsRegister(pluginsRegister)
                .build();

        FlutterBoost.instance().init(platform);



    }
}

进入native页面,调用native的 startActivity
PageRouter.java

    public static boolean openPageByUrl(Context context, String url, Map params) {
        return openPageByUrl(context, url, params, 0);
    }

    public static boolean openPageByUrl(Context context, String url, Map params, int requestCode) {

        String path = url.split("\\?")[0];

        Log.i("openPageByUrl",path);
        try {
            if (pageName.containsKey(path)) {
                Intent intent = BoostFlutterActivity.withNewEngine().url(pageName.get(path)).params(params)
                        .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context);
                if(context instanceof Activity){
                    Activity activity=(Activity)context;
                    activity.startActivityForResult(intent,requestCode);
                }else{
                    context.startActivity(intent);
                }
                return true;
            } else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) {
                context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));
                return true;
            } else if (url.startsWith(NATIVE_PAGE_URL)) {
                context.startActivity(new Intent(context, NativePageActivity.class));
                return true;
            }

            return false;

        } catch (Throwable t) {
            return false;
        }
    }

2、native打开flutter页面

Flutter 页面的创建
1、打开flutter 入口



            PageRouter.openPageByUrl(this, PageRouter.FLUTTER_PAGE_FIRST_URL,params);

2、PageRouter分发,设置NewEngineIntentBuilder,配置url和参数,打开BoostFlutterActivity
PageRouter.java


    public static boolean openPageByUrl(Context context, String url, Map params) {
        return openPageByUrl(context, url, params, 0);
    }

    public static boolean openPageByUrl(Context context, String url, Map params, int requestCode) {

        String path = url.split("\\?")[0];

        Log.i("openPageByUrl",path);
        try {
            if (pageName.containsKey(path)) {
                Intent intent = BoostFlutterActivity.withNewEngine().url(pageName.get(path)).params(params)
                        .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context);
                if(context instanceof Activity){
                    Activity activity=(Activity)context;
                    activity.startActivityForResult(intent,requestCode);
                }else{
                    context.startActivity(intent);
                }
                return true;
            } else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) {
                context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));
                return true;
            } else if (url.startsWith(NATIVE_PAGE_URL)) {
                context.startActivity(new Intent(context, NativePageActivity.class));
                return true;
            }

            return false;

        } catch (Throwable t) {
            return false;
        }
    }

3、BoostFlutterActivity 初始化FlutterActivityAndFragmentDelegate和createFlutterView
BoostFlutterActivity.java

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        switchLaunchThemeForNormalTheme();


        super.onCreate(savedInstanceState);
        Log.d(TAG, "BoostFlutterActivity onCreate");
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);

        delegate = new FlutterActivityAndFragmentDelegate(this);
        delegate.onAttach(this);

        configureWindowForTransparency();
        setContentView(createFlutterView());
        configureStatusBarForFullscreenFlutterExperience();
    }


    @NonNull
    protected View createFlutterView() {
        return delegate.onCreateView(
                null /* inflater */,
                null /* container */,
                null /* savedInstanceState */);
    }

4、FlutterActivityAndFragmentDelegate attach 初始化flutter环境
FlutterActivityAndFragmentDelegate.java

  void onAttach(@NonNull Context context) {
        ensureAlive();
        Log.d(TAG, "onAttach");

        if (FlutterBoost.instance().platform().whenEngineStart() == FlutterBoost.ConfigBuilder.FLUTTER_ACTIVITY_CREATED) {
            FlutterBoost.instance().doInitialFlutter();
            FlutterBoost.instance().boostPluginRegistry();
        }
        // When "retain instance" is true, the FlutterEngine will survive configuration
        // changes. Therefore, we create a new one only if one does not already exist.
        if (flutterEngine == null) {
            Log.d(TAG, "setupFlutterEngine");
            setupFlutterEngine();
        }

        // Regardless of whether or not a FlutterEngine already existed, the PlatformPlugin
        // is bound to a specific Activity. Therefore, it needs to be created and configured
        // every time this Fragment attaches to a new Activity.
        // TODO(mattcarroll): the PlatformPlugin needs to be reimagined because it implicitly takes
        //                    control of the entire window. This is unacceptable for non-fullscreen
        //                    use-cases.
        platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);


        host.configureFlutterEngine(flutterEngine);


        host.getActivity().getWindow().setFormat(PixelFormat.TRANSLUCENT);
    }


    private void setupFlutterEngine() {
        Log.d(TAG, "Setting up FlutterEngine.");


        // Second, defer to subclasses for a custom FlutterEngine.
        flutterEngine = host.provideFlutterEngine(host.getContext());
        if (flutterEngine != null) {
            isFlutterEngineFromHost = true;
            return;
        }

        // Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our
        // FlutterView.
        Log.d(TAG, "No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
                + " this NewFlutterFragment.");
        isFlutterEngineFromHost = false;
    }

5、onCreateView通过 FlutterViewContainerManager 新建ContainerRecord
mSyncer = FlutterBoost.instance().containerManager().generateSyncer(this);
FlutterActivityAndFragmentDelegate.java


@SuppressLint("ResourceType")
    @NonNull
    View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Creating FlutterView.");
        flutterEngine.getActivityControlSurface().attachToActivity(
                host.getActivity(),
                host.getLifecycle()
        );


        Log.d(TAG, "onCreateView getContainerUrl " + getContainerUrl());
        mSyncer = FlutterBoost.instance().containerManager().generateSyncer(this);

        ensureAlive();
        flutterView = new XFlutterView(host.getActivity(), FlutterBoost.instance().platform().renderMode(), host.getTransparencyMode());


        flutterSplashView = new FlutterSplashView(host.getContext());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            flutterSplashView.setId(View.generateViewId());
        } else {
            // TODO(mattcarroll): Find a better solution to this ID. This is a random, static ID.
            // It might conflict with other Views, and it means that only a single FlutterSplashView
            // can exist in a View hierarchy at one time.
            flutterSplashView.setId(486947586);
        }
        flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());
        mSyncer.onCreate();
        return flutterSplashView;
    }

FlutterViewContainerManager.java



    @Override
    public IOperateSyncer generateSyncer(IFlutterViewContainer container) {
        Utils.assertCallOnMainThread();
        Log.d(TAG, "generateSyncer.");
        ContainerRecord record = new ContainerRecord(this, container);
        Log.d(TAG, "container.getContainerUrl() "+container.getContainerUrl());
        if (mRecordMap.put(container, record) != null) {
            Debuger.exception("container:" + container.getContainerUrl() + " already exists!");
        }

        mRefs.add(new ContainerRef(record.uniqueId(),container));

        return record;
    }

XFlutterView类型的flutterView ,通过TextureView或者SurfaceView显示flutter view
XFlutterView.java

  private void init() {
    Log.v(TAG, "Initializing FlutterView");

    switch (renderMode) {
      case surface:
        Log.v(TAG, "Internally using a FlutterSurfaceView.");
        FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(getContext(), transparencyMode == FlutterView.TransparencyMode.transparent);
        renderSurface = flutterSurfaceView;
        addView(flutterSurfaceView);
        break;
      case texture:
        Log.v(TAG, "Internally using a FlutterTextureView.");
        XFlutterTextureView flutterTextureView = new XFlutterTextureView(getContext());
        renderSurface = flutterTextureView;
        addView(flutterTextureView);
        break;
    }

6、步骤3 最后的onCreateView 函数最后执行创建
mSyncer.onCreate();
通过MethodChannel 调用didInitPageContainer


ContainerRecord.java

    @Override
    public void onCreate() {
        Utils.assertCallOnMainThread();

        if (mState != STATE_UNKNOW) {
            Debuger.exception("state error");
        }

        mState = STATE_CREATED;
//        mContainer.getBoostFlutterView().onResume();
        mProxy.create();
    }


        private void create() {

            if (mState == STATE_UNKNOW) {
                Log.d(TAG, "create. Container.getContainerUrl() "+mContainer.getContainerUrl());
                invokeChannelUnsafe("didInitPageContainer",
                        mContainer.getContainerUrl(),
                        mContainer.getContainerUrlParams(),
                        mUniqueId
                );
                //Debuger.log("didInitPageContainer");
                mState = STATE_CREATED;
            }
        }

7、boost_channel.dart 注册flutter 方法

class BoostChannel {
  final MethodChannel _methodChannel = MethodChannel("flutter_boost");

  final Map<String, List<EventListener>> _eventListeners = Map();
  final Set<MethodHandler> _methodHandlers = Set();

  BoostChannel() {
    _methodChannel.setMethodCallHandler((MethodCall call){
      if (call.method == "__event__") {
        String name = call.arguments["name"];
        Map arg = call.arguments["arguments"];
        List<EventListener> list = _eventListeners[name];
        if (list != null) {
          for (EventListener l in list) {
            l(name, arg);
          }
        }
      }else{
        for(MethodHandler handler in _methodHandlers) {
          handler(call);
        }
      }

      return Future.value();
    });
  }

8、container_coordinator 执行didInitPageContainer
container_coordinator.dart

  ContainerCoordinator(BoostChannel channel) {
    assert(_instance == null);

    _instance = this;

    channel.addEventListener("lifecycle",
        (String name, Map arguments) => _onChannelEvent(arguments));

    channel.addMethodHandler((MethodCall call) => _onMethodCall(call));
  }

  Future<dynamic> _onMethodCall(MethodCall call) {
    Logger.log("onMetohdCall ${call.method}");

    switch (call.method) {
      case "didInitPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerDidInit(pageName, params, uniqueId);
        }
        break;
      case "willShowPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerWillShow(pageName, params, uniqueId);
        }
        break;
      case "didShowPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          nativeContainerDidShow(pageName, params, uniqueId);
        }
        break;
      case "willDisappearPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerWillDisappear(pageName, params, uniqueId);
        }
        break;
      case "didDisappearPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerDidDisappear(pageName, params, uniqueId);
        }
        break;
      case "willDeallocPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerWillDealloc(pageName, params, uniqueId);
        }
        break;
      case "onNativePageResult":
        {}
        break;
    }

  bool _nativeContainerDidInit(String name, Map params, String pageId) {
    performContainerLifeCycle(_createContainerSettings(name, params, pageId),
        ContainerLifeCycle.Init);
    return true;
  }

9、_createContainerSettings 建立fluttter view

BoostContainerSettings _createContainerSettings(
    String name, Map params, String pageId) {
  Widget page;

  final BoostContainerSettings routeSettings = BoostContainerSettings(
      uniqueId: pageId,
      name: name,
      params: params,
      builder: (BuildContext ctx) {
        //Try to build a page using keyed builder.
        if (_pageBuilders[name] != null) {
          page = _pageBuilders[name](name, params, pageId);
        }

        //Build a page using default builder.
        if (page == null && _defaultPageBuilder != null) {
          page = _defaultPageBuilder(name, params, pageId);
        }

        assert(page != null);
        Logger.log('build widget:$page for page:$name($pageId)');

        return page;
      });

  return routeSettings;
}

10、_createContainerSettings 中的PageBuilder是main开始配置

main.dart

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();


    FlutterBoost.singleton.registerPageBuilders({
      'embeded': (pageName, params, _)=>EmbededFirstRouteWidget(),
      'first': (pageName, params, _) => FirstRouteWidget(),
      'second': (pageName, params, _) => SecondRouteWidget(),
      'tab': (pageName, params, _) => TabRouteWidget(),
      'platformView': (pageName, params, _) => PlatformRouteWidget(),
      'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
      ///可以在native层通过 getContainerParams 来传递参数
      'flutterPage': (pageName, params, _) {
        print("flutterPage params:$params");

        return FlutterRouteWidget(params:params);
      },
    });
    FlutterBoost.singleton.addBoostNavigatorObserver(TestBoostNavigatorObserver());
  }

Flutter 页面的显示

1、BoostFlutterActivity onResume
mSyncer.onAppear();

BoostFlutterActivity.java

    @Override
    protected void onResume() {
        super.onResume();
        lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        delegate.onResume();
    }

FlutterActivityAndFragmentDelegate.java

void
 onResume() {
        mSyncer.onAppear();

        Log.v(TAG, "onResume()");
        ensureAlive();
        flutterEngine.getLifecycleChannel().appIsResumed();

        BoostPluginRegistry registry = (BoostPluginRegistry) FlutterBoost.instance().getPluginRegistry();
        ActivityPluginBinding binding = registry.getRegistrarAggregate().getActivityPluginBinding();
        if (binding != null && (binding.getActivity() != this.host.getActivity())) {
            flutterEngine.getActivityControlSurface().attachToActivity(
                    host.getActivity(),
                    host.getLifecycle()
            );
        }

    }

2、ContainerRecord 调用didShowPageContainer

ContainerRecord.java
        private void appear() {
            Log.d(TAG, "appear. Container.getContainerUrl() "+mContainer.getContainerUrl());
            invokeChannelUnsafe("didShowPageContainer",
                    mContainer.getContainerUrl(),
                    mContainer.getContainerUrlParams(),
                    mUniqueId
            );
            //Debuger.log("didShowPageContainer");

            mState = STATE_APPEAR;
        }

FlutterBoostPlugin.java



  private class MethodChannelProxy {
        private int mState = STATE_UNKNOW;

        private void create() {

            if (mState == STATE_UNKNOW) {
                Log.d(TAG, "create. Container.getContainerUrl() "+mContainer.getContainerUrl());
                invokeChannelUnsafe("didInitPageContainer",
                        mContainer.getContainerUrl(),
                        mContainer.getContainerUrlParams(),
                        mUniqueId
                );
                //Debuger.log("didInitPageContainer");
                mState = STATE_CREATED;
            }
        }

        private void appear() {
            Log.d(TAG, "appear. Container.getContainerUrl() "+mContainer.getContainerUrl());
            invokeChannelUnsafe("didShowPageContainer",
                    mContainer.getContainerUrl(),
                    mContainer.getContainerUrlParams(),
                    mUniqueId
            );
            //Debuger.log("didShowPageContainer");

            mState = STATE_APPEAR;
        }

        private void disappear() {
            if (mState < STATE_DISAPPEAR) {
                invokeChannel("didDisappearPageContainer",
                        mContainer.getContainerUrl(),
                        mContainer.getContainerUrlParams(),
                        mUniqueId
                );
                //Debuger.log("didDisappearPageContainer");

                mState = STATE_DISAPPEAR;
            }
        }

        private void destroy() {
            if (mState < STATE_DESTROYED) {
                invokeChannel("willDeallocPageContainer",
                        mContainer.getContainerUrl(),
                        mContainer.getContainerUrlParams(),
                        mUniqueId
                );
                //Debuger.log("willDeallocPageContainer");

                mState = STATE_DESTROYED;
            }
        }

        public void invokeChannel(String method, String url, Map params, String uniqueId) {
            HashMap<String, Object> args = new HashMap<>();
            args.put("pageName", url);
            args.put("params", params);
            args.put("uniqueId", uniqueId);
            FlutterBoost.instance().channel().invokeMethod(method, args);
        }

        public void invokeChannelUnsafe(String method, String url, Map params, String uniqueId) {
            HashMap<String, Object> args = new HashMap<>();
            args.put("pageName", url);
            args.put("params", params);
            args.put("uniqueId", uniqueId);
            FlutterBoost.instance().channel().invokeMethodUnsafe(method, args);
        }
    }

3、ContainerRecord 调用didShowPageContainer
container_coordinator.dart


  Future<dynamic> _onMethodCall(MethodCall call) {
    Logger.log("onMetohdCall ${call.method}");

    switch (call.method) {
      case "didInitPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerDidInit(pageName, params, uniqueId);
        }
        break;
      case "willShowPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          _nativeContainerWillShow(pageName, params, uniqueId);
        }
        break;
      case "didShowPageContainer":
        {
          String pageName = call.arguments["pageName"];
          Map params = call.arguments["params"];
          String uniqueId = call.arguments["uniqueId"];
          nativeContainerDidShow(pageName, params, uniqueId);
        }

  bool _nativeContainerWillShow(String name, Map params, String pageId) {
    if (FlutterBoost.containerManager?.containsContainer(pageId) != true) {
      FlutterBoost.containerManager
          ?.pushContainer(_createContainerSettings(name, params, pageId));
    }

    //TODO, 需要验证android代码是否也可以移到这里
    if (Platform.isIOS) {
      try {
        final SemanticsOwner owner =
            WidgetsBinding.instance.pipelineOwner?.semanticsOwner;
        final SemanticsNode root = owner?.rootSemanticsNode;
        root?.detach();
        root?.attach(owner);
      } catch (e) {
        assert(false, e.toString());
      }
    }
    return true;
  }

4、container_manager pushContainer
container_manager.dart

  void pushContainer(BoostContainerSettings settings) {
    assert(settings.uniqueId != _onstage.settings.uniqueId);
    assert(_offstage.every((BoostContainer container) =>
        container.settings.uniqueId != settings.uniqueId));
    print("pushContainer ");
    _offstage.add(_onstage);
    _onstage = BoostContainer.obtain(widget.initNavigator, settings);

    setState(() {});

    for (BoostContainerObserver observer in FlutterBoost
        .singleton.observersHolder
        .observersOf<BoostContainerObserver>()) {
      observer(ContainerOperation.Push, _onstage.settings);
    }
    Logger.log('ContainerObserver#2 didPush');
  }

boost_container.dart

  factory BoostContainer.obtain(
          Navigator navigator, BoostContainerSettings settings) =>
      BoostContainer(
          key: GlobalKey<BoostContainerState>(),
          settings: settings,
          onGenerateRoute: (RouteSettings routeSettings) {
            if (routeSettings.name == '/') {
              return BoostPageRoute<dynamic>(
                  pageName: settings.name,
                  params: settings.params,
                  uniqueId: settings.uniqueId,
                  animated: false,
                  settings: routeSettings,
                  builder: settings.builder);
            } else {
              return navigator.onGenerateRoute(routeSettings);
            }
          },
          observers: <NavigatorObserver>[
            ContainerNavigatorObserver.bindContainerManager(),
            HeroController(),
          ],
          onUnknownRoute: navigator.onUnknownRoute);

boost_page_route.dart

typedef Widget PageBuilder(String pageName, Map params, String uniqueId);

class BoostPageRoute<T> extends MaterialPageRoute<T> {
  final String pageName;
  final String uniqueId;
  final Map params;
  final bool animated;
  final WidgetBuilder builder;
  final RouteSettings settings;

  final Set<VoidCallback> backPressedListeners = Set<VoidCallback>();

  BoostPageRoute(
      {this.pageName,
      this.params,
      this.uniqueId,
      this.animated,
      this.builder,
      this.settings})
      : super(builder: builder, settings: settings);

  static BoostPageRoute<T> of<T>(BuildContext context) {
    final Route<T> route = ModalRoute.of(context);
    if (route != null && route is BoostPageRoute<T>) {
      return route;
    } else {
      throw Exception('not in a BoostPageRoute');
    }
  }

  static BoostPageRoute<T> tryOf<T>(BuildContext context) {
    final Route<T> route = ModalRoute.of(context);
    if (route != null && route is BoostPageRoute<T>) {
      return route;
    } else {
      return null;
    }
  }
}

3、flutter页面打开flutter页面

simple_page_widgets.dart

                  FlutterBoost.singleton.open("second").then((Map value) {
                    print(
                        "call me when page is finished. did recieve second route result $value");
                  });
                  

flutter_boost.dart


    Future<Map<dynamic,dynamic>> open(String url,{Map<dynamic,dynamic> urlParams,Map<dynamic,dynamic> exts}){

    Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
    properties["url"] = url;
    properties["urlParams"] = urlParams;
    properties["exts"] = exts;
    print("invokeMethod open native page "+ url);
    return channel.invokeMethod<Map<dynamic,dynamic>>(
        'openPage', properties);
  }

FlutterBoostPlugin.java

    class BoostMethodHandler implements MethodChannel.MethodCallHandler {

        @Override
        public void onMethodCall(MethodCall methodCall, final MethodChannel.Result result) {

            FlutterViewContainerManager mManager = (FlutterViewContainerManager) FlutterBoost.instance().containerManager();
            switch (methodCall.method) {
                case "pageOnStart": {
                    Map<String, Object> pageInfo = new HashMap<>();

                    try {
                        IContainerRecord record = mManager.getCurrentTopRecord();

                        if (record == null) {
                            record = mManager.getLastGenerateRecord();
                        }

                        if (record != null) {
                            Log.i("pageOnStart","record.getContainer().getContainerUrl() " + record.getContainer().getContainerUrl());
                            pageInfo.put("name", record.getContainer().getContainerUrl());
                            pageInfo.put("params", record.getContainer().getContainerUrlParams());
                            pageInfo.put("uniqueId", record.uniqueId());
                        }

                        result.success(pageInfo);
                        FlutterBoost.instance().setFlutterPostFrameCallTime(new Date().getTime());


                    } catch (Throwable t) {
                        result.error("no flutter page found!", t.getMessage(), t);
                    }
                }
                break;
                case "openPage": {
                    try {
                        Map<String, Object> params = methodCall.argument("urlParams");
                        Map<String, Object> exts = methodCall.argument("exts");
                        String url = methodCall.argument("url");
                        Log.i("openPageByUrl","BoostMethodHandler openPage  " + url);
                        mManager.openContainer(url, params, exts, new FlutterViewContainerManager.OnResult() {
                            @Override
                            public void onResult(Map<String, Object> rlt) {
                                if (result != null) {
                                    result.success(rlt);
                                }
                            }
                        });
                    } catch (Throwable t) {
                        result.error("open page error", t.getMessage(), t);
                    }
                }

MyApplication.java

public class MyApplication extends Application {


    @Override
    public void onCreate() {
        super.onCreate();

        INativeRouter router =new INativeRouter() {
            @Override
            public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
                Log.i("openPageByUrl","MyApplication openContainer url " + url);
               String  assembleUrl=Utils.assembleUrl(url,urlParams);
                PageRouter.openPageByUrl(context,assembleUrl, urlParams);
            }

        };

        FlutterBoost.BoostPluginsRegister pluginsRegister= new FlutterBoost.BoostPluginsRegister(){

            @Override
            public void registerPlugins(PluginRegistry mRegistry) {
                GeneratedPluginRegistrant.registerWith(mRegistry);
                TextPlatformViewPlugin.register(mRegistry.registrarFor("TextPlatformViewPlugin"));
            }
        };

        Platform platform= new FlutterBoost
                .ConfigBuilder(this,router)
                .isDebug(true)
                .whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
                .renderMode(FlutterView.RenderMode.texture)
                .pluginsRegister(pluginsRegister)
                .build();

        FlutterBoost.instance().init(platform);



    }
}

4、native打开native页面

context.startActivity(new Intent(context, NativePageActivity.class));
PageRouter.java

   

        String path = url.split("\\?")[0];

        Log.i("openPageByUrl","PageRouter openPageByUrl" + path);
        try {
            if (pageName.containsKey(path)) {
                Intent intent = BoostFlutterActivity.withNewEngine().url(pageName.get(path)).params(params)
                        .backgroundMode(BoostFlutterActivity.BackgroundMode.opaque).build(context);
                if(context instanceof Activity){
                    Activity activity=(Activity)context;
                    activity.startActivityForResult(intent,requestCode);
                }else{
                    context.startActivity(intent);
                }
                return true;
            } else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) {
                context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));
                return true;
            } else if (url.startsWith(NATIVE_PAGE_URL)) {
                context.startActivity(new Intent(context, NativePageActivity.class));
                return true;
            }

            return false;

        } catch (Throwable t) {
            return false;
        }
    }
 

5、打开flutter fragment

PageRouter.java


                context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));

底部有四个Tab,click事件打开FlutterFragment,
默认onResume 打开第一个tab

FlutterFragmentPageActivity.java


    @Override
    public void onClick(View v) {

        mTab1.setBackgroundColor(Color.WHITE);
        mTab2.setBackgroundColor(Color.WHITE);
        mTab3.setBackgroundColor(Color.WHITE);
        mTab4.setBackgroundColor(Color.WHITE);

        if(mTab1 == v) {
            mTab1.setBackgroundColor(Color.YELLOW);

            mFragment= new FlutterFragment.NewEngineFragmentBuilder().url("flutterFragment").build();

        }else if(mTab2 == v) {
            mTab2.setBackgroundColor(Color.YELLOW);
            mFragment= new FlutterFragment.NewEngineFragmentBuilder().url("flutterFragment").build();
        }else if(mTab3 == v) {
            mTab3.setBackgroundColor(Color.YELLOW);
            mFragment= new FlutterFragment.NewEngineFragmentBuilder().url("flutterFragment").build();
        }else{
            mTab4.setBackgroundColor(Color.YELLOW);
            mFragment= new FlutterFragment.NewEngineFragmentBuilder().url("flutterFragment").build();
        }

        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.fragment_stub,mFragment)
                .commit();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mTab1.performClick();
    }

NewEngineFragmentBuilder 配置url flutterFragment 生成FlutterFragment

public class FlutterFragment extends Fragment implements FlutterActivityAndFragmentDelegate.Host  {

    
        @NonNull
        protected Bundle createArgs() {
            Bundle args = new Bundle();

            // TODO(mattcarroll): determine if we should have an explicit FlutterTestFragment instead of conflating.
            if (null != shellArgs) {
                args.putStringArray(ARG_FLUTTER_INITIALIZATION_ARGS, shellArgs.toArray());
            }

            BoostFlutterActivity.SerializableMap serializableMap = new BoostFlutterActivity.SerializableMap();
            serializableMap.setMap(params);

            args.putString(EXTRA_URL, url);
            args.putSerializable(EXTRA_PARAMS, serializableMap);
            args.putString(ARG_FLUTTERVIEW_RENDER_MODE, renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name());
            args.putString(ARG_FLUTTERVIEW_TRANSPARENCY_MODE, transparencyMode != null ? transparencyMode.name() : FlutterView.TransparencyMode.transparent.name());
            args.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, true);


            return args;
        }

        /**
         * Constructs a new {@code NewFlutterFragment} (or a subclass) that is configured based on
         * properties set on this {@code Builder}.
         */
        @NonNull
        public <T extends FlutterFragment> T build() {
            try {
                @SuppressWarnings("unchecked")
                T frag = (T) fragmentClass.getDeclaredConstructor().newInstance();
                if (frag == null) {
                    throw new RuntimeException("The NewFlutterFragment subclass sent in the constructor ("
                            + fragmentClass.getCanonicalName() + ") does not match the expected return type.");
                }

                Bundle args = createArgs();
                frag.setArguments(args);

                return frag;
            } catch (Exception e) {
                throw new RuntimeException("Could not instantiate NewFlutterFragment subclass (" + fragmentClass.getName() + ")", e);
            }
        }

FlutterFragment.java
FlutterFragment生命周期函数onAttach onCreateView onStart onResume,和FlutterActivityAndFragmentDelegate关联,
流程同打开native 页面

@Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        Log.d(TAG, "FlutterFragment onAttach");
        delegate = new FlutterActivityAndFragmentDelegate(this);
        delegate.onAttach(context);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "FlutterFragment onCreateView");
        return delegate.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG, "FlutterFragment onStart");
        delegate.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "FlutterFragment onResume");
        delegate.onResume();
    }

你可能感兴趣的:(flutter)