ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Flutter Android 端 FlutterInjector 及依赖流程源码分析

2022-01-31 15:00:04  阅读:253  来源: 互联网

标签:FlutterInjector String Flutter 步骤 flutterApplicationInfo public 源码 Android Resou


}

//步骤4、获取DeferredComponentManager实例,不分析,该特性在配合GP市场使用。

public DeferredComponentManager deferredComponentManager() {

return deferredComponentManager;

}

//步骤5、常规的构造器模式。

public static final class Builder {

private FlutterLoader flutterLoader;

private DeferredComponentManager deferredComponentManager;

//…

private void fillDefaults() {

if (flutterLoader == null) {

//步骤6、实例化一个FlutterLoader。

flutterLoader = new FlutterLoader();

}

// DeferredComponentManager’s intended default is null.

}

public FlutterInjector build() {

fillDefaults();

return new FlutterInjector(flutterLoader, deferredComponentManager);

}

}

}

可以看到,FlutterInjector 看起来只是一个全局单例的注入管理类角色,其核心还在于 FlutterInjector 和 DeferredComponentManager,由于我们不是海外市场,所以暂时不分析 DeferredComponentManager 特性,着重关注通用的 FlutterInjector 机制。

FlutterLoader 相关分析


正如其注释说的,这个类的职责是在应用 APK 中查找 Flutter 资源并加载 Flutter 原生库。源码如下:

public class FlutterLoader {

//…

//步骤7、创建实例,传递FlutterJNI实例,下一小节分析FlutterJNI。

public FlutterLoader() {

this(new FlutterJNI());

}

public FlutterLoader(@NonNull FlutterJNI flutterJNI) {

this.flutterJNI = flutterJNI;

}

//…

//步骤8、初始化结果结构体。

private static class InitResult {

final String appStoragePath;

final String engineCachesPath;

final String dataDirPath;

//…

}

//步骤9、FlutterEngine实例化中调用,重要开始入口。

public void startInitialization(@NonNull Context applicationContext) {

startInitialization(applicationContext, new Settings());

}

//步骤10、加载Flutter Engine native so库,定位Dart resources在apk中的路径。

//必须在主线程调用此方法。

public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {

//…

if (Looper.myLooper() != Looper.getMainLooper()) {

throw new IllegalStateException(“startInitialization must be called on the main thread”);

}

final Context appContext = applicationContext.getApplicationContext();

this.settings = settings;

initStartTimestampMillis = SystemClock.uptimeMillis();

//步骤11、通过ApplicationInfoLoader的load获取FlutterApplicationInfo信息。

//里面主要都是flutterAssetsDir、nativeLibraryDir、aotSharedLibraryName等信息,下一小节专门分析FlutterApplicationInfo。

flutterApplicationInfo = ApplicationInfoLoader.load(appContext);

//步骤12、平台VSYNC信号相关初始化设置,下面单独小节分析。

VsyncWaiter.getInstance((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE))

.init();

//步骤13、由于需要访问磁盘,异步调用执行初始化相关东西。

Callable initTask =

new Callable() {

@Override

public InitResult call() {

//步骤14、异步调用initResources得到ResourceExtractor。

ResourceExtractor resourceExtractor = initResources(appContext);

//步骤15、通过flutterJNI调用加载框架so,即libflutter.so

flutterJNI.loadLibrary();

//步骤16、异步之上再异步先尽可能快获取默认的font manager。

Executors.newSingleThreadExecutor()

.execute(

new Runnable() {

@Override

public void run() {

flutterJNI.prefetchDefaultFontManager();

}

});

//步骤17、等待ResourceExtractor异步任务结束。

if (resourceExtractor != null) {

resourceExtractor.waitForCompletion();

}

//步骤18、返回异步执行的结果结构。

return new InitResult(

PathUtils.getFilesDir(appContext),

PathUtils.getCacheDirectory(appContext),

PathUtils.getDataDirectory(appContext));

}

};

//步骤19、通过线程池提交Callable并返回一个Future实例。

initResultFuture = Executors.newSingleThreadExecutor().submit(initTask);

}

//…

//步骤20、提取apk中assets文件为未压缩的在磁盘中,上面步骤14调用。

private ResourceExtractor initResources(@NonNull Context applicationContext) {

ResourceExtractor resourceExtractor = null;

//步骤21、如果是debug或jit模式resourceExtractor才不为空。

if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {

//步骤22、路径为context.getDir(“flutter”),也就是私有沙盒下的flutter目录。

final String dataDirPath = PathUtils.getDataDirectory(applicationContext);

//步骤23、获取apk的应用包名。

final String packageName = applicationContext.getPackageName();

final PackageManager packageManager = applicationContext.getPackageManager();

final AssetManager assetManager = applicationContext.getResources().getAssets();

//步骤24、拿着一堆apk信息和目录实例化一个ResourceExtractor供后续调用。

resourceExtractor =

new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);

//步骤25、debug及jit模式填充路径。flutterApplicationInfo来自上面步骤11实例化构建。

//默认资源路径:flutter_assets/vm_snapshot_data

//默认资源路径:flutter_assets/isolate_snapshot_data

//默认资源路径:flutter_assets/kernel_blob.bin

resourceExtractor

.addResource(fullAssetPathFrom(flutterApplicationInfo.vmSnapshotData))

.addResource(fullAssetPathFrom(flutterApplicationInfo.isolateSnapshotData))

.addResource(fullAssetPathFrom(DEFAULT_KERNEL_BLOB));

//步骤26、开始执行resourceExtractor。

resourceExtractor.start();

}

return resourceExtractor;

}

