Flutter启动流程源码分析

前言

相信大家在学习Flutter的开始阶段都看过Flutter的架构图,如下

我们知道Flutter的应用层代码由Dart编写,Framework层提供了一系列Widget和其它API,那么这些Dart编写的代码是如何在特定平台上执行的呢,这就要从Flutter的启动过程说起了,了解了Flutter的启动过程,这个问题便迎刃而解。

我们通过架构图可以看出Embedder是由特定的平台实现,它其实就是将Flutter移植到各平台的中间层代码。Embedder层是Flutter启动的关键,其在应用启动后,由平台原生模块通过调用该层的API执行一系列操作,比如渲染层体系的设置、相关线程的创建等,最主要的是通过Embedder层初始化Flutter Engine,Engine中会创建DartVM、各种服务协议的初始化、Platform Channels的初始化等等,而后就会在DartVM中执行dart编写的入口方法main方法。至此,Flutter模块就启动成功了。

flutter启动分析

安卓平台代码分析

安卓平台对应的Embedder层代码在engine源码的 /flutter/shell/platform/android/ 目录下。

我们来根据flutter create my_app命令创建的Flutter项目demo来分析。

flutter文件资源准备和库加载

首先,my_app应用启动会先执行FlutterApplication,我们来看下该类中的生命周期方法onCreate方法的实现

  • /flutter/shell/platform/android/io/flutter/app/FlutterApplication.java
@Override
@CallSuper
public void onCreate() {
    super.onCreate();
    FlutterMain.startInitialization(this);
}

FlutterMain类即是Embedder层的代码,该类的startInitialization方法实现如下

  • /flutter/shell/platform/android/io/flutter/view/FlutterMain.java
public static void startInitialization(Context applicationContext) {
    startInitialization(applicationContext, new Settings());
}

public static void startInitialization(Context applicationContext, Settings settings) {
    if (Looper.myLooper() != Looper.getMainLooper()) {
      throw new IllegalStateException("startInitialization must be called on the main thread");
    }
    // Do not run startInitialization more than once.
    if (sSettings != null) {
      return;
    }

    sSettings = settings;

    long initStartTimestampMillis = SystemClock.uptimeMillis();
    initConfig(applicationContext);
    initAot(applicationContext);
    initResources(applicationContext);
    System.loadLibrary("flutter");

    long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
    nativeRecordStartTimestamp(initTimeMillis);
}

由以上源码可知startInitialization方法需要在主线程中执行,该方法主要是初始化配置信息、初始化AOT模式下的变量(Debug下是JIT模式)、资源文件的初始化(主要是将asset目录下的flutter相关资源文件copy到私有目录下)等,最后会将以上初始化所用时间通过JNI方法传递到c++层做记录。

  • /flutter/shell/platform/android/flutter_main.cc
static void RecordStartTimestamp(JNIEnv* env,
                                 jclass jcaller,
                                 jlong initTimeMillis) {
  int64_t initTimeMicros =
      static_cast<int64_t>(initTimeMillis) * static_cast<int64_t>(1000);
  blink::engine_main_enter_ts = Dart_TimelineGetMicros() - initTimeMicros;
}

关键java类的UML类图

flutter运行时环境初始化

FlutterApplication执行完onCreate方法后会执行启动页面MainActivity的生命周期方法。我们发现MainActivity的onCreate方法中并没有通过setContentView来设置显示的视图,由于MainActivity继承了FlutterActivity并重载了父类的onCreate方法,所以我们看下FlutterActivity的onCreate方法

  • /flutter/shell/platform/android/io/flutter/app/FlutterActivity.java
private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
private final FlutterActivityEvents eventDelegate = delegate;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    eventDelegate.onCreate(savedInstanceState);
}

FlutterActivity继承自Activity,那么视图的设置我们推测应该是在FlutterActivityDelegate的onCreate方法中,我们看下它的实现

  • /flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
@Override
public void onCreate(Bundle savedInstanceState) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Window window = activity.getWindow();
        window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.setStatusBarColor(0x40000000);
        window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
    }

    String[] args = getArgsFromIntent(activity.getIntent());
    FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);

    flutterView = viewFactory.createFlutterView(activity);
    if (flutterView == null) {
        FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
        flutterView = new FlutterView(activity, null, nativeView);
        flutterView.setLayoutParams(matchParent);
        activity.setContentView(flutterView);
        launchView = createLaunchView();
        if (launchView != null) {
            addLaunchView();
        }
    }

    if (loadIntent(activity.getIntent())) {
        return;
    }

    String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext());
    if (appBundlePath != null) {
        runBundle(appBundlePath);
    }
}

我们发现代码中有一句activity.setContentView(flutterView);即为当前MainActivity设置显示视图,那么flutterView是如何创建的呢,我们分析该语句之前的代码。

  1. 首先根据当前系统版本来设置沉浸式状态栏;
  2. 获取打开Activity时通过intent传入的参数信息;
  3. 执行FlutterMain的ensureInitializationComplete方法;
  4. 创建FlutterNativeView;
  5. 根据FlutterNativeView创建FlutterView;
  6. 将FlutterView设置为activity的内容视图;
  7. 通过FlutterMain查找appBundle所在路径,并执行appBundle;

