type
status
date
slug
summary
tags
category
icon
password
目前Flutter项目更新还是比较频繁的,这里主要是看主要的的流程,主要的代码,一些细枝末节或者与主题无关的代码均已忽略.
本文源码基于Flutter Engine master分支,updated 2020/12/07

基本流程

  1. 初始化Flutter: 找到APK包中的Flutter资源,并加载Flutter 的native库
  1. 启动FlutterActivity
  1. onCreate()回调中,启动FlutterEngine
  1. 创建PlatformPlugin
  1. 将所有配置再pubsepec.yaml中的插件注册到FlutterEngine中
  1. 设置ContentView为FlutterView
    1. FlutterView实际上是一个FrameLayout,并且根据渲染模式内部会选择将Flutter UI渲染到SurfaceView或者SurfaceTexture.
  1. 建立FlutterView和FlutterEngine的联系
  1. 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时做一些处理;
  1. 解析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代码已经执行起来了.
Flutter时间处理image_picker的使用
姜康
姜康
一个软件工程师
公告
type
status
date
slug
summary
tags
category
icon
password
🎉博客网站重新制作了🎉
👏欢迎更新体验👏