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引擎代码的显示