這篇文章主要是分析一下 Flutter Android 端的啓動流程,主要是上層代碼的分析,不涉及底層 c/c++ 等的分析。同時,不一樣 Flutter 版本的 sdk ,代碼也會有所不一樣,可是總體流程和原理不會有太大的不一樣。android
Android 端 app 的啓動,必定會先初始化 Application,再去加載默認的第一個類 MainActivity。Flutter 項目對應的 Android 端應用程序,application 默認指定爲 FlutterApplication。c++
<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>
複製代碼
FlutterApplication 中 onCreate 核心初始化代碼只有一行shell
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);
}
}
}
複製代碼
主要作了以下幾件事情:緩存
這個方法以下:bash
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 初始化默認配置,若是沒有設置則使用默認值。微信
代碼以下:app
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();
}
複製代碼
主要的做用就兩個:ide
上面就是 Application 的初始化過程。接下來看 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。
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 。
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。
public final class FlutterActivityDelegate implements FlutterActivityEvents, Provider, PluginRegistry
複製代碼
這個類經過 final 修飾,將不能被繼承,同時確實也實現了三個接口。
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 是這個類初始化以後執行的第一個函數,主要的做用是:
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 模式下的代碼,主要的做用是:
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 兩個接口。
主要的做用:
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();
}
...
}
複製代碼
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 方法。
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 編程開發」微信公衆號 。