Flutter启动流程源码分析

Flutter启动流程源码分析

Flutter的启动从java代码层面上看是离不开FlutterApplicationFlutterActivity这两个类的,下面我们就以flutter1.12.13版本为例来看下源码

一、FlutterApplication启动流程

1.1、FlutterApplication.onCreate

public void onCreate() {
    super.onCreate();
  // 初始化flutter相关资源
    FlutterMain.startInitialization(this);
}

1.2、FlutterMain

Flutter engine初始化类

public static void startInitialization(@NonNull Context applicationContext) {
  if (isRunningInRobolectricTest) {
    return;
  }
  // 从1.9.1+hotfix.6时单独抽出了一个单例FlutterLoader
  FlutterLoader.getInstance().startInitialization(applicationContext);
}

1.3、FlutterLoader

在apk中查找flutter resources并加载libflutter.so

FlutterLoader-->startInitialization

public void startInitialization(@NonNull Context applicationContext) {
  // 初始化一个默认的Setting
  startInitialization(applicationContext, new Settings());
}
public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
  // 首次执行时全局的settings还未被赋值,保证startInitialization只执行一次
  if (this.settings != null) {
    return;
  }
  // 保证在主线程中执行初始化操作
  if (Looper.myLooper() != Looper.getMainLooper()) {
    throw new IllegalStateException("startInitialization must be called on the main thread");
  }

  // 使用application的context.
  applicationContext = applicationContext.getApplicationContext();
    // 给全局的settings赋值
  this.settings = settings;

  long initStartTimestampMillis = SystemClock.uptimeMillis();
  // 初始化配置
  initConfig(applicationContext);
  // 初始化资源加载
  initResources(applicationContext);
    // 这个类的主要作用之一:加载libflutter.so
  System.loadLibrary("flutter");

  VsyncWaiter.getInstance(
    (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE))
    .init();

  long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
  // 调用C层代码记录一下application启动的时间
  FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
}

FlutterLoader-->initConfig

加载androidManifest.xml中的flutter相关的配置:

1、aot模式时libapp.so库的位置(默认在lib/armeabi-v7a或者lib/arm64-v8a文件夹下)

2、flutter_assets资源文件的路径(默认在assets文件夹下)

3、JIT模式时vm_snapshot_data的位置(默认在debug时在flutter_assets文件夹下)

4、JIT模式时isolate_snapshot_data的位置(默认在debug时在flutter_assets文件夹下)

private void initConfig(@NonNull Context applicationContext) {
  Bundle metadata = getApplicationInfo(applicationContext).metaData;

  // There isn't a `<meta-data>` tag as a direct child of `<application>` in
  // `AndroidManifest.xml`.
  if (metadata == null) {
    return;
  }

  aotSharedLibraryName =
    metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, DEFAULT_AOT_SHARED_LIBRARY_NAME);
  flutterAssetsDir =
    metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, DEFAULT_FLUTTER_ASSETS_DIR);

  vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, DEFAULT_VM_SNAPSHOT_DATA);
  isolateSnapshotData =
    metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, DEFAULT_ISOLATE_SNAPSHOT_DATA);
}

FlutterLoader.initResources

在debug或者JIT模式下,加载vm_snapshot_data、isolate_snapshot_data、kernel_blob.bin

private void initResources(@NonNull Context applicationContext) {
  // 先清空data/user/0/package/cache目录下文件
  new ResourceCleaner(applicationContext).start();
    // debug或者JIT模式
  if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
    // data/user/0/package/app_flutter目录
    final String dataDirPath = PathUtils.getDataDirectory(applicationContext);
    final String packageName = applicationContext.getPackageName();
    final PackageManager packageManager = applicationContext.getPackageManager();
    final AssetManager assetManager = applicationContext.getResources().getAssets();
    resourceExtractor =
      new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
    
    // 资源加载到列表中
    resourceExtractor
      .addResource(fullAssetPathFrom(vmSnapshotData)) // fullAssetPathFrom是拼写flutter_assets全路径的方法
      .addResource(fullAssetPathFrom(isolateSnapshotData))
      .addResource(fullAssetPathFrom(DEFAULT_KERNEL_BLOB));
    
    // 启动一个AsyncTask任务,会将data/user/0/package/app_flutter目录下对应的vm_snapshot_data、isolate_snapshot_data、kernel_blob.bin的文件先删除,然后从apk安装目录的assets中复制新的文件使用
    resourceExtractor.start();
  }
}

1.4、FlutterJNI

调用libflutter.so时用到的JNI方法封装

// 记录application启动的时间
public static native void nativeRecordStartTimestamp(long initTimeMillis);

1.5、flutter_main.cc

主要是定义了两个方法:nativeInit、nativeRecordStartTimestamp

bool FlutterMain::Register(JNIEnv* env) {
  static const JNINativeMethod methods[] = {
      // 。。。。。。省略其他代码
      {
            // JNI方法nativeRecordStartTimestamp,转化成调用C++的RecordStartTimestamp方法
          .name = "nativeRecordStartTimestamp",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
      },
  };
  // 。。。。。。省略其他代码
}

1.6、libary_loader.cc

在加载libflutter.so时会触发JNI_OnLoad方法

// 注册FlutterMain的JNI方法
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // 。。。。。。省略其他代码
    result = flutter::FlutterMain::Register(env);
  // 。。。。。。省略其他代码
}

