Flutter之源码分析

作者: 2c3d4f7ba0d4 | 来源:发表于2019-08-26 16:08 被阅读12次

    Flutter自从1.0版本发布,现在越来越受欢迎,很多公司都在研究或者用在项目上。今天实践一下Android原生项目如何嵌套Flutter页面,具体原理就是Flutter作为Android Module出现在项目中,这样就可以在已有的项目中使用,Android项目也是一个工程,Flutter项目也是一个工程,这样就互不相关,也很好进行管理。废话不多说,开始实践。

    1. FlutterActivity

    Android原生调用Flutter页面之前,先知道FlutterActivity这个类,在创建的FlutterModule.android->app->flutter_module->host下有个MainActivity,这个类是继承FlutterActivity类,在AndroidManifest.xml下并且配置了这个启动界面,也就是说当原生Android调用Flutter时,该类是Flutter项目的页面入口。那么下面看看这个类的源码,到底做了什么?

    可以发现它继承了Activity,也就是它还是普通的Activity,另外还实现了三个接口:

    • Provider

    这个接口只有一个方法:

        public interface Provider {
            FlutterView getFlutterView();
        }
    

    只是返回当前Activity中的FlutterView

    • PluginRegistry
    public interface PluginRegistry {
        //注册插件
        PluginRegistry.Registrar registrarFor(String var1);
        //是否有这个插件
        boolean hasPlugin(String var1);
        //插件发布值
        <T> T valuePublishedByPlugin(String var1);
        //为插件注册生命回调
        public interface PluginRegistrantCallback {
            void registerWith(PluginRegistry var1);
        }
        //视图销毁监听
        public interface ViewDestroyListener {
            boolean onViewDestroy(FlutterNativeView var1);
        }
        //用户手动离开当前activity监听,如主动切换任何,按back健
        //系统自动切换应用不会调用此方法,如来电,灭屏
        public interface UserLeaveHintListener {
            void onUserLeaveHint();
        }
        //监听Activity是否执行onNewIntent的回调
        public interface NewIntentListener {
            boolean onNewIntent(Intent var1);
        }
        //监听Activity是否执行onActivityResult
        public interface ActivityResultListener {
            boolean onActivityResult(int var1, int var2, Intent var3);
        }
        //监听Activity是否请求权限的回调
        public interface RequestPermissionsResultListener {
            boolean onRequestPermissionsResult(int var1, String[] var2, int[] var3);
        }
    
        //插件的注册者
        public interface Registrar {
            //插件宿主的activity
            Activity activity();
            //插件的上下文 Application Context
            Context context();
            //这是当前Activity的context
            Context activeContext();
            //信使 主要用来注册Platform channels
            BinaryMessenger messenger();
            //返回TextureRegistry 可以拿到SurfaceTexture
            TextureRegistry textures();
            //返回PlatformViewRegistry
            PlatformViewRegistry platformViewRegistry();
            //返回FlutterView
            FlutterView view();
            //根据key来寻找资源
            String lookupKeyForAsset(String var1);
            //同理根据key来寻找资源
            String lookupKeyForAsset(String var1, String var2);
            //发布值
            PluginRegistry.Registrar publish(Object var1);
            //增加回调
            PluginRegistry.Registrar addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener var1);
            //增加回调
            PluginRegistry.Registrar addActivityResultListener(PluginRegistry.ActivityResultListener var1);
            //增加回调newIntent回调
            PluginRegistry.Registrar addNewIntentListener(PluginRegistry.NewIntentListener var1);
            //增加回调
            PluginRegistry.Registrar addUserLeaveHintListener(PluginRegistry.UserLeaveHintListener var1);
            //增加回调视图销毁
            PluginRegistry.Registrar addViewDestroyListener(PluginRegistry.ViewDestroyListener var1);
        }
    }
    
    • ViewFactory
        //视图工厂
        public interface ViewFactory {
            //创建FlutterView
            FlutterView createFlutterView(Context var1);
            //创建FlutterNativeView
            FlutterNativeView createFlutterNativeView();
            //是否保留FlutterNativeView
            boolean retainFlutterNativeView();
        }
    

    也就是FlutterActivity实现上面三个接口主要是创建视图,返回视图以及监听生命周期的回调。下面回到FlutterActivityFLutterActivityDelegate后面再分析:

        //创建委托类FlutterActivityDelegate对象
        private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
        private final FlutterActivityEvents eventDelegate;
        private final Provider viewProvider;
        private final PluginRegistry pluginRegistry;
        //构造函数
        public FlutterActivity() {
            //FlutterActivityDelegate实现了FlutterActivityEvents,Provider,PluginRegistry 赋值对应的变量,调用更加清晰
            this.eventDelegate = this.delegate;
            this.viewProvider = this.delegate;
            this.pluginRegistry = this.delegate;
        }
    

    并且Activity的生命周期函数都是由FlutterActivityEvents对象来执行:

      protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.eventDelegate.onCreate(savedInstanceState);
        }
    
        protected void onStart() {
            super.onStart();
            this.eventDelegate.onStart();
        }
    
        protected void onResume() {
            super.onResume();
            this.eventDelegate.onResume();
        }
    
        protected void onDestroy() {
            this.eventDelegate.onDestroy();
            super.onDestroy();
        }
    
        public void onBackPressed() {
            if (!this.eventDelegate.onBackPressed()) {
                super.onBackPressed();
            }
    
        }
    
        protected void onStop() {
            this.eventDelegate.onStop();
            super.onStop();
        }
    
        protected void onPause() {
            super.onPause();
            this.eventDelegate.onPause();
        }
    
        protected void onPostResume() {
            super.onPostResume();
            this.eventDelegate.onPostResume();
        }
    
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            this.eventDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (!this.eventDelegate.onActivityResult(requestCode, resultCode, data)) {
                super.onActivityResult(requestCode, resultCode, data);
            }
    
        }
    
        protected void onNewIntent(Intent intent) {
            this.eventDelegate.onNewIntent(intent);
        }
    
        public void onUserLeaveHint() {
            this.eventDelegate.onUserLeaveHint();
        }
    
        public void onTrimMemory(int level) {
            this.eventDelegate.onTrimMemory(level);
        }
    
        public void onLowMemory() {
            this.eventDelegate.onLowMemory();
        }
    
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            this.eventDelegate.onConfigurationChanged(newConfig);
        }
    

    下面看看创建FlutterView以及返回FlutterView的方法:

        public FlutterView getFlutterView() {
            //通过FlutterActivityDelegate委托执行
            return this.viewProvider.getFlutterView();
        }
        //子类实现 返回null
        public FlutterView createFlutterView(Context context) {
            return null;
        }
        //子类实现 返回null
        public FlutterNativeView createFlutterNativeView() {
            return null;
        }
    

    插件管理的方法实现:

        public final boolean hasPlugin(String key) {
            //也是通过FlutterActivityDelegate委托执行
            return this.pluginRegistry.hasPlugin(key);
        }
    
        public final <T> T valuePublishedByPlugin(String pluginKey) {
            return this.pluginRegistry.valuePublishedByPlugin(pluginKey);
        }
    
        public final Registrar registrarFor(String pluginKey) {
            return this.pluginRegistry.registrarFor(pluginKey);
        }
    

    那么这里很清晰地知道FlutterActivity的生命周期各个方法实际由FlutterActivityDelegate代理执行,并且知道FlutterActivity通过委托代理的方式解决来生命周期的回调,插件管理和FlutterView的创建,是Android原生调Flutter页面的中间桥梁。

    2. FlutterActivityDelegate

    经过上面的分析,FlutterActivityDelegate作为委托的角色存在,下面更进一步地去深入:

        public FlutterActivityDelegate(Activity activity, FlutterActivityDelegate.ViewFactory viewFactory) {
            this.activity = (Activity)Preconditions.checkNotNull(activity);
            this.viewFactory = (FlutterActivityDelegate.ViewFactory)Preconditions.checkNotNull(viewFactory);
        }
    

    FlutterActivityDelegate构造函数需要传入Activity对象和FlutterActivityDelegate.ViewFactory,其实重点看Activity对象就行,因为传递给委托类FlutterActivityDelegateViewFactory并没有生成FlutterView,恰好相反,FlutterView是通过传递进来的Activity来生成的。在FlutterActivityDelegate类源码可以看到,定义类和Activity同名的函数,如:onCreate,onPause,onStart,onResume。在FlutterActivity中调用这个委托类同名函数,因此得出Flutter页面是由该委托类处理的。下面具体看一下onCreate方法:

        public void onCreate(Bundle savedInstanceState) {
            if (VERSION.SDK_INT >= 21) {
                Window window = this.activity.getWindow();
                window.addFlags(-2147483648);
                window.setStatusBarColor(1073741824);
                window.getDecorView().setSystemUiVisibility(1280);
            }
            //获取启动参数
            String[] args = getArgsFromIntent(this.activity.getIntent());
            //保证FlutterMain初始化完成
            FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
            //注意这里,在FlutterActivity默认返回null的
            this.flutterView = this.viewFactory.createFlutterView(this.activity);
            //所以会走到这里
            if (this.flutterView == null) {
                //这里也是创建类空FlutterNativeView
                FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
                //这里才是实际创建了FlutterView
                this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
                //设置布局参数,添加到当前activity,作为主视图
                this.flutterView.setLayoutParams(matchParent);
                this.activity.setContentView(this.flutterView);
                //创建启动ui
                this.launchView = this.createLaunchView();
                if (this.launchView != null) {
                    this.addLaunchView();
                }
            }
            //根据activity获取intent中传递的路由值
            if (!this.loadIntent(this.activity.getIntent())) {
                //获取路由值 去跳转flutter项目设定的route对应页面
                //查找bundle
                String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
                if (appBundlePath != null) {
                    this.runBundle(appBundlePath);
                }
    
            }
        }
    

    上面的步骤就是:

    • 根据当前系统版本来设置沉浸式状态栏;
    • 获取打开Activity时通过intent传入的参数信息;
    • 执行FlutterMain的ensureInitializationComplete方法;
    • 创建FlutterNativeView;
    • 根据FlutterNativeView创建FlutterView;
    • 将FlutterView设置为activity的内容视图;
    • 通过FlutterMain查找appBundle所在路径,并执行appBundle; 从上面可以得知,FlutterActivityDelegate这个类的onCreate方法主要是创建FlutterView并且设置到Activity上,然后通过loadIntent方法去读取intent中传递的路由值去跳转到Flutter项目中对应的页面去。

    3.FlutterView

    上面讲述道Activity会将FlutterView设置到setContView里,下面简单看看FlutterView源码:

    public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry
    

    看到FlutterView继承了SurfaceView,至于为什么要继承SurfaceView,因为SurfaceView使用的绘图线程不是UI线程,平时需要图形性能比较高的场景就得需要它了。

    public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry {
        private final NavigationChannel navigationChannel;//重点看这个
        private final KeyEventChannel keyEventChannel;
        private final LifecycleChannel lifecycleChannel;
        private final LocalizationChannel localizationChannel;
        //构造函数
        public FlutterView(Context context) {
            this(context, (AttributeSet)null);
        }
    
        public FlutterView(Context context, AttributeSet attrs) {
            this(context, attrs, (FlutterNativeView)null);
        }
    
        public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
            super(context, attrs);
            this.nextTextureId = new AtomicLong(0L);
            this.mIsSoftwareRenderingEnabled = false;
            this.onAccessibilityChangeListener = new OnAccessibilityChangeListener() {
                public void onAccessibilityChanged(boolean isAccessibilityEnabled, boolean isTouchExplorationEnabled) {
                    FlutterView.this.resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
                }
            };
            Activity activity = getActivity(this.getContext());
            if (activity == null) {
                throw new IllegalArgumentException("Bad context");
            } else {
                //如果传递的FlutterNativeView是空
                if (nativeView == null) {
                    //重新创建默认的FlutterNativeView
                    this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
                } else {
                    this.mNativeView = nativeView;
                }
    
                this.dartExecutor = this.mNativeView.getDartExecutor();
                this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI());
                this.mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();
                //适配窗口变化,并在合适的时候更新mMetrics,设置到native中
                this.mMetrics = new FlutterView.ViewportMetrics();
                this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
    
            }
        }
    }
    

    下面重点观察NavigationChannel这个导航Channel:

    public class NavigationChannel {
        @NonNull
        public final MethodChannel channel;
    
        public NavigationChannel(@NonNull DartExecutor dartExecutor) {
            //创建MethodChannel
            this.channel = new MethodChannel(dartExecutor, "flutter/navigation", JSONMethodCodec.INSTANCE);
        }
        //设置初始路由
        public void setInitialRoute(String initialRoute) {
            this.channel.invokeMethod("setInitialRoute", initialRoute);
        }
        //将指定路由压入栈
        public void pushRoute(String route) {
            this.channel.invokeMethod("pushRoute", route);
        }
        //将指定路由弹出栈
        public void popRoute() {
            this.channel.invokeMethod("popRoute", (Object)null);
        }
        //设置MethodCallHandler
        public void setMethodCallHandler(@Nullable MethodCallHandler handler) {
            this.channel.setMethodCallHandler(handler);
        }
    }
    

    也就是说FlutterView导航是通过MethodChannelFlutter进行通信,最终交由Flutter处理。做个插件都知道,在Flutter肯定存在MethodChannel('flutter/navigation',JSONMethodCodec),在ststem_channels.dart中找到:

      /// A JSON [MethodChannel] for navigation.
      ///
      /// The following incoming methods are defined for this channel (registered
      /// using [MethodChannel.setMethodCallHandler]):
      ///
      ///  * `popRoute`, which is called when the system wants the current route to
      ///    be removed (e.g. if the user hits a system-level back button).
      ///
      ///  * `pushRoute`, which is called with a single string argument when the
      ///    operating system instructs the application to open a particular page.
      ///
      /// See also:
      ///
      ///  * [WidgetsBindingObserver.didPopRoute] and
      ///    [WidgetsBindingObserver.didPushRoute], which expose this channel's
      ///    methods.
      static const MethodChannel navigation = MethodChannel(
          'flutter/navigation',
          JSONMethodCodec(),
      );
    

    并且在widgets/binding.dart找到对应实现:

      Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
        switch (methodCall.method) {
          case 'popRoute':
            //压入栈
            return handlePopRoute();
          case 'pushRoute':
            //出栈
            return handlePushRoute(methodCall.arguments);
        }
        return Future<dynamic>.value();
      }
    

    但是没有看到setInitialRoute处理,那么在哪里会用到呢?在app.dart下:

     /// The [MaterialApp] configures the top-level [Navigator] to search for routes
     /// in the following order:
     ///
     ///  1\. For the `/` route, the [home] property, if non-null, is used.
     ///
     ///  2\. Otherwise, the [routes] table is used, if it has an entry for the route.
     ///
     ///  3\. Otherwise, [onGenerateRoute] is called, if provided. It should return a
     ///     non-null value for any _valid_ route not handled by [home] and [routes].
     ///
     ///  4\. Finally if all else fails [onUnknownRoute] is called.
     ///
     /// If a [Navigator] is created, at least one of these options must handle the
     /// `/` route, since it is used when an invalid [initialRoute] is specified on
     /// startup (e.g. by another application launching this one with an intent on
     /// Android; see [Window.defaultRouteName]).
     ///
     /// This widget also configures the observer of the top-level [Navigator] (if
     /// any) to perform [Hero] animations.
     ///
     /// If [home], [routes], [onGenerateRoute], and [onUnknownRoute] are all null,
     /// and [builder] is not null, then no [Navigator] is created.
     /// {@macro flutter.widgets.widgetsApp.initialRoute}
      final String initialRoute;
    

    上面说明了Natvigator配置寻找路由顺序:

    • 1.对于"/"路由,如果[home]属性不为空,则会使用
    • 2.否则,将会使用路由表(如果有路由条目)
    • 3.否则,将会调用[onGenerateRoute]提供一个有效没有被[home]和[routes]处理的路由
    • 4.最后,如果前面寻找失败,则调用[onUnknownRoute] 再查看widgetsApp下具体说明:
      /// {@template flutter.widgets.widgetsApp.initialRoute}
      /// The name of the first route to show, if a [Navigator] is built.
      ///
      /// Defaults to [Window.defaultRouteName], which may be overridden by the code
      /// that launched the application.
      ///
      /// If the route contains slashes, then it is treated as a "deep link", and
      /// before this route is pushed, the routes leading to this one are pushed
      /// also. For example, if the route was `/a/b/c`, then the app would start
      /// with the three routes `/a`, `/a/b`, and `/a/b/c` loaded, in that order.
      ///
      /// If any part of this process fails to generate routes, then the
      /// [initialRoute] is ignored and [Navigator.defaultRouteName] is used instead
      /// (`/`). This can happen if the app is started with an intent that specifies
      /// a non-existent route.
      /// The [Navigator] is only built if routes are provided (either via [home],
      /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not,
      /// [initialRoute] must be null and [builder] must not be null.
      ///
      /// See also:
      ///
      ///  * [Navigator.initialRoute], which is used to implement this property.
      ///  * [Navigator.push], for pushing additional routes.
      ///  * [Navigator.pop], for removing a route from the stack.
      /// {@endtemplate}
      final String initialRoute;
    

    如果生成了[navigator],则initialRoute是第一个展示的默认路由,默认是Window.defaultRouteName,而在window.dartdefaultName更进一步的说明:

      /// The route or path that the embedder requested when the application was
      /// launched.
      ///
      /// This will be the string "`/`" if no particular route was requested.
      ///
      /// ## Android
      ///
      /// On Android, calling
      /// [`FlutterView.setInitialRoute`](/javadoc/io/flutter/view/FlutterView.html#setInitialRoute-java.lang.String-)
      /// will set this value. The value must be set sufficiently early, i.e. before
      /// the [runApp] call is executed in Dart, for this to have any effect on the
      /// framework. The `createFlutterView` method in your `FlutterActivity`
      /// subclass is a suitable time to set the value. The application's
      /// `AndroidManifest.xml` file must also be updated to have a suitable
      /// [`<intent-filter>`](https://developer.android.com/guide/topics/manifest/intent-filter-element.html).
      ///
      /// ## iOS
      ///
      /// On iOS, calling
      /// [`FlutterViewController.setInitialRoute`](/objcdoc/Classes/FlutterViewController.html#/c:objc%28cs%29FlutterViewController%28im%29setInitialRoute:)
      /// will set this value. The value must be set sufficiently early, i.e. before
      /// the [runApp] call is executed in Dart, for this to have any effect on the
      /// framework. The `application:didFinishLaunchingWithOptions:` method is a
      /// suitable time to set this value.
      ///
      /// See also:
      ///
      ///  * [Navigator], a widget that handles routing.
      ///  * [SystemChannels.navigation], which handles subsequent navigation
      ///    requests from the embedder.
      String get defaultRouteName => _defaultRouteName();
      String _defaultRouteName() native 'Window_defaultRouteName';
    

    注释的意思如果没有特定的路由,默认是/AndroidIOS如何设置该值方式和时机,再回到FlutterView里:

        public void setInitialRoute(String route) {
            this.navigationChannel.setInitialRoute(route);
        }
    

    到这里,已经清楚Flutter如何接受native传递的路由参数过程了。就是通过FlutterView可以设置该路由值,在native创建FlutterView并且通过setInitialRoute方法设置route(window.defaultRouteName),而Flutter通过window.defaultRouteName从而知道native要跳转到Flutter项目的哪个页面。 再回到FlutterView的构造函数中,或者大家和我可能会有疑惑:为什么要创建FlutterNativeView呢?那下面简单看看FlutterNativeView的源码:

    4.FlutterNativeView

    public class FlutterNativeView implements BinaryMessenger {
        private static final String TAG = "FlutterNativeView";
        //插件管理
        private final FlutterPluginRegistry mPluginRegistry;
        private final DartExecutor dartExecutor;
        private FlutterView mFlutterView;
        private final FlutterJNI mFlutterJNI;
        private final Context mContext;
        private boolean applicationIsRunning;
    
        public FlutterNativeView(@NonNull Context context) {
            this(context, false);
        }
    
        public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
            this.mContext = context;
            this.mPluginRegistry = new FlutterPluginRegistry(this, context);
            //创建FlutterJNI
            this.mFlutterJNI = new FlutterJNI();
            this.mFlutterJNI.setRenderSurface(new FlutterNativeView.RenderSurfaceImpl());
            this.dartExecutor = new DartExecutor(this.mFlutterJNI);
            this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
            this.attach(this, isBackgroundView);
            this.assertAttached();
        }
    }
    

    可以看到FlutterNativeView实现了BinaryMessenger接口,根据其意思可以得知,这个BinaryMessenger是一个数据信息交流对象,接口声明如下:

    public interface BinaryMessenger {
        void send(String var1, ByteBuffer var2);
    
        void send(String var1, ByteBuffer var2, BinaryMessenger.BinaryReply var3);
    
        void setMessageHandler(String var1, BinaryMessenger.BinaryMessageHandler var2);
    
        public interface BinaryReply {
            void reply(ByteBuffer var1);
        }
    
        public interface BinaryMessageHandler {
            void onMessage(ByteBuffer var1, BinaryMessenger.BinaryReply var2);
        }
    }
    

    这是用于FlutterNative之间交换数据的接口类,已知FlutterView已经实现了SurfaceView,而FlutterNativeView负责FlutterViewFlutter之间的通讯,再使用Skia绘制页面。

    下面再看看FlutterJNI这个类:

    public class FlutterJNI {
        ...
        public FlutterJNI() {
        }
        private native void nativeDestroy(long var1);
    
        private native long nativeAttach(FlutterJNI var1, boolean var2);
            private static native void nativeDetach(long var0);
    
        private static native void nativeRunBundleAndSnapshot(long var0, String var2, String var3, String var4, boolean var5, AssetManager var6);
    
        private static native void nativeRunBundleAndSource(long var0, String var2, String var3, String var4);
    
        private static native void nativeSetAssetBundlePathOnUI(long var0, String var2);
    
        private static native String nativeGetObservatoryUri();
    
        private static native void nativeDispatchEmptyPlatformMessage(long var0, String var2, int var3);
    
        private static native void nativeDispatchPlatformMessage(long var0, String var2, ByteBuffer var3, int var4, int var5);
    }
    

    发现涉及到很多和native打交道的方法,可以知道NativeView显然是一个插件、消息的管理类,并与native打交道,那么和FlutterView的关系,显然一个负责展示,一个负责交互。

    5.loadIntent

    在上面分析FlutterActivity实现了getFlutterView方法,也分析到在FlutterActivityDelegate创建了FlutterView并添加到当前Activity中。当FlutterView被添加到Activity,那么Flutter怎么知道native打开哪个页面呢,其实是通过loadIntent这个方法来打开对应的页面,下面具体看看这个再FlutterActivityDelegate这个类里的loadIntent方法:

            //根据activity获取intent中传递的路由值
            if (!this.loadIntent(this.activity.getIntent())) {
                String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
                if (appBundlePath != null) {
                    this.runBundle(appBundlePath);
                }
    
            }
    
            .....
    
            private boolean loadIntent(Intent intent) {
            String action = intent.getAction();
            if ("android.intent.action.RUN".equals(action)) {
                String route = intent.getStringExtra("route");
                String appBundlePath = intent.getDataString();
                if (appBundlePath == null) {
                   //查找bundle
                    appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
                }
    
                if (route != null) {
                    //flutterView初始化,参数为路由
                    this.flutterView.setInitialRoute(route);
                }
    
                this.runBundle(appBundlePath);
                return true;
            } else {
                return false;
            }
        }
    
    

    6.runBundle

        //runBundle方法
        private void runBundle(String appBundlePath) {
        //第一次启动flutter页面isApplicationRunning()为false
        if (!this.flutterView.getFlutterNativeView().isApplicationRunning()) {
            FlutterRunArguments args = new FlutterRunArguments();
            ArrayList<String> bundlePaths = new ArrayList();
            //检查是否有flutter相关资源,这里用于动态更新
            ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
            if (resourceUpdater != null) {
                File patchFile = resourceUpdater.getInstalledPatch();
                JSONObject manifest = resourceUpdater.readManifest(patchFile);
                if (resourceUpdater.validateManifest(manifest)) {
                    bundlePaths.add(patchFile.getPath());
                }
            }
            //设置对应的运行参数
            bundlePaths.add(appBundlePath);
            args.bundlePaths = (String[])bundlePaths.toArray(new String[0]);
    
            args.entrypoint = "main";
            //通过flutterView.runFromBundle()来执行
            this.flutterView.runFromBundle(args);
        }
    
    }
    

    可以看到最后通过FlutterViewrunFromBundle()执行。

    7.runFromBundle

        public void runFromBundle(FlutterRunArguments args) {
            this.assertAttached();
            this.preRun();
            this.mNativeView.runFromBundle(args);
            this.postRun();
        }
    

    调用FlutterNativeViewrunFromBundle方法:

        public void runFromBundle(FlutterRunArguments args) {
            boolean hasBundlePaths = args.bundlePaths != null && args.bundlePaths.length != 0;
            if (args.bundlePath == null && !hasBundlePaths) {
                throw new AssertionError("Either bundlePath or bundlePaths must be specified");
            } else if ((args.bundlePath != null || args.defaultPath != null) && hasBundlePaths) {
                throw new AssertionError("Can't specify both bundlePath and bundlePaths");
            } else if (args.entrypoint == null) {
                throw new AssertionError("An entrypoint must be specified");
            } else {
                if (hasBundlePaths) {
                    this.runFromBundleInternal(args.bundlePaths, args.entrypoint, args.libraryPath);
                } else {
                    this.runFromBundleInternal(new String[]{args.bundlePath, args.defaultPath}, args.entrypoint, args.libraryPath);
                }
    
            }
        }
    

    当Bundle参数不为空的时候,调用runFromBundleInternal方法:

        private void runFromBundleInternal(String[] bundlePaths, String entrypoint, String libraryPath) {
            this.assertAttached();
            if (this.applicationIsRunning) {
                throw new AssertionError("This Flutter engine instance is already running an application");
            } else {
                this.mFlutterJNI.runBundleAndSnapshotFromLibrary(bundlePaths, entrypoint, libraryPath, this.mContext.getResources().getAssets());
                this.applicationIsRunning = true;
            }
        }
    

    最后通过FlutterJNI来调用JNI方法执行:

        @UiThread
        public void runBundleAndSnapshotFromLibrary(@NonNull String[] prioritizedBundlePaths, @Nullable String entrypointFunctionName, @Nullable String pathToEntrypointFunction, @NonNull AssetManager assetManager) {
            this.ensureAttachedToNative();
            this.nativeRunBundleAndSnapshotFromLibrary(this.nativePlatformViewId, prioritizedBundlePaths, entrypointFunctionName, pathToEntrypointFunction, assetManager);
        }
    
    • nativePlatformViewId 这是在FlutterView创建FlutterNativeView,FlutteNativeView调用FlutterJNI的natvieAttach传递给c++层,而从c++层返回,通过这个值来执行c++的一些方法。
    • prioritizedBundlePaths,数组中只有一个值类似/data/data/包名/flutter/flutter_assets/的路径值,这就是路由值。
    • entrypointFunctionName:这个值为main
    • pathToEntrypointFunction:这是null

    最后调用c++方法将main函数调起,之后就执行widget绑定,UI渲染等。这里发现nativeRunBundleAndSnapshotFromLibrary需要传四个参数。

    这里可以得出,只要打开FlutterActivity页面的时候,通过intent传入的key,如果这个值于Flutter项目定义的route值一样,就能跳到对应的页面。下面用一张图简单描述流程:

    也就是当原生打开Flutter页面的时候,其实还是跳转Activity,只不过这个Activity铺了FlutterView来显示,那下面具体实践。

    关注+加群:

    Android进阶技术交流 (895077617 )免费获取整理版的资料

    群里可以与大神一起交流并走出迷茫。新手可进群免费领取学习资料,看看前辈们是如何在编程的世界里傲然前行!有想学习Android Java的,或是转行,或是大学生,还有工作中想提升自己能力的,正在学习的小伙伴欢迎加入。(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,ViewPager,Bitmap,组件化架构,四大组件等深入学习视频资料以及Android、Java全方面面试资料)

    相关文章

      网友评论

        本文标题:Flutter之源码分析

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