Android进阶之路Android开发经验谈Android开发

Flutter之源码分析

2019-08-26  本文已影响12人  2c3d4f7ba0d4

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,另外还实现了三个接口:

这个接口只有一个方法:

    public interface Provider {
        FlutterView getFlutterView();
    }

只是返回当前Activity中的FlutterView

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);
    }
}
    //视图工厂
    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);
            }

        }
    }

上面的步骤就是:

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配置寻找路由顺序:

  /// {@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);
    }

最后调用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全方面面试资料)

上一篇下一篇

猜你喜欢

热点阅读