Flutter Android 端启动流程浅析

3,285 阅读7分钟

这篇文章主要是分析一下 Flutter Android 端的启动流程,主要是上层代码的分析,不涉及底层 c/c++ 等的分析。同时,不同 Flutter 版本的 sdk ,代码也会有所不同,但是整体流程和原理不会有太大的不同。

1、FlutterApplication

Android 端 app 的启动,一定会先初始化 Application,再去加载默认的第一个类 MainActivity。Flutter 项目对应的 Android 端应用程序,application 默认指定为 FlutterApplication。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.flutter_share">
    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="flutter_share"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

1.1 FlutterMain.startInitialization(this);

FlutterApplication 中 onCreate 核心初始化代码只有一行

        FlutterMain.startInitialization(this);

FlutterMain 这个类在 flutter.jar 包中。不同的平台对应不同的 flutter.jar 包,这个文件在 flutter sdk 的路径位置为: flutterSdkPath\flutter\bin\cache\artifacts\engine 。

接下来看 FlutterMain 中的代码

    public static void startInitialization(@NonNull Context applicationContext) {
        if (!isRunningInRobolectricTest) {
            startInitialization(applicationContext, new io.flutter.view.FlutterMain.Settings());
        }
    }

    public static void startInitialization(@NonNull Context applicationContext, @NonNull io.flutter.view.FlutterMain.Settings settings) {
        if (!isRunningInRobolectricTest) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                throw new IllegalStateException("startInitialization must be called on the main thread");
            } else if (sSettings == null) {
                sSettings = settings;
                long initStartTimestampMillis = SystemClock.uptimeMillis();
                initConfig(applicationContext);
                initResources(applicationContext);
                System.loadLibrary("flutter");
                VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService("window")).init();
                long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
                FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
            }
        }
    }

主要做了如下几件事情:

  • startInitialization 这个初始化函数必须在在主线程执行,否则抛出异常。
  • sSettings 这个变量只会初始化一次。
  • initConfig 初始化配置信息。
  • initResources 初始化资源。
  • System.loadLibrary("flutter") 加载 flutter 核心库 libflutter.so。这个库也在 flutter.jar 中,编译 flutter 项目中的时候,这个库会复制到 apk 中。
  • FlutterJNI.nativeRecordStartTimestamp 主要是调用底层方法记录初始化时间。

1.2 initConfig

这个方法如下:

    private static void initConfig(@NonNull Context applicationContext) {
        Bundle metadata = getApplicationInfo(applicationContext).metaData;
        if (metadata != null) {
            sAotSharedLibraryName = metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, "libapp.so");
            sFlutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, "flutter_assets");
            sVmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, "vm_snapshot_data");
            sIsolateSnapshotData = metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, "isolate_snapshot_data");
        }
    }

主要是解析 metadata 初始化默认配置,如果没有设置则使用默认值。

  • sAotSharedLibraryName : libapp.so
  • sFlutterAssetsDir: flutter_assets
  • sVmSnapshotData:vm_snapshot_data
  • sIsolateSnapshotData:isolate_snapshot_data

1.3 initResources

代码如下:

    private static void initResources(@NonNull Context applicationContext) {
        (new ResourceCleaner(applicationContext)).start();
        String dataDirPath = PathUtils.getDataDirectory(applicationContext);
        String packageName = applicationContext.getPackageName();
        PackageManager packageManager = applicationContext.getPackageManager();
        AssetManager assetManager = applicationContext.getResources().getAssets();
        sResourceExtractor = new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
        sResourceExtractor.addResource(fromFlutterAssets(sVmSnapshotData)).addResource(fromFlutterAssets(sIsolateSnapshotData)).addResource(fromFlutterAssets("kernel_blob.bin"));
        sResourceExtractor.start();
    }

主要的作用就两个:

  • 通过 ResourceCleaner 清理缓存文件
  • 通过 sRecourceExtractor 加载指定目录下的资源文件,通过这些文件将进行 flutter engine 和 Darv Vm 的初始化。

上面就是 Application 的初始化过程。接下来看 MainActivity 的执行。

2、MainActivity

Android 端默认启动的第一个类就是 MainActivity,而创建的 Flutter 的项目中,MainActivity 这个类都是自动生成的,代码如下:


public class MainActivity extends FlutterActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   GeneratedPluginRegistrant.registerWith(this);
 }
}

可以看到,MainActivity 继承自 Flutter 自己实现的 FlutterActivity。