附FlutterApplication时序图

image-flutter-application.png


image

二、FlutterActivity

在flutter中有两个FlutterActivity,一个是io.flutter.app.FlutterActivity,另一个是io.flutter.embedding.android.FlutterActivity,前者是老版本的Flutter运行相关类,在1.12版本已经不建议使用了。参考文档https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects,下面讲解的都是io.flutter.embedding.android.FlutterActivity。

2.1、FlutterActivity

2.1.1、onCreate
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
  // 查看metedata中是否有配置主题
  switchLaunchThemeForNormalTheme();
  super.onCreate(savedInstanceState);
  lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    // 初始化delegate
  delegate = new FlutterActivityAndFragmentDelegate(this);
  // 初始化flutter engine相关
  delegate.onAttach(this);
  // 为插件提供恢复状态的onRestoreInstanceState
  delegate.onActivityCreated(savedInstanceState);

  // 当Intent配置的backgroundMode是透明时,就配置window是否透明
  configureWindowForTransparency();
  // 创建FlutterView
  setContentView(createFlutterView());
  configureStatusBarForFullscreenFlutterExperience();
}
2.1.2、configureWindowForTransparency
public FlutterView.RenderMode getRenderMode() {
    // 获取intent里传递的backgroundMode,opaque表示不透明
    return getBackgroundMode() == BackgroundMode.opaque
        ? FlutterView.RenderMode.surface
        : FlutterView.RenderMode.texture;
}
private void configureWindowForTransparency() {
    BackgroundMode backgroundMode = getBackgroundMode();
    if (backgroundMode == BackgroundMode.transparent) {
      getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
      getWindow().setFlags(
        WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
        WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
      );
    }
  }
2.1.3、createFlutterView
private View createFlutterView() {
    // 通过代理创建flutterView
    return delegate.onCreateView(
    null /* inflater */,
    null /* container */,
    null /* savedInstanceState */);
}

2.2、FlutterActivityAndFragmentDelegate

2.2.1、onAttach

主要做以下几件事:

1、获取或者创建flutter engine

2、创建和配置PlatformPlugin

3、将flutterEngine附加到activity

void onAttach(@NonNull Context context) {
    ensureAlive();

    // 当这个FlutterActivity是复用时,flutter engine复用
    if (flutterEngine == null) {
      setupFlutterEngine();
    }

    // 创建和配置platform plugin
    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);

    if (host.shouldAttachEngineToActivity()) {
      // 将flutter engine附加到activity
      Log.d(TAG, "Attaching FlutterEngine to the Activity that owns this Fragment.");
      flutterEngine.getActivityControlSurface().attachToActivity(
          host.getActivity(),
          host.getLifecycle()
      );
    }
        // flutter activity配置flutter engine提供入口
    host.configureFlutterEngine(flutterEngine);
  }

2.2.2、onCreateView

View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    Log.v(TAG, "Creating FlutterView.");
    ensureAlive();
    // 创建flutterView
    flutterView = new FlutterView(host.getActivity(), host.getRenderMode(), host.getTransparencyMode());
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);
        // 创建一个在view直到flutter的第一帧显示出来
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      flutterSplashView.setId(486947586);
    }
    // 当flutter view第一帧渲染后会移除splash view
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());

    return flutterSplashView;
 }

三、FlutterEngine

3.1、构造方法时调用
public FlutterEngine(
      @NonNull Context context,
      @NonNull FlutterLoader flutterLoader,
      @NonNull FlutterJNI flutterJNI,
      @NonNull PlatformViewsController platformViewsController,
      @Nullable String[] dartVmArgs,// FlutterActivity重写getFlutterShellArgs方法可以添加参数
      boolean automaticallyRegisterPlugins) {
    this.flutterJNI = flutterJNI;
    // 初始化配置、资源、加载libflutter.so;如果使用了FlutterApplication,也不会重复初始化操作
    flutterLoader.startInitialization(context.getApplicationContext());
    // 确保初始化完成
    flutterLoader.ensureInitializationComplete(context, dartVmArgs);

    flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
    // 调用flutterJNI的attachToNative初始化setting配置
    attachToJni();

    this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
    this.dartExecutor.onAttachedToJNI();

    // 。。。。。省略
  }
3.2、attachToJni
private void attachToJni() {
    Log.v(TAG, "Attaching to JNI.");
    // 通过FlutterJNI调用libflutter.so中的方法
    flutterJNI.attachToNative(false);
    if (!isAttachedToJni()) {
      throw new RuntimeException("FlutterEngine failed to attach to its native Object reference.");
    }
  }

四、FlutterJNI

通过这个类调用flutter engine中的 C/C++ 代码,对应platform_view_android_jni.cc代码

// 将java层初始化的参数传递给C++层
public static native void nativeInit(
      @NonNull Context context,
      @NonNull String[] args,
      @Nullable String bundlePath,
      @NonNull String appStoragePath,
      @NonNull String engineCachesPath);
// 初始化AndroidShellHolder
private native long nativeAttach(@NonNull FlutterJNI flutterJNI, boolean isBackgroundView);

附上FlutterActivity启动时序图

image

了解完Flutter的启动流程,下一篇文章我们就来配置一下flutter engine的编译环境,以及一步步的实现flutter的动态化,敬请期待

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容