Flutter在Android上的启动流程


目前Flutter项目更新还是比较频繁的,这里主要是看主要的的流程,主要的代码,一些细枝末节或者与主题无关的代码均已忽略.

本文源码基于Flutter Engine master分支,updated 2020/12/07

基本流程

  1. 初始化Flutter: 找到APK包中的Flutter资源,并加载Flutter 的native库

  2. 启动FlutterActivity

  3. onCreate()回调中,启动FlutterEngine

  4. 创建PlatformPlugin

  5. 将所有配置再pubsepec.yaml中的插件注册到FlutterEngine中

  6. 设置ContentView为FlutterView

    FlutterView实际上是一个FrameLayout,并且根据渲染模式内部会选择将Flutter UI渲染到SurfaceView或者SurfaceTexture.

  7. 建立FlutterView和FlutterEngine的联系

  8. FlutterActivity#onStart()的时候,找到Dart的入口函数,并使用DartExecutor执行Dart代码.

Flutter的初始化

FlutterApplication中有:

  @Override
  @CallSuper
  public void onCreate() {
    super.onCreate();
    FlutterInjector.instance().flutterLoader().startInitialization(this);
  }

最后调用的是FlutterLoader中的初始化方法:

  public FlutterLoader() {
    this(new FlutterJNI());
  }

  public void startInitialization(@NonNull Context applicationContext) {
    startInitialization(applicationContext, new Settings());
  }

  public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
    ...
    // 注册VsyncWaiter监听  
    VsyncWaiter.getInstance((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE))
        .init();

    // 开启一个线程执行初始化任务
    Callable<InitResult> initTask =
        new Callable<InitResult>() {
          @Override
          public InitResult call() {

            // 从APK中解析出Flutter相关的资源并缓存到磁盘中
            ResourceExtractor resourceExtractor = initResources(appContext);

            // 加载libflutter.so
            flutterJNI.loadLibrary();

            // Skia字体管理相关
            Executors.newSingleThreadExecutor()
                .execute(
                    new Runnable() {
                      @Override
                      public void run() {
                        flutterJNI.prefetchDefaultFontManager();
                      }
                    });
            // 等待APK解析完成
            if (resourceExtractor != null) {
              resourceExtractor.waitForCompletion();
            }
            // 返回结果
            return new InitResult(
                PathUtils.getFilesDir(appContext),
                PathUtils.getCacheDirectory(appContext),
                PathUtils.getDataDirectory(appContext));
          }
        };
    initResultFuture = Executors.newSingleThreadExecutor().submit(initTask);
  }  

FlutterJNI中有:

  public void loadLibrary() {
    System.loadLibrary("flutter");
  }

其实就是加载libflutter.so的.

总结下:

Flutter初始化流程

  1. 注册VsyncWaiter,用于后面Vsync时做一些处理;
  2. 解析APK中的Flutter资源,加载libflutter.so

FlutterActivity的启动

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    switchLaunchThemeForNormalTheme();

    super.onCreate(savedInstanceState);

    delegate = new FlutterActivityAndFragmentDelegate(this);
    delegate.onAttach(this);
    delegate.onRestoreInstanceState(savedInstanceState);

    lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);

    configureWindowForTransparency();
    setContentView(createFlutterView());
    configureStatusBarForFullscreenFlutterExperience();
  }

这里FlutterActivity其实只是一个壳子,主要都是委托给FlutterActivityAndFragmentDelegate去处理的,至于为什么要用这个委托类,Google给出了解释:

Flutter作为一个第三方库,如果再带上FragmentActivity等support库就显得有点臃肿了,因此自行实现Lifecyle机制和一个状态委托类

实际开发中可以继承FlutterActivity,重写各种方法,比如提供自定义的FlutterEngine,对FlutterSurfaceView或者FlutterTextureView进行自定义配置,为开发着提供了一定的灵活性.

