Flutter : Flutter allows you to build beautiful native apps on iOS and Android from a single codebase. 具有跨平台, 高性能的优势.
产物流向:
通过分析我们可以发现
不变的产物有 flutter.jar ,libfluter.so,icudtl.dat, vm_snapshot_data , vm_snapshot_instr, 不跟业务代码相关, 只跟 flutter engine 的版本有关.
变化的产物: flutter_assets , isolate_snapshot_data , isolate_snapshot_instr 主要是业务的代码和资源.
LICENSE 没用, 可以删除.
总结:
我们通过将不变的产物集成到APK 中.将变化组成一个资源包,通过配置下发下来.
修改 Flutter.createView()
方法.
@NonNull public static FlutterView createView(@NonNull final Context activity, @NonNull final Lifecycle lifecycle, final String initialRoute, String bundlePath) { Context context = activity; if (!TextUtils.isEmpty(bundlePath)) { final AssetManager bundleAsset = AssetManagerUtils.newAssetManager(bundlePath); // Flutter 组件资源包位置 context = new ContextWrapper(activity) { @Override public Resources getResources() { return new Resources(bundleAsset, super.getResources().getDisplayMetrics(), super.getResources().getConfiguration()) { }; } }; } FlutterMain.startInitialization(context); // 使用自定义的 context FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), null); final FlutterNativeView nativeView = new FlutterNativeView(context);// 使用自定义的 context ... return flutterView; }
这里: 通过反射 AssetManger . 同时将 bundlePath 添加进去.
bundlePath 的作用:
FlutterNativeView.nativeRunBundleAndSnapshotFromLibrary()
传递给 Flutter 用于查找 flutter_assets 资源.Copy 资源是由 ResourceExtractor 完成的.
我们需要修改 ResourceExtractor.ExtractTask
private void extractResources() { final File dataDir = new File(PathUtils.getDataDirectory(mContext)); final AssetManager bundleManger = mContext.getResources().getAssets(); //获取 Apk 自身的 AssetsManger final AssetManager shareManager = mContext.getApplicationContext().getResources().getAssets(); final String fluterBundleVersion = getFlutterBundleVersion(bundleManger); if (fluterBundleVersion != null) { Log.i(TAG, "delete cache fluterBundleVersion " + fluterBundleVersion); deleteFiles(); } AssetManager manager; byte[] buffer = null; for (String asset : mResources) { try { final File output = new File(dataDir, asset); if (output.exists()) { continue; } if (output.getParentFile() != null) { output.getParentFile().mkdirs(); } manager = bundleManger; if (asset.startsWith("flutter_shared") || asset.equals("vm_snapshot_data") || asset.equals("vm_snapshot_instr")) { manager = shareManager; } ... } } catch (FileNotFoundException fnfe) { continue; } catch (IOException ioe) { Log.w(TAG, "Exception unpacking resources: " + ioe.getMessage()); deleteFiles(); return; } } if (fluterBundleVersion != null) { try { new File(dataDir, fluterBundleVersion).createNewFile(); } catch (IOException e) { Log.w(TAG, "Failed to write resource timestamp"); } } } private String getFlutterBundleVersion(AssetManager bundleAssets) { final File dataDir = new File(PathUtils.getDataDirectory(mContext)); String expectedTimestamp = null; try { InputStream in = bundleAssets.open("flutter_bundle_version"); expectedTimestamp = VERSION_PREFIX + IoUtils.toString(in); } catch (IOException e) { e.printStackTrace(); } if (expectedTimestamp == null) { return null; } final String[] existingTimestamps = getVersionStamps(dataDir); if (existingTimestamps == null) { return null; } if (existingTimestamps.length != 1 || !expectedTimestamp.equals(existingTimestamps[0])) { return expectedTimestamp; } return null; }
主要的修改:
需要做的事情:
MethodChannel.MethodCallHandler
进行 ABI 格式化. 即 APK 具有一样的扩展能力.相同版本才能升级.Flutter 模块 一般情况我们是以 aar 的形式依赖. 需要修改上传到 maven 的AAR 如下.