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
实现上面三个接口主要是创建视图,返回视图以及监听生命周期的回调。下面回到FlutterActivity
,FLutterActivityDelegate
后面再分析:
//创建委托类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
对象就行,因为传递给委托类FlutterActivityDelegate
的ViewFactory
并没有生成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
导航是通过MethodChannel
与Flutter
进行通信,最终交由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.dart对defaultName更进一步的说明:
/// 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';
注释的意思如果没有特定的路由,默认是/和Android和IOS如何设置该值方式和时机,再回到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);
}
}
这是用于Flutter
和Native
之间交换数据的接口类,已知FlutterView
已经实现了SurfaceView
,而FlutterNativeView
负责FlutterView
和Flutter
之间的通讯,再使用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);
}
}
可以看到最后通过FlutterView
的runFromBundle()
执行。
7.runFromBundle
public void runFromBundle(FlutterRunArguments args) {
this.assertAttached();
this.preRun();
this.mNativeView.runFromBundle(args);
this.postRun();
}
调用FlutterNativeView
的runFromBundle
方法:
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全方面面试资料)
网友评论