Android插件化

Android插件化

​ 减少安装包大小,实现app功能模块化动态扩展

发展历程

需解决三个问题

插件中代码的加载和与主工程的互相调用
插件中资源的加载和与主工程的互相访问
四大组件生命周期的管理

框架发展的三代

第一代
dynamic-load-apk:使用ProxyActivity静态代理技术由ProxyActivity去控制插件中PluginActivity的生命周期
缺点:插件中的activity必须继承PluginActivity,开发时要小心处理context,开发侵入性高

第二代
在manifest中预埋一些组件实现对四大组件的插件化。为了实现插件开发的低侵入性和稳定性,实现原理选择尽量少的hook
第三代
VirtualApp:能够实现app的免安装裕兴

动态加载apk简单案例

简单实现

//创建名为Plugin工程,并创建PluginAUtils.java文件如下,然后编译成Plugin.apk
public class PluginAUtils {
    public void showToastInfo(Context context) {
        Toast.makeText(context,"This is from pluginA",Toast.LENGTH_SHORT).show();
    }}
//创建名为PluginApp工程,在app/src/main/目录下创建asserts文件夹,并放入上述Plugin.apk文件
//创建AssertsDexLoader.java,用于动态加载Plugin工程
private static void installBundleDexs(ClassLoader loader, File dexDir, List<File> files, boolean isHotFix) throws Exception {    
    if (!files.isEmpty()) {
        if (Build.VERSION.SDK_INT >= 23) {
            V23.install(loader, files, dexDir,isHotFix);
        } else if (Build.VERSION.SDK_INT >= 19) {
            V19.install(loader, files, dexDir,isHotFix);
        } else if (Build.VERSION.SDK_INT >= 14) {
            V14.install(loader, files, dexDir,isHotFix);
        } else {
            V4.install(loader, files,isHotFix);
}}}
//通过反射,调用Plugin工程中的方法
private void runAssertsDexMethod() throws Exception {
	Class<?> clazz = Class.forName("h3c.plugina.PluginAUtils");
	//Class<?> clazz = getClassLoader().loadClass("h3c.plugina.PluginAUtils");
	Constructor<?> constructor = clazz.getConstructor();
	Object bundleUtils = constructor.newInstance();
	Method printSumMethod = clazz.getMethod("showToastInfo", Context.class);
	printSumMethod.setAccessible(true);
	printSumMethod.invoke(bundleUtils, getApplicationContext());
}

ClassLoader

​ 类加载器,负责将class文件中的类加载到内存中

​ App启动时会创建一个ClassLoader实例,将我们创建的ClassLoader挂载到App的ClassLoader下即可实现类的动态加载

AssertsDexLoader
拷贝asserts中的apk文件到系统的/data/data/appPackageDir/;再把ClassLoader拷贝的目录及文件三个参数传递给installBundleDexs()即可动态加载其方法至内存

小结

App拷贝需要读写权限
如无法找到插件APK中的类或方法,可能是插件不含对应的类或方法,或者没有将其编译到插件APK中
插件APK体积越大,加载时间越长,动态加载可在宿主需要时再加载到内存
反射调用必须按照约定的命名规范,否则会导致累或方法无法找到
Dex的加载严重依赖系统版本,需对不同版本做兼容

猜你喜欢

转载自blog.csdn.net/mLuoya/article/details/87902313