本人之前基于 Flutter SDK 1.2.0版本,做过一次动态更新。
Flutter混合开发,热修复(Android端)
随着 Google 对 Flutter 的维护,Flutter 变得越来越好了。因为官方对Flutter 不做动态更新的计划了,Flutter Release 版本的加载方式有了变化。
这里针对 Flutter SDK 1.12.13+hotfix.8 版本又做了修改;
主要做了如下修改:
1,覆盖修改 flutter.jar 里面的 FlutterLoader 类
2,为了兼容 FlutterView 的显示,覆盖修改 FlutterActivityAndFragmentDelegate,FlutterView 两个类;
3,因为 SO 加载涉及到64位问题,所以建议 SO 只放 armeabi-v7a,
并且为了防止客户端没有其他so,工程内放了一个空的32位SO(libnull.so)
原理介绍:
1,在这个版本,Flutter Release 产物,只有 libflutter.so,libapp.so,flutterAssets。
libflutter.so:是 Flutter 底层 JNI 的库;
libapp.so:是 dart 代码的产物;
flutterAssets:是图片字体等资源文件;
2,主要就是动态指定这3个产物的路径;
先看下 Flutter Engine 本身的源码:
public class FlutterLoader {
public void startInitialization(Context applicationContext, Settings settings) {
......
// 加载 libflutter.so
System.loadLibrary("flutter");
......
}
}
public class FlutterLoader {
public void ensureInitializationComplete(Context applicationContext, String[] args) {
......
// 指定 libapp.so 路径
shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + aotSharedLibraryName);
shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + applicationInfo.nativeLibraryDir + File.separator + aotSharedLibraryName);
......
}
}
// FlutterAssets 的指定,先看 dart 层怎么获取资源的。
// package:flutter/src/painting/image_resolution.dart
// AssetImage -> AssetBundleImageProvider -> PlatformAssetBundle
class PlatformAssetBundle extends CachingAssetBundle {
@override
Future<ByteData> load(String key) async {
// 通过通信 “flutter/assets”,获取资源的
final ByteData asset = await defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData());
......
return asset;
}
}
// 在 c 层找到这个消息处理
// flutter/shell/common/engine.cc
static constexpr char kAssetChannel[] = "flutter/assets";
void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move