介绍

Flutter应用是由平台来创建、初始化并启动的,这里我们以android为例,对启动过程做一个走马观花式的了解,旨在对平台端的工作有个大致了解。

Android端的启动流程

启动流程实际上还涉及了很多native 层的工作,但是宥于篇幅,暂且只看Android端。

FlutterApplication

Flutter——在Android平台上的启动流程浅析_第1张图片

flutter应用下,原生的启动流程并没有什么变化,我们来看Application的onCreate函数。

  @Override  @CallSuper  public void onCreate() {    super.onCreate();    FlutterMain.startInitialization(this);  }

很简单,继续往里走

  public static void startInitialization(@NonNull Context applicationContext) {    if (isRunningInRobolectricTest) {      return;    }    FlutterLoader.getInstance().startInitialization(applicationContext);  }

按上面方法的注释来看,是初始化 native system(即C++)的,最终会调用下面的方法:

我将说明以注释的形式写在下面
  public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {        if (this.settings != null) {      return;    }    ///确保运行在 主线程    if (Looper.myLooper() != Looper.getMainLooper()) {      throw new IllegalStateException("startInitialization must be called on the main thread");    }    // Ensure that the context is actually the application context.    final Context appContext = applicationContext.getApplicationContext();    this.settings = settings;    initStartTimestampMillis = SystemClock.uptimeMillis();        ///配置 aotSharedLibraryName、flutterAssetsDir、    ///      vmSnapshotData、isolateSnapshotData    ///等参数        initConfig(appContext);    ///初始化VsyncWaiter,并设置回调    /// 当vsync信号到来时,就调用我们设置的回调,最终会触发页面的刷新    VsyncWaiter.getInstance((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE))        .init();    // 子线程        ///这里主要是抽取资源文件,    ///加载 flutter(框架)代码    Callable initTask =        new Callable() {          @Override          public InitResult call() {            ResourceExtractor resourceExtractor = initResources(appContext);            System.loadLibrary("flutter");            // Prefetch the default font manager as soon as possible on a background thread.            // It helps to reduce time cost of engine setup that blocks the platform thread.            Executors.newSingleThreadExecutor()                .execute(                    new Runnable() {                      @Override                      public void run() {                        FlutterJNI.nativePrefetchDefaultFontManager();                      }                    });            if (resourceExtractor != null) {              resourceExtractor.waitForCompletion();            }            return new InitResult(                PathUtils.getFilesDir(appContext),                PathUtils.getCacheDirectory(appContext),                PathUtils.getDataDirectory(appContext));          }        };    initResultFuture = Executors.newSingleThreadExecutor().submit(initTask);  }

至此FlutterApplication 的相关流程就走完了。

另外,虽然上面的代码中使用了子线程,但是最终在这些任务没有完成前,是不会进入flutter侧的,我们接着走FlutterActivity。

FlutterActivity & onCreate

Flutter——在Android平台上的启动流程浅析_第2张图片

开始的地方依然是 onCreate()方法:

  @Override  protected void onCreate(@Nullable Bundle savedInstanceState) {  ///切换主题    switchLaunchThemeForNormalTheme();    super.onCreate(savedInstanceState);///通知生命周期    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);    ///初始化delete,这个很重要,    ///所有的工作都是由它来完成的    delegate = new FlutterActivityAndFragmentDelegate(this);    delegate.onAttach(this);    ///是否需要恢复(包括通知插件)一些状态    delegate.onActivityCreated(savedInstanceState);///配置窗口    configureWindowForTransparency();    ///创建flutterView    setContentView(createFlutterView());    configureStatusBarForFullscreenFlutterExperience();  }

这里面比较重的代码是这几行:

    delegate = new FlutterActivityAndFragmentDelegate(this);    delegate.onAttach(this);    ...    setContentView(createFlutterView());

我们一步一步来,首先创建了FlutterActivityAndFragmentDelegate 并调用了它的attact(this)方法。

FlutterActivityAndFragmentDelegate

void onAttach(@NonNull Context context) {    ensureAlive();///初始化engine    if (flutterEngine == null) {    ///这里面会对已有的engine进行复用      setupFlutterEngine();    }    ///初始化平台插件    ///本质上,是将engine的 channel回调与平台的系统服务进行绑定    ///如:震动、复制粘贴、声音播放等...    platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);    if (host.shouldAttachEngineToActivity()) {      Log.v(TAG, "Attaching FlutterEngine to the Activity that owns this Fragment.");      /// 激活 原生viewController      /// 并通知相关插件      /// PlatformViewsController 这个类你应该很熟悉(如果你接入过原生view的话)      flutterEngine          .getActivityControlSurface()          .attachToActivity(host.getActivity(), host.getLifecycle());    }///注册插件    ///通过反射调用 “io.flutter.plugins.GeneratedPluginRegistrant”    ///的 “registerWith”方法,这个过程走完了,你的插件基本就能用了    host.configureFlutterEngine(flutterEngine);  }

通过上面,我们大致了解了,在flutter端使用的平台功能是什么时候装配的了。

我们回到FlutterActivity,继续重要的第二步:

setContentView(createFlutterView());  @NonNull  private View createFlutterView() {    return delegate.onCreateView(        null /* inflater */, null /* container */, null /* savedInstanceState */);  }
这里插一句,可以看一下这篇文章:

Flutter&Android 启动页(闪屏页)的加载流程和优化方案

最终会调用 delete的onCreateView :

  @NonNull  View onCreateView(      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {    Log.v(TAG, "Creating FlutterView.");    ensureAlive();    if (host.getRenderMode() == RenderMode.surface) {        ///一般flutter应用是 RenderMode.surface,所以会进入到这里        ///创建FlutterSurfaceView      FlutterSurfaceView flutterSurfaceView =          new FlutterSurfaceView(              host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);      // Allow our host to customize FlutterSurfaceView, if desired.      host.onFlutterSurfaceViewCreated(flutterSurfaceView);      // flutterView 创建完成后,便会调用addView      //将 flutterSurfaceView 显示出来,只不过啥都没有而已      flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);    } else {      ...省略代码...    }    // Add listener to be notified when Flutter renders its first frame.    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);    flutterSplashView = new FlutterSplashView(host.getContext());    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {      flutterSplashView.setId(View.generateViewId());    } else {      flutterSplashView.setId(486947586);    }    ///这里显示闪屏页 默认是个白屏    ///即,AndroidMainfest.xml 的所设置    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());    ///将flutterview 绑定到 engine上    flutterView.attachToFlutterEngine(flutterEngine);    return flutterSplashView;  }

flutterView 内部持有flutterSurfaceView (一个Surface),并最终通过attachToFlutterEngine绑定到engine上,我们来看一下其内部实现:

  public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {     ...省略部分代码...    this.flutterEngine = flutterEngine;    ///通过engine的 getRenderer,    ///可以将flutter的纹理绘制到android 上。    FlutterRenderer flutterRenderer = this.flutterEngine.getRenderer();    isFlutterUiDisplayed = flutterRenderer.isDisplayingFlutterUi();    renderSurface.attachToRenderer(flutterRenderer);    flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);    ...省略部分代码...        ///输入插件    textInputPlugin =        new TextInputPlugin(            this,            this.flutterEngine.getTextInputChannel(),            this.flutterEngine.getPlatformViewsController());    ///国际化插件    localizationPlugin = this.flutterEngine.getLocalizationPlugin();    ///与上面的textInputPlugin相关联    androidKeyProcessor =        new AndroidKeyProcessor(this.flutterEngine.getKeyEventChannel(), textInputPlugin);             /// 触摸事件的初始化     /// 相关触摸数据会发送到flutter端    androidTouchProcessor = new AndroidTouchProcessor(this.flutterEngine.getRenderer());    ///辅助功能    accessibilityBridge =        new AccessibilityBridge(            this,            flutterEngine.getAccessibilityChannel(),            (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE),            getContext().getContentResolver(),            this.flutterEngine.getPlatformViewsController());      ...省略部分代码...    ///通过上面的初始化,将用户相关的设置发送到flutter端    sendUserSettingsToFlutter();    localizationPlugin.sendLocalesToFlutter(getResources().getConfiguration());    sendViewportMetricsToFlutter();    ///将当前flutter view 绑定到 PlatformViewsController    flutterEngine.getPlatformViewsController().attachToView(this);    ...省略部分代码...  }

相关初始化工作完成,activity的生命周期也从onCreate来到了onStart()

FlutterActivity & onStart()

  @Override  protected void onStart() {    super.onStart();    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);    ///重要入口    delegate.onStart();  }

delegate.onStart()此方法 最终会调用doInitialFlutterViewRun()方法:

  private void doInitialFlutterViewRun() {    ...省略部分代码...    // 这里就是获取我们打包所得的 libapp.so路径    // 即,我们所写的dart代码,并执行它    DartExecutor.DartEntrypoint entrypoint =        new DartExecutor.DartEntrypoint(            host.getAppBundlePath(), host.getDartEntrypointFunctionName());    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);  }

至此整个android端的启动流程就走完了,这里再回顾总结一下。

总结

在flutterApplication中:

初始化一些资源路径,配置相关参数抽取资源并加载(assets)加载flutter.so关键库    - 最终走JNI_OnLoad 进入native进行相关工作    - 如绑定flutter jni初始化vsyncWaiter

在flutterActivity中:

会初始化重要类FlutterActivityAndFragmentDelegateactivity端的生命周期,也会触发delegate来对应回调对平台的系统功能(震动、剪贴板)进行绑定初始化platformViewController以及系统channel创建flutterView(内部持有一个surfaceView)    - 会最终进入native进行engine的初始化工作在onStart生命周期中加载咱们的dart代码,开始执行

在这整个过程中,会穿插进行native层的工作,并最终通过native层的调用,转到flutter端的main()函数,由于这里的内容很多,将会在后面的文章中介绍。

最后,谢谢大家的阅读,如果有不对的地方,还请指出。

系列文章

Flutter 仿网易云音乐App

Flutter&Android 启动页(闪屏页)的加载流程和优化方案

Flutter版 仿.知乎列表的视差效果

Flutter——实现网易云音乐的渐进式卡片切换

Flutter 仿同花顺自选股列表

更多相关文章

  1. Android 系统启动流程简析
  2. 编写高效的Android代码
  3. Android 测试代码编写小技巧 - UI 和 单元测试间共享代码
  4. Android 初始化之Zygote
  5. Github项目解析(二)-->将Android项目发布至JCenter代码库
  6. android优化 清除无效代码 UCDetector
  7. Android HAL 层框架分析以及代码示例
  8. Android init源代码分析(1)概要分析

随机推荐

  1. Android之判断当前网络状态
  2. Android获取apk的版本及包名等信息
  3. android折叠展开自定义列表项测试
  4. Android(安卓)架构
  5. Android(安卓)Path的使用
  6. Android(安卓)配置输出Apk名称和路径、渠
  7. android googlemap的location报空指针解
  8. android 单选对话框
  9. CentOS 安装 Android
  10. Android(安卓)AsyncTask