2.1 GeneratedPluginRegistrant.registerWith(this)

MainActivity 中的核心代码只有一行

GeneratedPluginRegistrant.registerWith(this);

GeneratedPluginRegistrant 这个类代码如下:

/**
 * Generated file. Do not edit.
 */
public final class GeneratedPluginRegistrant {
  public static void registerWith(PluginRegistry registry) {
    if (alreadyRegisteredWith(registry)) {
      return;
    }
  }

  private static boolean alreadyRegisteredWith(PluginRegistry registry) {
    final String key = GeneratedPluginRegistrant.class.getCanonicalName();
    if (registry.hasPlugin(key)) {
      return true;
    }
    registry.registrarFor(key);
    return false;
  }
}

可以看到,这个类是自动生成的,并且会 执行 registry.registrarFor(key) 方法。 registry 是一个接口,并且 FlutterActivity 实现了这个接。而 MainActivity 也继承了 FlutterActivity 。接下来分析 FlutterActivity 。

3、FlutterActivity

public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory 

可以看到 FlutterActivity 实现了 Provider、PluginRegistry,ViewFactory 三个接口。

    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
    private final FlutterActivityEvents eventDelegate;
    private final Provider viewProvider;
    private final PluginRegistry pluginRegistry;

    public FlutterActivity() {
        this.eventDelegate = this.delegate;
        this.viewProvider = this.delegate;
        this.pluginRegistry = this.delegate;
    }

可以看到,三个引用都指向了同一个对象,也就是 这个 delegate 对象将实现另外三个类声明的功能。

接着看 FlutterActivity 中的主要方法:

    protected void onStart() {
        super.onStart();
        this.eventDelegate.onStart();
    }

    protected void onResume() {
        super.onResume();
        this.eventDelegate.onResume();
    }
   ...

可以看到,在 FlutterActivity 中的核心方法中,只是简单的回调了 delegate 中对应的方法,也就是 FlutterActivity 这个类只是一个代理,真正实现功能的一定是 delegate 这个对象对应的类,也就是 FlutterActivityDelegate。

4、 FlutterActivityDelegate

public final class FlutterActivityDelegate implements FlutterActivityEvents, Provider, PluginRegistry 

这个类通过 final 修饰,将不能被继承,同时确实也实现了三个接口。

4.1 onCreate

    public void onCreate(Bundle savedInstanceState) {
        if (VERSION.SDK_INT >= 21) {
            Window window = this.activity.getWindow();
            window.addFlags(-2147483648);
            window.setStatusBarColor(1073741824);
            window.getDecorView().setSystemUiVisibility(1280);
        }

        String[] args = getArgsFromIntent(this.activity.getIntent());
        FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
        this.flutterView = this.viewFactory.createFlutterView(this.activity);
        if (this.flutterView == null) {
            FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
            this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
            this.flutterView.setLayoutParams(matchParent);
            this.activity.setContentView(this.flutterView);
            this.launchView = this.createLaunchView();
            if (this.launchView != null) {
                this.addLaunchView();
            }
        }

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

        }
    }

onCreate 是这个类初始化之后执行的第一个函数,主要的作用是:

  • 设置沉浸式状态栏
  • 从 intent 中获取参数
  • 调用 FlutterMain.ensureInitializationComplete 确保资源初始化完成。
  • 创建 FlutterNativeView 和 FlutterView 对象实例。
  • 设置当前 activity 的视图布局为 flutterView。
  • runBundle 这里面将通过一些列方法的调用,加载 Dart 代码。

4.1 FlutterMain.ensureInitializationComplete

  public static void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
        if (!isRunningInRobolectricTest) {
            if (Looper.myLooper() != Looper.getMainLooper()) {
                throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
            } else if (sSettings == null) {
                throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
            } else if (!sInitialized) {
                try {
                    if (sResourceExtractor != null) {
                        sResourceExtractor.waitForCompletion();
                    }

                    List<String> shellArgs = new ArrayList();
                    shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
                    ApplicationInfo applicationInfo = getApplicationInfo(applicationContext);
                    shellArgs.add("--icu-native-lib-path=" + applicationInfo.nativeLibraryDir + File.separator + "libflutter.so");
                    if (args != null) {
                        Collections.addAll(shellArgs, args);
                    }

                    String kernelPath = null;
                    shellArgs.add("--aot-shared-library-name=" + sAotSharedLibraryName);
                    shellArgs.add("--aot-shared-library-name=" + applicationInfo.nativeLibraryDir + File.separator + sAotSharedLibraryName);
                    shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
                    if (sSettings.getLogTag() != null) {
                        shellArgs.add("--log-tag=" + sSettings.getLogTag());
                    }

                    String appStoragePath = PathUtils.getFilesDir(applicationContext);
                    String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
                    FlutterJNI.nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), (String)kernelPath, appStoragePath, engineCachesPath);
                    sInitialized = true;
                } catch (Exception var7) {
                    Log.e("FlutterMain", "Flutter initialization failed.", var7);
                    throw new RuntimeException(var7);
                }
            }
        }
    }

