国际惯例先上狗图,以防被打,看不懂的可以先看第一篇文章的源码解读。
一.通过FlutterLoader加载更新libapp.so文件完成动态化--源码解析
1.1 拷贝ApplicationInfoLoader代码,重载load方法
final class KCApplicationInfoLoader {
....
@NonNull
public static FlutterApplicationInfo load(@NonNull Context applicationContext,String path) {
ApplicationInfo appInfo = getApplicationInfo(applicationContext);
// Prior to API 23, cleartext traffic is allowed.
boolean clearTextPermitted = true;
if (android.os.Build.VERSION.SDK_INT >= 23) {
clearTextPermitted = NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted();
}
return new FlutterApplicationInfo(
path,
getString(appInfo.metaData, PUBLIC_VM_SNAPSHOT_DATA_KEY),
getString(appInfo.metaData, PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY),
getString(appInfo.metaData, PUBLIC_FLUTTER_ASSETS_DIR_KEY),
getNetworkPolicy(appInfo, applicationContext),
appInfo.nativeLibraryDir,
clearTextPermitted);
}
}
1.2 继承FlutterLoader,重写ensureInitializationComplete方法
public class KCFlutterLoader extends FlutterLoader {
private static final String TAG = "KCFlutterLoader";
private static KCFlutterLoader flutterLoaderInstance=new KCFlutterLoader();
public static KCFlutterLoader getInstance() {
return flutterLoaderInstance;
}
@Override
public void startInitialization(@NonNull Context applicationContext) {
Log.d(TAG,"KCFlutterLoader===startInitialization");
super.startInitialization(applicationContext);
}
@Override
public void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
Log.d(TAG,"KCFlutterLoader===ensureInitializationComplete");
File file=new File(applicationContext.getFilesDir(),"libappfix.so");
if(file.exists()){
String name=file.getAbsolutePath();
FlutterApplicationInfo flutterApplicationInfo = KCApplicationInfoLoader.load(applicationContext, name);
try {
Class FlutterLoaderClass = Class.forName("io.flutter.embedding.engine.loader.FlutterLoader");
Field nameField = FlutterLoaderClass.getDeclaredField("flutterApplicationInfo");
nameField.setAccessible(true);
nameField.set(this,flutterApplicationInfo);
Field initialized = FlutterLoaderClass.getDeclaredField("initialized");
initialized.setAccessible(true);
// 这里是调试方便默认设置为false,在真实情况下,这个变量应该保存在本地sp中,跟随so的变化而改变。避免重复加载,影响性能
initialized.set(this,false);
} catch (Exception e) {
e.printStackTrace();
}
}
super.ensureInitializationComplete(applicationContext, args);
}
}
1.3 注入自定义的FlutterLoader
1.3.1 纯flutter应用注入
public class MyApplication extends FlutterApplication {
public static Application application;
@Override
public void onCreate() {
//修改FlutterLoader
FlutterInjector flutterInjector = FlutterInjector.instance();
try {
Class FlutterInjectorClass = Class.forName("io.flutter.FlutterInjector");
Field nameField = FlutterInjectorClass.getDeclaredField("flutterLoader");
nameField.setAccessible(true);
nameField.set(flutterInjector,KCFlutterLoader.getInstance());
} catch (Exception e) {
e.printStackTrace();
}
super.onCreate();
application=this;
}
}
1.3.2 混合flutter应用注入
在混合应用中注入自定义的FlutterLoader相对简单,只需要在FlutterEngine初始化时将自定义FlutterLoader实例传递进去就好了:
FlutterEngine flutterEngine =new FlutterEngine(context, KCFlutterLoader.getInstance(),new FlutterJNI())
1.4 libapp.so的注意
1.libapp.so为了安全性最好下载在应用的file目录下
2.libapp.so在下载完成后可以通过生成md5值,确保文件安全性和完整性
3.如果更新的libapp.so初始化完成后,为了避免重复加载,需要设置FlutterLoader中的initialized为true(initialized变量保存到本地sp,跟随so的变化而改变)。