//…

}

到此初始化就异步开始了,我们需要阻塞等待他的执行结束,如下:

public class FlutterLoader {

//…

//步骤27、阻塞直到上面步骤10的startInitialization方法执行完毕。

//一般紧
挨在startInitialization方法后调用。

public void ensureInitializationComplete(

@NonNull Context applicationContext, @Nullable String[] args) {

//…

try {

//步骤28、阻塞等待上面步骤19的线程池Callable initTask执行完毕。

InitResult result = initResultFuture.get();

//步骤29、构建一堆参数供初始化使用。

List shellArgs = new ArrayList<>();

shellArgs.add("–icu-symbol-prefix=_binary_icudtl_dat");

//步30、flutterApplicationInfo在上面步骤11构建。

//路径为:[ApplicationInfo.nativeLibraryDir]/libflutter.so

shellArgs.add(

“–icu-native-lib-path=”

  • flutterApplicationInfo.nativeLibraryDir

  • File.separator

  • DEFAULT_LIBRARY);

if (args != null) {

//步31、把启动FlutterActivity或FlutterFragment时intent中传递的dartVmArgs参数加入列表。

//譬如:trace-startup=true等

Collections.addAll(shellArgs, args);

}

String kernelPath = null;

//步32、debug、jit模式设置一些参数路径啥的。

if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {

String snapshotAssetPath =

result.dataDirPath + File.separator + flutterApplicationInfo.flutterAssetsDir;

kernelPath = snapshotAssetPath + File.separator + DEFAULT_KERNEL_BLOB;

shellArgs.add("–" + SNAPSHOT_ASSET_PATH_KEY + “=” + snapshotAssetPath);

shellArgs.add("–" + VM_SNAPSHOT_DATA_KEY + “=” + flutterApplicationInfo.vmSnapshotData);

shellArgs.add(

“–” + ISOLATE_SNAPSHOT_DATA_KEY + “=” + flutterApplicationInfo.isolateSnapshotData);

} else {

//步骤33、release模式重点!!!!

//前几天还有网友微信我说想让分析flutter appso热更新,这就是核心啊,就这一句话。

//–aot-shared-library-name=缺省libapp.so,可以通过清单文件meta-data配置so的名称为自定义值,配置name为io.flutter.embedding.engine.loader.FlutterLoader.aot-shared-library-name。

shellArgs.add(

“–” + AOT_SHARED_LIBRARY_NAME + “=” + flutterApplicationInfo.aotSharedLibraryName);

//步骤34、–aot-shared-library-name再配置一个apk安装后包路径下so的全路径地址。

shellArgs.add(

“–”

  • AOT_SHARED_LIBRARY_NAME

  • “=”

  • flutterApplicationInfo.nativeLibraryDir

  • File.separator

  • flutterApplicationInfo.aotSharedLibraryName);

}

//步骤35、一堆同理的参数路径配置啥的。

shellArgs.add("–cache-dir-path=" + result.engineCachesPath);

if (flutterApplicationInfo.domainNetworkPolicy != null) {

shellArgs.add("–domain-network-policy=" + flutterApplicationInfo.domainNetworkPolicy);

}

if (settings.getLogTag() != null) {

shellArgs.add("–log-tag=" + settings.getLogTag());

}

//…

//步骤36、进行框架真正的native层代码初始化,传入我们准备的一切。

flutterJNI.init(

applicationContext,

shellArgs.toArray(new String[0]),

kernelPath,

result.appStoragePath,

result.engineCachesPath,

initTimeMillis);

initialized = true;

} catch (Exception e) {

Log.e(TAG, “Flutter initialization failed.”, e);

throw new RuntimeException(e);

}

}

//…

//步骤37、dart使用资源resources的路径。

//本质可以通过meta-data配置name为io.flutter.embedding.engine.loader.FlutterLoader.flutter-assets-dir。

//缺省为 flutter_assets。

@NonNull

public String findAppBundlePath() {

return flutterApplicationInfo.flutterAssetsDir;

}

//…

//步骤38、flutter plugin是否自动配置注册,默认是true,同样可以通过meta-data配置变更。

@NonNull

public boolean automaticallyRegisterPlugins() {

return flutterApplicationInfo.automaticallyRegisterPlugins;

}

//…

}