FlutterEngine的创建和初始化

  /* package */ void setupFlutterEngine() {
    // 首先是否要使用一个缓存的FlutterEngine
    String cachedEngineId = host.getCachedEngineId();
    if (cachedEngineId != null) {
      flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
      isFlutterEngineFromHost = true;
      if (flutterEngine == null) {
        throw new IllegalStateException(
            "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
                + cachedEngineId
                + "'");
      }
      return;
    }

    // 然后看看是否提供了自定义的FlutterEngine
    flutterEngine = host.provideFlutterEngine(host.getContext());
    if (flutterEngine != null) {
      isFlutterEngineFromHost = true;
      return;
    }

    // 没有自定义的FlutterEngine,创建默认的FlutterEngine
    flutterEngine =
        new FlutterEngine(
            host.getContext(),
            host.getFlutterShellArgs().toArray(),
            /*automaticallyRegisterPlugins=*/ false,
            /*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
    isFlutterEngineFromHost = false;
  }

在FlutterEngine中有:

  public FlutterEngine(
      @NonNull Context context,
      @Nullable FlutterLoader flutterLoader,
      @NonNull FlutterJNI flutterJNI,
      @NonNull PlatformViewsController platformViewsController,
      @Nullable String[] dartVmArgs,
      boolean automaticallyRegisterPlugins,
      boolean waitForRestorationData) {

    // 获取AssetManager
    AssetManager assetManager;
    try {
      assetManager = context.createPackageContext(context.getPackageName(), 0).getAssets();
    } catch (NameNotFoundException e) {
      assetManager = context.getAssets();
    }
    // 创建DartExecutor,并
    this.dartExecutor = new DartExecutor(flutterJNI, assetManager);
    this.dartExecutor.onAttachedToJNI();

    // 创建各种Channel,用于处理一些平台相关的事件处理
    accessibilityChannel = new AccessibilityChannel(dartExecutor, flutterJNI);
    keyEventChannel = new KeyEventChannel(dartExecutor);
    lifecycleChannel = new LifecycleChannel(dartExecutor);
    localizationChannel = new LocalizationChannel(dartExecutor);
    mouseCursorChannel = new MouseCursorChannel(dartExecutor);
    navigationChannel = new NavigationChannel(dartExecutor);
    platformChannel = new PlatformChannel(dartExecutor);
    restorationChannel = new RestorationChannel(dartExecutor, waitForRestorationData);
    settingsChannel = new SettingsChannel(dartExecutor);
    systemChannel = new SystemChannel(dartExecutor);
    textInputChannel = new TextInputChannel(dartExecutor);

    this.localizationPlugin = new LocalizationPlugin(context, localizationChannel);

    // 初始化,这之前FlutterApplication中已经执行过一次,不过这里有判断是否已经初始化过,不用担心
    this.flutterJNI = flutterJNI;
    if (flutterLoader == null) {
      flutterLoader = FlutterInjector.instance().flutterLoader();
    }
    flutterLoader.startInitialization(context.getApplicationContext());
    flutterLoader.ensureInitializationComplete(context, dartVmArgs);

    // Flutter Engine的生命周期回调
    flutterJNI.addEngineLifecycleListener(engineLifecycleListener);

    // 一个PlatformViewController最多attach到一个FlutterView,用于管理Platform View
    flutterJNI.setPlatformViewsController(platformViewsController);
    // 国际化
    flutterJNI.setLocalizationPlugin(localizationPlugin);
    flutterJNI.setDynamicFeatureManager(FlutterInjector.instance().dynamicFeatureManager());

    // 关键,进入Flutter Engine C++层
    attachToJni();

    // 创建FlutterRenderer
    this.renderer = new FlutterRenderer(flutterJNI);

    this.platformViewsController = platformViewsController;
    this.platformViewsController.onAttachedToJNI();

    this.pluginRegistry =
        new FlutterEngineConnectionRegistry(context.getApplicationContext(), this, flutterLoader);

    // 如果是自动注册插件,则注册插件,后面还会手动注册
    if (automaticallyRegisterPlugins) {
      registerPlugins();
    }
  }

  private void attachToJni() {
    flutterJNI.attachToNative(false);

    if (!isAttachedToJni()) {
      throw new RuntimeException("FlutterEngine failed to attach to its native Object reference.");
    }
  }

FlutterEngine的构造函数中做了很多重要组件的创建工作,比如:

  • DartExecutor

  • AssetManager

  • 各种系统Channel

  • 通过JNI调用Flutter Engine中的C++层代码

  • FlutterRenderer

    表示Flutter Engine的渲染能力,它提供了RenderSurface用于绘制Flutter UI像素到Android的View层级.

    FlutterRenderer管理用于渲染的texture,和一些执行native方法的java JNI调用;

    RenderSurface提供了Surface给Flutter去绘制.

    FlutterSurafceView和FlutterTextureView都实现了RenderSurface.

  • 注册插件

    这里这是一个注册插件的入口,这里是自动注册

    后面还有一次注册插件;

FlutterEngine中有:

  @UiThread
  public void attachToNative(boolean isBackgroundView) {
    ensureRunningOnMainThread();
    ensureNotAttachedToNative();
    nativePlatformViewId = performNativeAttach(this, isBackgroundView);
  }

  @VisibleForTesting
  public long performNativeAttach(@NonNull FlutterJNI flutterJNI, boolean isBackgroundView) {
    return nativeAttach(flutterJNI, isBackgroundView);
  }

  private native long nativeAttach(@NonNull FlutterJNI flutterJNI, boolean isBackgroundView);

这里会调用C++层的代码,在shell/platform/android/platform_view_android_jni_impl.cc中有:

// Called By Java
static jlong AttachJNI(JNIEnv* env,
                       jclass clazz,
                       jobject flutterJNI,
                       jboolean is_background_view) {
  fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI);
  std::shared_ptr<PlatformViewAndroidJNI> jni_facade =
      std::make_shared<PlatformViewAndroidJNIImpl>(java_object);
  auto shell_holder = std::make_unique<AndroidShellHolder>(
      FlutterMain::Get().GetSettings(), jni_facade, is_background_view);
  if (shell_holder->IsValid()) {
    return reinterpret_cast<jlong>(shell_holder.release());
  } else {
    return 0;
  }
}

这里会创建AndroidShellHolder,这个AndroidShellHolder用处巨大,后面会具体聊聊.

PlatformPlugin的创建和作用

  @Nullable
  @Override
  public PlatformPlugin providePlatformPlugin(
      @Nullable Activity activity, @NonNull FlutterEngine flutterEngine) {
    return new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel(), this);
  }

这里不多说,后面仔细聊聊.

插件注册

  @Override
  public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    GeneratedPluginRegister.registerGeneratedPlugins(flutterEngine);
  }

这里又注册了一次插件,需要与前面一次注册插件的调用区分,上一个带有一个参数判断,而这个是不带判断的.

在GeneratePluginRegister中有:

  public static void registerGeneratedPlugins(@NonNull FlutterEngine flutterEngine) {
    try {
      Class<?> generatedPluginRegistrant =
          Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
      Method registrationMethod =
          generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
      registrationMethod.invoke(null, flutterEngine);
    } catch (Exception e) {
      Log.w(
          TAG,
          "Tried to automatically register plugins with FlutterEngine ("
              + flutterEngine
              + ") but could not find and invoke the GeneratedPluginRegistrant.");
    }
  }

FlutterView的渲染流程

  @NonNull
  View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    // 根据渲染模式选择创建对应的FlutterSurfaceView或者FlutterTextureView,然后添加到FlutterView中
    if (host.getRenderMode() == RenderMode.surface) {
      FlutterSurfaceView flutterSurfaceView =
          new FlutterSurfaceView(
              host.getActivity(), host.getTransparencyMode() == TransparencyMode.transparent);
      // 允许Activity自定义
      host.onFlutterSurfaceViewCreated(flutterSurfaceView);
      // Create the FlutterView that owns the FlutterSurfaceView.
      flutterView = new FlutterView(host.getActivity(), flutterSurfaceView);
    } else {
      FlutterTextureView flutterTextureView = new FlutterTextureView(host.getActivity());
      host.onFlutterTextureViewCreated(flutterTextureView);
      flutterView = new FlutterView(host.getActivity(), flutterTextureView);
    }

    // 首帧渲染监听
    flutterView.addOnFirstFrameRenderedListener(flutterUiDisplayListener);

    // Splashview 相关的逻辑
    flutterSplashView = new FlutterSplashView(host.getContext());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
      flutterSplashView.setId(View.generateViewId());
    } else {
      flutterSplashView.setId(486947586);
    }
    flutterSplashView.displayFlutterViewWithSplash(flutterView, host.provideSplashScreen());

    // 建立FlutterView与FlutterEngine的联系
    flutterView.attachToFlutterEngine(flutterEngine);

    return flutterSplashView;
  }

这里主要是选择渲染模式,然后建立起FlutterView和Flutter Engine间的联系.

FlutterView的渲染模式

  • RenderMode#surface

    默认的渲染模式,将Flutter UI渲染到SurfaceView上.

    优点: 性能好

    缺点: 在z轴方向上,不能放置在其他2个Android View之间,也不能使用animation和transform效果.

    除非有特别需求要使用SurfaceTexture,一般都是使用SurafceView.

  • RenderMode#texture

    将Flutter UI渲染到SurfaceTexture上,性能没有SurfaceView模式好,但是由于它使用的是TextureView,表现得更像一个正常的Android View.

    优点: 可以使用动画和转换效果,可以任意放在View之间.

    缺点: 性能稍差一点

建立FlutterEngine 和 FlutterView的联系

  public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    // 已经绑定了FlutterEngine
    if (isAttachedToFlutterEngine()) {
      if (flutterEngine == this.flutterEngine) {
        return;
      }
      detachFromFlutterEngine();
    }

    // 绑定FlutterView的FlutterEngine
    this.flutterEngine = flutterEngine;

    // 这里的FlutterRendeer是FlutterEngine初始化的时候创建的
    FlutterRenderer flutterRenderer = this.flutterEngine.getRenderer();
    isFlutterUiDisplayed = flutterRenderer.isDisplayingFlutterUi();

    // 这里的RenderSurface可能是FlutterSurfaceView,FlutterTextureView,FlutterImageView中的一种
    // 关键
    renderSurface.attachToRenderer(flutterRenderer);

    flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);

    /// ...各种平台事件处理

    this.flutterEngine
        .getPlatformViewsController()
        .attachToFlutterRenderer(this.flutterEngine.getRenderer());


    // Push View and Context related information from Android to Flutter.
    sendUserSettingsToFlutter();
    localizationPlugin.sendLocalesToFlutter(getResources().getConfiguration());
    sendViewportMetricsToFlutter();

    flutterEngine.getPlatformViewsController().attachToView(this);

    // Notify engine attachment listeners of the attachment.
    for (FlutterEngineAttachmentListener listener : flutterEngineAttachmentListeners) {
      listener.onFlutterEngineAttachedToFlutterView(flutterEngine);
    }

    // If the first frame has already been rendered, notify all first frame listeners.
    // Do this after all other initialization so that listeners don't inadvertently interact
    // with a FlutterView that is only partially attached to a FlutterEngine.
    if (isFlutterUiDisplayed) {
      flutterUiDisplayListener.onFlutterUiDisplayed();
    }
  }

这里拿FlutterSurfaceView举例:

  public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
    if (this.flutterRenderer != null) {
      this.flutterRenderer.stopRenderingToSurface();
      this.flutterRenderer.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
    }

    this.flutterRenderer = flutterRenderer;
    isAttachedToFlutterRenderer = true;

    this.flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);

    // 现在可以开始渲染了(Android Window 和 renderer都已经绑定好了)
    if (isSurfaceAvailableForRendering) {
      Log.v(
          TAG,
          "Surface is available for rendering. Connecting FlutterRenderer to Android surface.");
      connectSurfaceToRenderer();
    }
  }

  private void connectSurfaceToRenderer() {
    if (flutterRenderer == null || getHolder() == null) {
      throw new IllegalStateException(
          "connectSurfaceToRenderer() should only be called when flutterRenderer and getHolder() are non-null.");
    }
    // 开始渲染
    flutterRenderer.startRenderingToSurface(getHolder().getSurface());
  }  

然后就是FlutterRenderer中:

  public void startRenderingToSurface(@NonNull Surface surface) {
    if (this.surface != null) {
      stopRenderingToSurface();
    }

    this.surface = surface;

    flutterJNI.onSurfaceCreated(surface);
  }

FlutterJNI中有:

  @UiThread
  public void onSurfaceCreated(@NonNull Surface surface) {
    ensureRunningOnMainThread();
    ensureAttachedToNative();
    nativeSurfaceCreated(nativePlatformViewId, surface);
  }

到这就会调用到C++层了(shell/platform/android/platform_view_android_jni_impl.cc):

static void SurfaceCreated(JNIEnv* env,
                           jobject jcaller,
                           jlong shell_holder,
                           jobject jsurface) {
  // Note: This frame ensures that any local references used by
  // ANativeWindow_fromSurface are released immediately. This is needed as a
  // workaround for https://code.google.com/p/android/issues/detail?id=68174
  fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env);
  auto window = fml::MakeRefCounted<AndroidNativeWindow>(
      ANativeWindow_fromSurface(env, jsurface));
  ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
}

这里Java的Surface和C++的Surface就建立了联系.

执行Dart代码

在FlutterActivity的onStart()回调中有:

  void onStart() {
    Log.v(TAG, "onStart()");
    ensureAlive();
    doInitialFlutterViewRun();
  }
  private void doInitialFlutterViewRun() {

    if (host.getCachedEngineId() != null) {
      return;
    }
    if (flutterEngine.getDartExecutor().isExecutingDart()) {
      // 有些情况会重复执行onStart()回调,不过不用担心
      return;
    }

    // 初始Router路径
    String initialRoute = host.getInitialRoute();
    if (initialRoute == null) {
      initialRoute = maybeGetInitialRouteFromIntent(host.getActivity().getIntent());
      if (initialRoute == null) {
        initialRoute = DEFAULT_INITIAL_ROUTE;
      }
    }

    // The engine needs to receive the Flutter app's initial route before executing any
    // Dart code to ensure that the initial route arrives in time to be applied.
    flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);

    String appBundlePathOverride = host.getAppBundlePath();
    if (appBundlePathOverride == null || appBundlePathOverride.isEmpty()) {
      appBundlePathOverride = FlutterInjector.instance().flutterLoader().findAppBundlePath();
    }

    // 配置Dart入口函数并执行,默认是main()方法
    DartExecutor.DartEntrypoint entrypoint =
        new DartExecutor.DartEntrypoint(
            appBundlePathOverride, host.getDartEntrypointFunctionName());
    flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
  }

到这里,Flutter中的Dart代码已经执行起来了.


文章作者: 姜康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 姜康 !
评论
 上一篇
std::deque std::deque
C++中的std::deque,看名字就知道是一个双端队列. 容量操作// 容量大小 deq.size(); // 最大容量 deq.max_size(); // 更改容器大小 deq.resize(); // 容器判空 deq.e
2020-12-12
下一篇 
C++11中的Lambda C++11中的Lambda
C++ 11 中支持了Lambda,然后C++14, C++20中又有所增加. 本着实用的目的,这里就简单的说下C++11中Lambda的基本用法. 语法有以下几种形式: [ captures ] ( params ) -> ret { b
2020-12-08
  目录