前言
今天主要带大家一起分析下flutter是如何启动、初始化和加载dart代码的。这里有几点需要提前告知:
-
由于篇幅的问题,关于flutter界面创建、绘制过程将略过;
-
由于相关的c++代码比较多,而且较为复杂,建议先下载flutter engine的完整开发环境代码,阅读本文更方便;
-
本文只分析启动过程,参考的项目是基于android studio创建的一个默认flutter项目,以下简称demo。
(文章干货很长 请耐心看完 文末有福利!)
正文
java层启动过程
熟悉android的朋友都知道,一个APP启动会先执行Application再执行Activity(AndroidManifest.xml中配置的启动Activity),结合这个,我们先看看Application里做了什么,在分析过程中我们将挑取一些关键的native方法作为c++层入口方法作进一步的分析。
// io.flutter.app.FlutterApplication
public class FlutterApplication extends Application {
@Override
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}
//这块代码和FlutterActivityDelegate的生命周期方法结合使用
private Activity mCurrentActivity = null;
public Activity getCurrentActivity() {
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity) {
this.mCurrentActivity = mCurrentActivity;
}
}
// io.flutter.view.FlutterMain中的方法
public static void startInitialization(Context applicationContext, FlutterMain.Settings settings) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
} else if (sSettings == null) {
sSettings = settings;
long initStartTimestampMillis = SystemClock.uptimeMillis();
initConfig(applicationContext);
initAot(applicationContext);
initResources(applicationContext);
System.loadLibrary("flutter");
...
}
}
startInitialization
只能执行在主线程中,否则会抛出异常。通过sSettings
这个变量可以看出,启动的过程中,这个方法将只执行一遍。initConfig
初始化一些变量的配置信息(在AndroidManifest.xml中可以通过meta-data方式配置这些变量值), System.loadLibrary("flutter")
则完成装载flutter库文件,期间会在c++层完成JNI方法的动态注册。initResources
方法我们往下看。
private static void initResources(Context applicationContext) {
Context context = applicationContext;
new ResourceCleaner(context).start();
...
sResourceExtractor = new ResourceExtractor(context);
...
sResourceExtractor.start();
}
ResourceCleaner
将清理带有指定标识的缓存文件,ResourceExtractor
将完成asset 目录下flutter相关资源的拷贝,这些资源会在后续flutter engine和DartVM等初始化时使用。 然后我们再来看看启动activity都做了些什么
onCreate
//MainActivity.java
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
//FlutterActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.eventDelegate.onCreate(savedInstanceState);
}
先看FlutterActivity中执行onCreate,可以看到这里面并没有当前ContentView的设置,那么其内容界面是在哪里设置的呢,我们可以看到第二句this.eventDelegate.onCreate(savedInstanceState);
,最终我们发现Activity中显示的view是在代理类中进行初始化的,下面看下代理类FlutterActivityDelegate
的执行,
//FlutterActivityDelegate.java
public void onCreate(Bundle savedInstanceState) {
...
String[] args = getArgsFromIntent(this.activity.getIntent());
FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
this.flutterView = this.viewFactory.createFlutterView(this.activity);
if (this.flutterView == null) {
FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
this.flutterView.setLayoutParams(matchParent);
this.activity.setContentView(this.flutterView);
this.launchView = this.createLaunchView();
if (this.launchView != null) {
this.addLaunchView();
}
}
...
this.runBundle(appBundlePath);
...
}
在这里我们需要注意FlutterMain.ensureInitializationComplete的执行,
//FlutterMain.java
public static void ensureInitializationComplete(Context applicationContext, String[] args) {
...
sResourceExtractor.waitForCompletion();
...
nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);
sInitialized = true;
...
}
//c++关键方法1
private static native void nativeInit(Context var0, String[] var1, String var2, String var3, String var4);
它将等待解压任务结束,资源处理完毕,然后拼接参数,完成参数初始化后将执行nativeInit
方法对c++层初始化。
然后会创建FlutterView对象,这里面还包含了很多关键对象的创建,这个下文将会分析到。
//FlutterView.java的构造方法
public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
super(context, attrs);
...
if (nativeView == null) {
this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
} else {
this.mNativeView = nativeView;
}
this.mNativeView.getFlutterJNI();
this.mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();
...