可以看到,FlutterLoader 在调用 ensureInitializationComplete 方法时会将编译进 apk 中的 Flutter 相关libapp.so、assets 下面资源路径等各种安卓平台路径进行拼接传递给 flutterJNI 的 init 初始化。也就是说,Flutter Engine 拿到的关于 Flutter App 的各种原始资源路径都来自安卓平台解析传递,对于 Engine 来说就是一个 File path 的概念。这也就给我们进行 File path 重定向提供了思路,带来的国内团队骚操作就是衍生出了 Flutter app.so 热更新能力。

ResourceExtractor 相关分析


ResourceExtractor 类主要通过线程池异步解析安装好的 apk 文件,释放 assets 路径下 Flutter 相关的资源,为 Flutter Engine 使用提供便利路径。

class ResourceExtractor {

//…

//步骤39、依据标准安卓系统获取支持的abi列表

private static final String[] SUPPORTED_ABIS = getSupportedAbis();

//步骤40、构造方法,在上面步骤24中被调用。

ResourceExtractor(

@NonNull String dataDirPath,
ath 重定向提供了思路,带来的国内团队骚操作就是衍生出了 Flutter app.so 热更新能力。

ResourceExtractor 相关分析


ResourceExtractor 类主要通过线程池异步解析安装好的 apk 文件,释放 assets 路径下 Flutter 相关的资源,为 Flutter Engine 使用提供便利路径。

class ResourceExtractor {

//…

//步骤39、依据标准安卓系统获取支持的abi列表

private static final String[] SUPPORTED_ABIS = getSupportedAbis();

//步骤40、构造方法,在上面步骤24中被调用。

ResourceExtractor(

@NonNull String dataDirPath,

标签:FlutterInjector,String,Flutter,步骤,flutterApplicationInfo,public,源码,Android,Resou
来源: https://blog.csdn.net/m0_66264569/article/details/122759868

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有