这里分析的是 release 模式下的代码,主要的作用是:

  • 主线程执行
  • sSetting 不能为空,否则抛出异常。
  • 必须保证 sResourceExtractor 资源提取完成。
  • 将所有的配置参数(如 flutter 核心库的路径、flutter APP 项目编译之后生成的 so 库的路径)传递给 shellArgs,并且这个 List 数组将会传递给底层进行 Dart Vm 的初始等。
  • 通过 FlutterJNI 进行底层初始操作。

4.2 FlutterView 的初始化

public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry {
    ...
    
    public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
        super(context, attrs);
        this.nextTextureId = new AtomicLong(0L);
        this.mIsSoftwareRenderingEnabled = false;
        this.didRenderFirstFrame = false;
        this.onAccessibilityChangeListener = new OnAccessibilityChangeListener() {
            public void onAccessibilityChanged(boolean isAccessibilityEnabled, boolean isTouchExplorationEnabled) {
                FlutterView.this.resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
            }
        };
        Activity activity = getActivity(this.getContext());
        if (activity == null) {
            throw new IllegalArgumentException("Bad context");
        } else {
            if (nativeView == null) {
                this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
            } else {
                this.mNativeView = nativeView;
            }

            this.dartExecutor = this.mNativeView.getDartExecutor();
            this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI());
            this.mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();
            this.mMetrics = new FlutterView.ViewportMetrics();
            this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
            this.setFocusable(true);
            this.setFocusableInTouchMode(true);
            this.mNativeView.attachViewAndActivity(this, activity);
            this.mSurfaceCallback = new Callback() {
                public void surfaceCreated(SurfaceHolder holder) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
                }

                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
                }

                public void surfaceDestroyed(SurfaceHolder holder) {
                    FlutterView.this.assertAttached();
                    FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed();
                }
            };
            this.getHolder().addCallback(this.mSurfaceCallback);
            this.mActivityLifecycleListeners = new ArrayList();
            this.mFirstFrameListeners = new ArrayList();
            this.navigationChannel = new NavigationChannel(this.dartExecutor);
            this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
            this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
            this.localizationChannel = new LocalizationChannel(this.dartExecutor);
            this.platformChannel = new PlatformChannel(this.dartExecutor);
            this.systemChannel = new SystemChannel(this.dartExecutor);
            this.settingsChannel = new SettingsChannel(this.dartExecutor);
            final PlatformPlugin platformPlugin = new PlatformPlugin(activity, this.platformChannel);
            this.addActivityLifecycleListener(new ActivityLifecycleListener() {
                public void onPostResume() {
                    platformPlugin.updateSystemUiOverlays();
                }
            });
            this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method");
            PlatformViewsController platformViewsController = this.mNativeView.getPluginRegistry().getPlatformViewsController();
            this.mTextInputPlugin = new TextInputPlugin(this, this.dartExecutor, platformViewsController);
            this.androidKeyProcessor = new AndroidKeyProcessor(this.keyEventChannel, this.mTextInputPlugin);
            this.androidTouchProcessor = new AndroidTouchProcessor(this.flutterRenderer);
            this.mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(this.mTextInputPlugin);
            this.sendLocalesToDart(this.getResources().getConfiguration());
            this.sendUserPlatformSettingsToDart();
        }
    }
    ...
}

可以看到,FlutterView 继承了 SurfaceView ,并且实现了 BinaryMessenger,TextureRegistry 两个接口。

主要的作用:

  • 创建 FlutterNativeView。
  • 创建 CallBack 实例,当执行 Surface 回调函数的时候,会通知底层。
  • 创建平台通道,并将平台通过设置信息传递给 Dart。

4.3 FlutterNativeView 初始化

