美文网首页
Flutter V0.154 Android 插件解析

Flutter V0.154 Android 插件解析

作者: lizubing1992 | 来源:发表于2019-11-12 17:44 被阅读0次

    1. Flutter Page和Android Activity/Fragment 生命周期同步

    这个类的主要作用就是同步activity 和Flutter的生命周期

        @Override
        public void onCreate() {
            //....
            mState = STATE_CREATED;
            mContainer.getBoostFlutterView().onResume();
            mProxy.create();
        }
    
        @Override
        public void onAppear() {
             //....
            mState = STATE_APPEAR;
            mManager.pushRecord(this);
            mContainer.getBoostFlutterView().onAttach();
            mProxy.appear();
        }
    
        @Override
        public void onDisappear() {
             //....
            mState = STATE_DISAPPEAR;
            mProxy.disappear();
            if(getContainer().getContextActivity().isFinishing()) {
                mProxy.destroy();
            }
            mContainer.getBoostFlutterView().onDetach();
            mManager.popRecord(this);
        }
    
        @Override
        public void onDestroy() {
             //....
            mState = STATE_DESTROYED;
            mProxy.destroy();
            mContainer.getBoostFlutterView().onDestroy();
            mManager.removeRecord(this);
            mManager.setContainerResult(this,-1,-1,null);
            if (!mManager.hasContainerAppear()) {
                mContainer.getBoostFlutterView().onPause();
                mContainer.getBoostFlutterView().onStop();
            }
        }
    
        //....其他的生命周期
    

    同步的生命周期主要有onAppear/onDisappear/onDestroy 等

    还有一个就是methodProxy 通信代理类,告知flutter页面的生命周期的回调

    private class MethodChannelProxy {
            private int mState = STATE_UNKNOW;
            private void create() {
                if (mState == STATE_UNKNOW) {
                    invokeChannelUnsafe("didInitPageContainer",
                            mContainer.getContainerUrl(),
                            mContainer.getContainerUrlParams(),
                            mUniqueId
                    );
                    mState = STATE_CREATED;
                }
            }
             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.singleton().channel().invokeMethodUnsafe(method, args);
            }
        }
           //其他页面生命周期的回调......
        public static String genUniqueId(Object obj) {
            return System.currentTimeMillis() + "-" + obj.hashCode();
        }
    

    之后总体会调用到BoostChannel类中的invokeMethodUnsafe/invokeMethod方法中

     public void invokeMethodUnsafe(final String name,Serializable args){
            invokeMethod(name, args, new MethodChannel.Result() {
                @Override
                public void success(@Nullable Object o) {
                    //every thing ok...
                }
                @Override
                public void error(String s, @Nullable String s1, @Nullable Object o) {
                    Debuger.log("invoke method "+name+" error:"+s+" | "+s1);
                }
                @Override
                public void notImplemented() {
                    Debuger.log("invoke method "+name+" notImplemented");
                }
            });
        }
    

    对应的APP整体的声明周期回调是通过Application.ActivityLifecycleCallbacks 这个回调函数来确认的

    FlutterBoost构造函数注册了这个回调函数

    具体代码如下

     class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
            @Override
            public void onActivityStarted(Activity activity) {
                if (mCurrentActiveActivity == null) {
                    if (mEngineProvider.tryGetEngine() != null) {
                        HashMap<String, String> map = new HashMap<>();
                        map.put("type", "foreground");
                        channel().sendEvent("lifecycle",map);
                    }
                }
                mCurrentActiveActivity = activity;
            }
            //....其他APP生命周期回调
        }
    

    通过上面的invokeMethod会通过Channel调用到Flutter对应的boost_channel.dart对应的方法中

    typedef Future<dynamic> EventListener(String name, Map arguments);
    typedef Future<dynamic> MethodHandler(MethodCall call);
    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) {
                //App生命周期 循环调用给回调函数
                l(name, arg);
              }
            }
          }else{
            for(MethodHandler handler in _methodHandlers) {
            //页面Page生命周期 循环调用给回调函数
              handler(call);
            }
          }
          return Future.value();
        });
      }
     }
    

    执行回调是FlutterBoost的构造函数调用ContainerCoordinator(_boostChannel)之后进入到了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> _onChannelEvent(dynamic event) {
        if (event is Map) {
          Map map = event;
          final String type = map['type'];
          switch (type) {
            case 'foreground':
              {
                FlutterBoost.containerManager?.setForeground();
              }
              break;
              //....其他App生命周期回调处理
          }
        }
      }
      
       Future<dynamic> _onMethodCall(MethodCall call) {
        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;
             //....其他页面生命周期回调处理
            }
      }
      
    

    2.Flutter引擎复用逻辑

    主要是体现在XFlutterView 的attachToFlutterEngine和detachFromFlutterEngine方法中

     public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        Log.d(TAG, "attachToFlutterEngine()");
        if (isAttachedToFlutterEngine()) {
          if (flutterEngine == this.flutterEngine) {
            // 相同 复用之前的引擎
            return;
          }
          // 不同 移除之前的引擎
          detachFromFlutterEngine();
        }
        //重新赋值
        this.flutterEngine = flutterEngine;
    
        // 设置渲染层
        this.flutterEngine.getRenderer().attachToRenderSurface(renderSurface);
    
        // 重设输入输出
        textInputPlugin = new TextInputPlugin(
            this,
            this.flutterEngine.getDartExecutor()
        );
        //android 的键盘处理
        androidKeyProcessor = new AndroidKeyProcessor(
            this.flutterEngine.getKeyEventChannel(),
            textInputPlugin
        );
        //触摸处理
        androidTouchProcessor = new AndroidTouchProcessor(this.flutterEngine.getRenderer());
        //辅助连接桥
        accessibilityBridge = new AccessibilityBridge(
            this,
            flutterEngine.getAccessibilityChannel(),
            (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE),
            getContext().getContentResolver(),
            // TODO(mattcaroll): plumb the platform views controller to the accessibility bridge.
            // https://github.com/flutter/flutter/issues/29618
            null
        );
        
        accessibilityBridge.setOnAccessibilityChangeListener(onAccessibilityChangeListener);
        resetWillNotDraw(
            accessibilityBridge.isAccessibilityEnabled(),
            accessibilityBridge.isTouchExplorationEnabled()
        );
    
       //重启输入连接
        textInputPlugin.getInputMethodManager().restartInput(this);
        //一系列初始化
        // Push View and Context related information from Android to Flutter.
        sendUserSettingsToFlutter();
        sendLocalesToFlutter(getResources().getConfiguration());
        sendViewportMetricsToFlutter();
      }
      
      
      public void detachFromFlutterEngine() {
        if (!isAttachedToFlutterEngine()) {
          return;
        }
    
        //重启输入连接
        textInputPlugin.getInputMethodManager().restartInput(this);
    
        // 移除渲染层
        flutterEngine.getRenderer().detachFromRenderSurface();
        flutterEngine = null;
      }
    

    引擎相同则复用,不同detach 之前,重新赋值以及初始化相关的配置

    3.打开Flutter页面的主要逻辑

    调用链 PageRouter.openPageByUrl -->BoostFlutterEngine.startRun -->BoostFlutterActivity.onCreate -->createFlutterView(mFlutterEngine)

    BoostFlutterEngine.startRun

    BoostFlutterEngine.startRun这个方法的启动主要是在Application 配置的启动的方式来决定的

        int IMMEDIATELY = 0;          //立即启动引擎
        int ANY_ACTIVITY_CREATED = 1; //当有任何Activity创建时,启动引擎
    
        @Override
        public int whenEngineStart() {
            return ANY_ACTIVITY_CREATED;
        }
    

    默认使用这个ANY_ACTIVITY_CREATED 的时候,会在ActivityLifecycleCallbacks回调函数中做处理

      class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                if (platform().whenEngineStart() == IPlatform.ANY_ACTIVITY_CREATED) {
                    sInstance.mEngineProvider
                            .provideEngine(activity)
                            .startRun(activity);
                }
            }
        }
    

    BoostFlutterActivity.onCreate

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            configureWindowForTransparency();
            //创建同步器
            mSyncer = FlutterBoost.singleton().containerManager().generateSyncer(this);
            //创建引擎
            mFlutterEngine = createFlutterEngine();
            //创建FlutterView
            mFlutterView = createFlutterView(mFlutterEngine);
            setContentView(mFlutterView);
            //同步器初始化
            mSyncer.onCreate();
            //配置状态栏
            configureStatusBarForFullscreenFlutterExperience();
        }
    

    同步器就是前面讲的ContainerRecord,主要是同步Flutter和Android的页面和APP状态

    FlutterEngine,这个是Flutter的核心,flutter_boost对其做了进一步的封装

    FlutterView 主要是展示Flutter中的Widget页面

    4.FlutterEngine 封装

    主要是修改DartExecutor.DartEntrypoint和 InitRoute 以及对应的插件注册

     public BoostFlutterEngine(@NonNull Context context, DartExecutor.DartEntrypoint entrypoint, String initRoute) {
            super(context);
            mContext = context.getApplicationContext();
            mBoostPluginRegistry = new BoostPluginRegistry(this, context);
            //支持用户的修改的进入点 一般对应的main
            if (entrypoint != null) {
                mEntrypoint = entrypoint;
            } else {
                mEntrypoint = defaultDartEntrypoint(context);
            }
            //初始化路由
            if (initRoute != null) {
                mInitRoute = initRoute;
            } else {
                mInitRoute = defaultInitialRoute(context);
            }
            //获取FlutterJNI用于引擎通信相关的
            FlutterJNI flutterJNI = null;
            try {
                Field field = FlutterEngine.class.getDeclaredField("flutterJNI");
                field.setAccessible(true);
    
                flutterJNI = (FlutterJNI) field.get(this);
            } catch (Throwable t) {
                try {
                    for(Field field:FlutterEngine.class.getDeclaredFields()) {
                        field.setAccessible(true);
                        Object o = field.get(this);
    
                        if(o instanceof FlutterJNI) {
                            flutterJNI = (FlutterJNI)o;
                        }
                    }
    
                    if(flutterJNI == null) {
                        throw new RuntimeException("FlutterJNI not found");
                    }
                }catch (Throwable it){
                    Debuger.exception(it);
                }
            }
            mFakeRender = new FakeRender(flutterJNI);
        }
    

    BoostRegistrar 插件注册主要是获取Activity,让Container 和Activity同步

            @Override
            public Activity activity() {
                Activity activity;
                IContainerRecord record;
                //获取当前的Container
                record = FlutterBoost.singleton().containerManager().getCurrentTopRecord();
                if (record == null) {
                    //获取最后生成Container
                    record = FlutterBoost.singleton().containerManager().getLastGenerateRecord();
                }
                if (record == null) {
                    activity = FlutterBoost.singleton().currentActivity();
                } else {
                    activity = record.getContainer().getContextActivity();
                }
                if (activity == null && mCurrentActivityRef != null) {
                    activity = mCurrentActivityRef.get();
                }
                if (activity == null) {
                    throw new RuntimeException("current has no valid Activity yet");
                }
                return activity;
    

    5.BoostFlutterView封装View

    BoostFlutterView主要是封装各种Flutter需要加载的东西

      private void init() {
            //创建引擎
            if (mFlutterEngine == null) {
                mFlutterEngine = createFlutterEngine(getContext());
            }
            //activity传递的参数
            if (mArguments == null) {
                mArguments = new Bundle();
            }
            //FlutterBoost平台自身需要的参数
            mPlatformPlugin = new PlatformPlugin((Activity) getContext(), mFlutterEngine.getPlatformChannel());
            //封装的XFlutterView
            mFlutterView = new XFlutterView(getContext(), getRenderMode(), getTransparencyMode());
            //添加控件
            addView(mFlutterView, new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            //截屏View
            mSnapshot = new SnapshotView(getContext());
            //Flutter引擎初始化loading
            if(mRenderingProgressCoverCreator != null) {
                mRenderingProgressCover = mRenderingProgressCoverCreator
                        .createRenderingProgressCover(getContext());
            }else{
                mRenderingProgressCover = createRenderingProgressCorver();
            }
            //添加loading
            if(mRenderingProgressCover != null) {
                addView(mRenderingProgressCover, new FrameLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            }
            //监听第一帧绘制回调函数
            mFlutterView.addOnFirstFrameRenderedListener(mOnFirstFrameRenderedListener);
            //启动封装引擎
            mFlutterEngine.startRun((Activity)getContext());
    
            final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
            if(stateListener != null) {
                stateListener.onFlutterViewInited(mFlutterEngine,this);
            }
            checkAssert();
        }
    

    默认的createRenderingProgressCorver返回的是一个ProgressBar 用户可以根据重写这个方法自己修改loading界面

    结语

    还有一些相关的类 XAndroidKeyProcessor(按键处理)/XInputConnectionAdaptor(输入输出适配)/XTextInputPlugin(输入插件)。总体来讲,flutter_boost的Android版本插件难度不是很大,Flutter Page/App生命周期同步以及引擎封装思路还是不错的,可以像WebView一样的使用是该插件的初衷。以后有时间还有进一步的解读源码。

    相关文章

      网友评论

          本文标题:Flutter V0.154 Android 插件解析

          本文链接:https://www.haomeiwen.com/subject/ifvqictx.html