我们先来分析第3步骤执行FlutterMain的ensureInitializationComplete方法,先看一下具体实现

  • /flutter/shell/platform/android/io/flutter/view/FlutterMain.java
public static void ensureInitializationComplete(Context applicationContext, String[] args) {
    if (Looper.myLooper() != Looper.getMainLooper()) {
      throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
    }
    ...
    if (sInitialized) {
        return;
    }
    try {
        sResourceExtractor.waitForCompletion();

        List<String> shellArgs = new ArrayList<>();
        shellArgs.add("--icu-data-file-path=" + sIcuDataPath);
        ...
        
        String appBundlePath = findAppBundlePath(applicationContext);
        String appStoragePath = PathUtils.getFilesDir(applicationContext);
        String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
        nativeInit(applicationContext, shellArgs.toArray(new String[0]),
            appBundlePath, appStoragePath, engineCachesPath);

        sInitialized = true;
    } catch (Exception e) {
        Log.e(TAG, "Flutter initialization failed.", e);
        throw new RuntimeException(e);
    }
}

我们发现该方法也要求必须在主线程中执行,且只执行一次,一旦执行过会通过sInitialized变量来进行标识下次不再执行。try-catch代码块中第一句sResourceExtractor.waitForCompletion()表示要等待初始化时的资源初始化完毕后才会向下执行,否则会一直阻塞。下面会初始化一些参数配置信息、flutter打包出的appBundle路径、应用存储目录、引擎缓存目录等信息,然后会调用JNI方法在c++层初始化这些信息,JNI方法对应的c++方法如下

  • /flutter/shell/platform/android/flutter_main.cc
void FlutterMain::Init(JNIEnv* env,
                       jclass clazz,
                       jobject context,
                       jobjectArray jargs,
                       jstring bundlePath,
                       jstring appStoragePath,
                       jstring engineCachesPath) {
  std::vector<std::string> args;
  args.push_back("flutter");
  for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
    args.push_back(std::move(arg));
  }
  auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());
  auto settings = SettingsFromCommandLine(command_line);
  settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);

  ...

  g_flutter_main.reset(new FlutterMain(std::move(settings)));
}

c++层会将传入的参数保存到settings对象中,然后根据settings对象创建FlutterMain对象并保存到全局静态变量g_flutter_main中,供后续flutter引擎初始化使用。

接着,会通过viewFactory创建FlutterView对象,viewFactory就是实现了ViewFactory接口的FlutterActivity对象,查看其createFlutterView方法的实现发现返回null,此时就会执行if中的代码块,同样的,会通过viewFactory创建FlutterNativeView对象,我们查看源码发现同样返回null,这两个方法在FlutterActivity中的实现如下

  • /flutter/shell/platform/android/io/flutter/app/FlutterActivity.java
@Override
public FlutterView createFlutterView(Context context) {
    return null;
}

@Override
public FlutterNativeView createFlutterNativeView() {
    return null;
}

紧接着,会开始使用FlutterView的带参数的构造方法创建FlutterView对象,其具体实现如下

  • /flutter/shell/platform/android/io/flutter/view/FlutterView.java
public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
    super(context, attrs);

    Activity activity = (Activity) getContext();
    if (nativeView == null) {
        mNativeView = new FlutterNativeView(activity.getApplicationContext());
    } else {
        mNativeView = nativeView;
    }
    ...

    mNativeView.attachViewAndActivity(this, activity);

    mSurfaceCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            assertAttached();
            mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
        }

        ...
    };
    getHolder().addCallback(mSurfaceCallback);
	 ...

    // Configure the platform plugins and flutter channels.
    mFlutterLocalizationChannel = new MethodChannel(this, "flutter/localization", JSONMethodCodec.INSTANCE);
    ...
}

这里参数nativeView上文已经得出结论为null,要先通过FlutterNativeView的构造方法创建mNativeView对象,然后通过mNativeView调用attachViewAndActivity方法将FlutterView和当前的Activity做连接。

接着创建当前FlutterView(要知道它继承自SurfaceView)的mSurfaceCallback对象并添加到当前SurfaceHolder中以监听Surface的变化(如Surface的创建、改变和销毁等),这些变化会执行对应的回调方法,然后通过FlutterJNI的相关方法传递数据给Flutter engine层。

该方法中还会创建各种必要的平台插件和platform channel(用于flutter和原生之间的各种数据传递)。

接下来我们看下FlutterNativeView的构造方法实现

  • /flutter/shell/platform/android/io/flutter/view/FlutterNativeView.java
public FlutterNativeView(Context context) {
    this(context, false);
}

public FlutterNativeView(Context context, boolean isBackgroundView) {
    mContext = context;
    mPluginRegistry = new FlutterPluginRegistry(this, context);
    mFlutterJNI = new FlutterJNI();
    mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
    mFlutterJNI.setPlatformMessageHandler(new PlatformMessageHandlerImpl());
    mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
    attach(this, isBackgroundView);
    assertAttached();
    mMessageHandlers = new HashMap<>();
}

方法中会初始化mFlutterJNI对象&#

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值