public class FlutterNativeView implements BinaryMessenger {
    ...
    public FlutterNativeView(@NonNull Context context, boolean isBackgroundView) {
        this.flutterUiDisplayListener = new FlutterUiDisplayListener() {
            public void onFlutterUiDisplayed() {
                if (FlutterNativeView.this.mFlutterView != null) {
                    FlutterNativeView.this.mFlutterView.onFirstFrame();
                }
            }

            public void onFlutterUiNoLongerDisplayed() {
            }
        };
        this.mContext = context;
        this.mPluginRegistry = new FlutterPluginRegistry(this, context);
        this.mFlutterJNI = new FlutterJNI();
        this.mFlutterJNI.addIsDisplayingFlutterUiListener(this.flutterUiDisplayListener);
        this.dartExecutor = new DartExecutor(this.mFlutterJNI, context.getAssets());
        this.mFlutterJNI.addEngineLifecycleListener(new FlutterNativeView.EngineLifecycleListenerImpl());
        this.attach(this, isBackgroundView);
        this.assertAttached();
    }
    ...
}
  • 初始化对象FlutterPluginRegistry;
  • 初始化对象FlutterJNI;
  • 初始化对象RenderSurfaceImpl,并赋值给mFlutterJNI的成员变量renderSurface;
  • 初始化对象DartExecutor;
  • 设置引擎生命周期回调监听器;
  • 并执行attach方法
    private void attach(FlutterNativeView view, boolean isBackgroundView) {
        this.mFlutterJNI.attachToNative(isBackgroundView);
        this.dartExecutor.onAttachedToJNI();
    }
  @UiThread
    public void attachToNative(boolean isBackgroundView) {
        this.ensureRunningOnMainThread();
        this.ensureNotAttachedToNative();
        this.nativePlatformViewId = this.nativeAttach(this, isBackgroundView);
    }

上面两个函数执行之后,将执行 jni 层方法,进而将执行底层代码,进行 Flutter 引擎的初始化和启动操作。

当 Flutter引擎和 Dart Vm 等初始化完成之后,代码将会执行到 FlutterActivityDelegate 中的 runBundle 方法。

4.4 runBundle

    private void runBundle(String appBundlePath) {
        if (!this.flutterView.getFlutterNativeView().isApplicationRunning()) {
            FlutterRunArguments args = new FlutterRunArguments();
            args.bundlePath = appBundlePath;
            args.entrypoint = "main";
            this.flutterView.runFromBundle(args);
        }

    }

主要是创建 FlutterRunArguments 对象,指定入口函数名称为 "main",接着执行 FlutterView 中的 runFromBundle 方法。


    public void runFromBundle(FlutterRunArguments args) {
        this.assertAttached();
        this.preRun();
        this.mNativeView.runFromBundle(args);
        this.postRun();
    }
    
        public void runFromBundle(FlutterRunArguments args) {
        if (args.entrypoint == null) {
            throw new AssertionError("An entrypoint must be specified");
        } else {
            this.assertAttached();
            if (this.applicationIsRunning) {
                throw new AssertionError("This Flutter engine instance is already running an application");
            } else {
                this.mFlutterJNI.runBundleAndSnapshotFromLibrary(args.bundlePath, args.entrypoint, args.libraryPath, this.mContext.getResources().getAssets());
                this.applicationIsRunning = true;
            }
        }
    }

在 runFromBundle 中,主要是进一步调用了 jni 层的方法,调用的时候,指定了函数名称,库路径,资源文件等。

  @UiThread
    public void runBundleAndSnapshotFromLibrary(@NonNull String bundlePath, @Nullable String entrypointFunctionName, @Nullable String pathToEntrypointFunction, @NonNull AssetManager assetManager) {
        this.ensureRunningOnMainThread();
        this.ensureAttachedToNative();
        this.nativeRunBundleAndSnapshotFromLibrary(this.nativePlatformViewId, bundlePath, entrypointFunctionName, pathToEntrypointFunction, assetManager);
    }

接着将调用底层方法:

    private native void nativeRunBundleAndSnapshotFromLibrary(long var1, @NonNull String var3, @Nullable String var4, @Nullable String var5, @NonNull AssetManager var6);

底层方法经过一系列方法的调用,将会执行到 Dart 中的 main 函数,也就是将会运行到我们写的 Dart 代码。

整个过程如下图所示。

欢迎关注「Flutter 编程开发」微信公众号 。