Flutter提供了獨立的運行環境Flutter.so做爲Dart代碼的運行環境和控制邏輯,完整的UI框架彙總邏輯和dartVM都是封裝在flutter.so庫中,在Android中開發完成以後,系統會打包到Asset目錄下,安裝成功以後,會抽取Asset文件夾下的Dart相關文件到Android安裝包的環境中,進行加載執行,最終把FlutterUI相關的界面彙總在Android端提供的SurfaceView中進行渲染,開始分析Flutter相關文件在android的加載流程java
Flutter Engine編譯完成以後會生成一個FlutterJar
包,提供給Android和Flutter代碼交互的過程 android
Flutter代碼在Android端代碼啓動時,是如何加載相關的Dart代碼,進行執行,最終在手機端是如何顯示出來的c++
!!! info "Android初始化過程"shell
* 1.Android Application啓動
* 2.FlutterMain類初始化Flutter相關的文件,請查看flutter的Apk包中的文件結構
* 3.抽取Apk包中的Flutter相關的資源
* 4.System.loadLibrary(「flutter」)加載`libflutter.so` 引擎文件
* 5.JNI第一次加載so庫時,會自動調用JNI_OnLoad方法,關聯Flutter java平臺代碼到JNI中
* 6.在FlutterMain.cc中調用`Init()`初始化在java端抽取的flutter代碼,把相關的文件路徑傳遞到JNI中,進行初始化,JNI層能夠讀取的文件路徑
複製代碼
!!! info "STEP"緩存
* 1.Application中調用FlutterMain.startInitialization(this);
* 2.初始化配置文件的路徑和文件名配置,方便讀取不一樣位置的flutter文件
* 3.抽取Aot優化過的代碼
* 4.加載資源文件到資源查找路徑中
* 5.加載so庫:System.loadLibrary("flutter");
* 6.FlutterActivity:對View、事件一系列動做的初始化
複製代碼
android應用啓動Application初始化Dart相關的代碼 Android項目下打包完成以後,抽取Flutter.jar下的libFlutter.so文件在lib文件夾下,資源文件和虛擬機和相關的配置文件到lib下,這一步文件仍是今天加載的文件。安裝App成功以後,App第一次啓動會判斷時間戳來判斷當前的文件是否須要再次抽取到Android的目錄文件夾下。app
public class FlutterApplication extends Application {
private Activity mCurrentActivity = null;
public FlutterApplication() {
}
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}
public Activity getCurrentActivity() {
return this.mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity) {
this.mCurrentActivity = mCurrentActivity;
}
}
複製代碼
flutter在apk中的文件須要加載纔可以運行dart代碼框架
1.初始化配置文件 2.抽象相關的代碼Apk包Asset目錄中的數據抽取到apk包下的目錄中 3.System.loadLibrary("flutter");初始化so庫async
public void startInitialization(@NonNull Context applicationContext, @NonNull FlutterLoader.Settings settings) {
if (this.settings == null) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
} else {
this.settings = settings;
long initStartTimestampMillis = SystemClock.uptimeMillis();
this.initConfig(applicationContext);
this.initResources(applicationContext);
System.loadLibrary("flutter");
VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService("window")).init();
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
}
}
}
複製代碼
初始化配置文件,在apk包安裝到手機以後,在apk的目錄下能夠找,初始化查找的路徑函數
private void initConfig(@NonNull Context applicationContext) {
Bundle metadata = this.getApplicationInfo(applicationContext).metaData;
if (metadata != null) {
this.aotSharedLibraryName = metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, "libapp.so");
this.flutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, "flutter_assets");
this.vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, "vm_snapshot_data");
this.isolateSnapshotData = metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, "isolate_snapshot_data");
}
}
複製代碼
apk是一個文件壓縮包,flutter代碼發在apk包中的Assert中,須要出去出來發在apk的安裝目錄中,經過ExtractTask
類解析抽取,AssetManager
管理器能夠抽取出相關的Flutter代碼,會根據目錄下的時間戳文件來判斷文件是否已經被抽取過res_timestamp
oop
private 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();
this.resourceExtractor = new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
this.resourceExtractor.addResource(this.fullAssetPathFrom(this.vmSnapshotData)).addResource(this.fullAssetPathFrom(this.isolateSnapshotData)).addResource(this.fullAssetPathFrom("kernel_blob.bin"));
this.resourceExtractor.start();
}
複製代碼
到目前爲止只是android在啓動時進行靜態的加載數據,相關的文件已經添加到Android目錄文件夾下。
1.在主線程中初始化Flutter文件的安裝路徑 2.FlutterLoader
主要負責抽取Flutter的相關文件到從apk包中的asset文件夾下抽取到安裝目錄文件下
FlutterEngine是一個so庫,只有加載到Java的執行路徑中才能初始化Dart虛擬機,提供Dart運行的環境,在接下來的文章中將一些分析FlutterEngine初始化過程,在Android中Application啓動完成,已經初始化進程以後,就能夠開啓Activity,在清單文件中配置的啓動Activity類繼承了FlutterActivity
1.初始化Androidwindow屬性,提供一個全屏狀態個Flutter來使用 2.等待Flutter引擎初始化完成 3.createFlutterView 提供給開發者本身定義Flutter SurfaceView的機制 4.若是createFlutterView
用戶沒有定製,那麼使用系統默認的SurfaceView 5.FlutterView
提供了面向用戶操做的類,FlutterNativeView
提供了Android代碼和Flutter的互操做機制 6.調用setContentView
添加SurfaceView 7.添加第一幀到系統,能夠避免Flutter初始化的時候出現白屏現象
通過上面的初始化過程,已經初始化完成UI界面,可是還有Flutter.so文件的加載工做尚未完成
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());
加載flutter.so庫,經過FlutterJNI.nativeInit方法
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);
}
}
}
複製代碼
FlutterView初始化時須要加載Flutter相關的資源
1.初始化FlutterNativeView
監聽Flutter.so
庫的事件監聽,加載,卸載so庫的事件 FlutterPluginRegistry
:註冊系統層級的插件管理對象 DartExecutor
:真正的管理FlutterAndroid側的插件綁定及解綁定,事件級別的的處理 FlutterJNI
:監聽Flutter側回調Android端的代碼邏輯,so庫層級的事件處理 FlutterUiDisplayListener
:Flutter初始化完成以後會回到到Android端的UI改變監聽 2.
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 = this.mNativeView.getFlutterJNI().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();
}
}
複製代碼
在Android端進行SurfaceView進行初始化時,SurfaceView的回到函數中,經過FlutterJNI
類中的本地方法和JNI層中的方法進行綁定,FlutterEngine在進行Flutter的渲染時,就能夠傳遞相關的Surface給Android平臺進行渲染顯示
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();
}
};
複製代碼
調用Flutter for android 庫初始化Flutter相關的文件
1.FlutterMain.startInitialization(this);
2.System.loadLibrary('flutter')
加載so
在engine中調用engine/src/flutter/shell/platform/android/library_loader.cc,JNI中的代碼初始化:
!!! info "主要完成三件事"
* 1.初始化FlutterMain做爲JNI層回調的類
* 2.初始化平臺事件的處理類
* 3.初始化UI繪製Sync信號的傳遞
複製代碼
在Flutter.jar初始化時,調用System.loadLibrary 查找解壓出來的Flutter.so文件,調用dlopen打開打開so庫,加載C++相關的資源,加載完成後調用JNI_OnLoad,具體調用過程參考下圖,當調用JNI_OnLoad
完成後so庫以及提供了能夠運行的函數,接下來就是初始化Flutter相關的代碼和業務邏輯
JNI中對應相關的類進行初始化
第一次加載so庫時,調用當前的方法,完成一下三件事:
註冊Java層代碼到JNI層,方便後續的回調Java層代碼
engine/src/flutter/shell/platform/android/flutter_main.cc
/src/flutter/shell/platform/android/io/flutter/view/FlutterView.java
初始化相關的平臺View的事件處理邏輯
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// Initialize the Java VM.
fml::jni::InitJavaVM(vm);
JNIEnv* env = fml::jni::AttachCurrentThread();
bool result = false;
// Register FlutterMain.
result = shell::FlutterMain::Register(env);
FML_CHECK(result);
// Register PlatformView
// 處理平臺的UI/事件相關的內容,生命週期的管理,後臺執行
result = shell::PlatformViewAndroid::Register(env);
FML_CHECK(result);
// Register VSyncWaiter.
// 真正處理相關的UI繪製事件
result = shell::VsyncWaiterAndroid::Register(env);
FML_CHECK(result);
return JNI_VERSION_1_4;
}
複製代碼
在library_loader庫中進行組成,編譯engine回調java成代碼
bool FlutterMain::Register(JNIEnv* env) {
static const JNINativeMethod methods[] = {
{
.name = "nativeInit",
.signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
"lang/String;Ljava/lang/String;Ljava/lang/String;)V",
.fnPtr = reinterpret_cast<void*>(&Init),
},
{
.name = "nativeRecordStartTimestamp",
.signature = "(J)V",
.fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
},
};
jclass clazz = env->FindClass("io/flutter/view/FlutterMain");
if (clazz == nullptr) {
return false;
}
return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
}
複製代碼
result = shell::PlatformViewAndroid::Register(env);對應java層事件的處理 /engine/src/flutter/shell/platform/android/platform_view_android.h
class PlatformViewAndroid final : public PlatformView {
<!-- 沒有對Register進行初始化 -->
public:
static bool Register(JNIEnv* env);
複製代碼
VsyncWaiterAndroid::Register(env);處理相關的frame rate問題,同步平臺層的事件和dart UI的事件更新,JNI回調Java層的代碼io/flutter/view/VsyncWaiter
,Android平臺層對幀率的控制使用的類:android.view.Choreographer
// 對應flutter for android 庫中的:io.flutter.view.VsyncWaiter
//
bool VsyncWaiterAndroid::Register(JNIEnv* env) {
static const JNINativeMethod methods[] = {{
.name = "nativeOnVsync",
.signature = "(JJJ)V",
.fnPtr = reinterpret_cast<void*>(&OnNativeVsync),
}};
jclass clazz = env->FindClass("io/flutter/view/VsyncWaiter");
if (clazz == nullptr) {
return false;
}
g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);
FML_CHECK(!g_vsync_waiter_class->is_null());
g_async_wait_for_vsync_method_ = env->GetStaticMethodID(
g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V");
FML_CHECK(g_async_wait_for_vsync_method_ != nullptr);
return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
}
複製代碼
apk中文件抽取完成以後處理初始化JNI中的代碼,加載flutter相關的文件代碼,io/flutter/view/FlutterMain.class ,nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);
,初始化完成以後十里河
nativeInit() 在Java層能夠使用相關的命令傳遞相關的參數 Java層中apk文件抽取完成後初始化參數信息, 主要是傳遞相關的初始化參數到JNI層,方便加載相關的文件 初始化Flutter路徑信息
void FlutterMain::Init(JNIEnv* env,
jclass clazz,
jobject context,
jobjectArray jargs,
jstring bundlePath,
jstring appStoragePath,
jstring engineCachesPath) {
std::vector<std::string> args;
args.push_back("flutter");
for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
args.push_back(std::move(arg));
}
// 初始化命令行參數
auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());
auto settings = SettingsFromCommandLine(command_line);
// 初始化資源目錄結構
settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);
// Restore the callback cache.
// TODO(chinmaygarde): Route all cache file access through FML and remove this
// setter.
// 設置緩存目錄
blink::DartCallbackCache::SetCachePath(
fml::jni::JavaStringToString(env, appStoragePath));
// 初始化Android緩存目錄
fml::paths::InitializeAndroidCachesPath(
fml::jni::JavaStringToString(env, engineCachesPath));
// 從磁盤加載緩存數據
blink::DartCallbackCache::LoadCacheFromDisk();
// 如何運行時配置文件路徑
if (!blink::DartVM::IsRunningPrecompiledCode()) {
// Check to see if the appropriate kernel files are present and configure
// settings accordingly.
auto application_kernel_path =
fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"});
if (fml::IsFile(application_kernel_path)) {
settings.application_kernel_asset = application_kernel_path;
}
}
// 添加回調進入消息隊列
settings.task_observer_add = [](intptr_t key, fml::closure callback) {
fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
};
// 移除消息隊列
settings.task_observer_remove = [](intptr_t key) {
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
};
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
// There are no ownership concerns here as all mappings are owned by the
// embedder and not the engine.
auto make_mapping_callback = [](const uint8_t* mapping, size_t size) {
return [mapping, size]() {
return std::make_unique<fml::NonOwnedMapping>(mapping, size);
};
};
settings.dart_library_sources_kernel =
make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize);
#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
// Not thread safe. Will be removed when FlutterMain is refactored to no
// longer be a singleton.
g_flutter_main.reset(new FlutterMain(std::move(settings)));
}
複製代碼
執行到這個地方,Apk中的文件已經抽取完成,回調方法,回調事件已經完成,路徑的初始化信息已經初始化
經過上面的分析,已經初始化完成Flutter和Android的調用邏輯,經過上面的分析,總結一下Flutter初始化的大概邏輯
1.App啓動,在Application中調用FlutterMain
中的startInitialization
方法,完成路徑的配置,flutter代碼的抽取,加載Flutter.so庫
2.開始初始化Activity中的UI界面和綁定Android和Flutter通訊,回調等一系列的操做FlutterActivityDelegate
中完成
3.在``中調用nativeInit
方法初始化Flutter.so
庫進行DartVM的初始化操做
4.Flutter.so
庫加載時調用JNI_OnLoad
方法中初始化FlutterMain
做爲Android端的調用入口
5.初始化PlatformViewAndroid
,Android端和FlutterView通訊交互的入口
6.Flutter.so初始化完成Engine相關的資源以後,在FlutterLoader.class
中調用nativeInit
方法初始化
7.經過FlutterJNI
中的nativeAttach
方法初始化Flutter.so
開始綁定Android端和Flutter相關的事件回調
8.在Android端進行SurfaceView進行初始化時,SurfaceView的回到函數Callback
中,經過FlutterJNI
類中的本地方法和JNI層中的方法進行綁定,FlutterEngine在進行Flutter的渲染時,就能夠傳遞相關的Surface給Android平臺進行渲染顯示
至此,Android端啓動、加載Flutter資源、初始化FlutterEngine,綁定SurfaceView和FlutterEngine引擎的對象,註冊系統級別的插件功能,已經初始化完成,下一篇中咱們將,分析FlutterEngine引擎是怎麼初始化的,畢竟要在手機上看到Flutter引擎代碼的顯示