阅读 1862

Flutter Android 端启动流程浅析

这篇文章主要是分析一下 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 编程开发」微信公众号 。

文章分类
阅读
文章标签