从ClassLoader到Android插件化以及热更新原理

ClassLoader

关于ClassLoader,一看你就懂,超详细java中的ClassLoader详解,android的Classloader有些不同Android插件化开发之动态加载基础之ClassLoader工作机制

Android插件化

最经换了工作,公司的项目比较庞大,很多地方都运用了插件化,插件化说简单就是把部分功能进行打包成专门的apk、dex等文件,当宿主app需要用到此功能的时候才去加载插件;插件不仅可以实现一些功能的热插拔;以及不需要去安装app,只是在使用到的情况下再去下载,这样就减小宿主的apk的体积;还可以去通过更新插件来完成功能的更新。插件化技术已经比较成熟了,很多大公司的产品也都是使用插件化开发,也有很多比较成熟的插件化框架,例如DynamicAPK、RePlugin 、Small等等

插件化的原理

android里面有PathClassLoader以及DexClassLoader:

  • PathClassLoader用于加载data/app下的dex、apk、class文件,这个目录就对应了我们安装的一些应用
  • DexClassLoader可以用来加载外部的一些dex、apk、class文件

我们可以加载其他地方的dex、apk文件了,并使用相应的class文件

我们还需要获取资源文件

//创建AssetManager对象 
AssetManager assets = new AssetManager();
 //将apk路径添加到AssetManager中
  if (assets.addAssetPath(resDir) == 0){              
    return null;  
}
 //创建Resource对象

r = new Resources(assets, metrics, getConfiguration(), compInfo);
复制代码

只要将插件apk的路径加入到AssetManager中,便能够实现对插件资源的访问。

具体实现时,由于AssetManager并不是一个public的类,需要通过反射去创建,并且部分Rom对创建的Resource类进行了修改,所以需要考虑不同Rom的兼容性。

还有一个问题就是插件的activity没有进行注册,我们在宿主中注册一个空的Activity,专门用来加载插件app中的activity,这个Activity叫ProxyActivity。我们还需要配置一下ProxyActivity

class ProxyActivity : AppCompatActivity() {

    /**
     * 要跳转的activity的name
     */
    private var className = ""
    private var appInterface: AppInterface? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        /**
         * step1:得到插件app的activity的className
         */
        className = intent.getStringExtra("className")
        /**
         * step2:通过反射拿到class,
         * 但不能用以下方式
         * classLoader.loadClass(className)
         * Class.forName(className)
         * 因为插件app没有被安装!
         * 这里我们调用我们重写过多classLoader
         */
        var activityClass = classLoader.loadClass(className)
        var constructor = activityClass.getConstructor()
        var instance = constructor.newInstance()

        appInterface = instance as?AppInterface
        appInterface?.attach(this)
        var bundle = Bundle()
        appInterface?.onCreate(bundle)

    }

    override fun onStart() {
        super.onStart()
        appInterface?.onStart()
    }

    override fun onResume() {
        super.onResume()
        appInterface?.onResume()
    }

    override fun onDestroy() {
        super.onDestroy()
        appInterface?.onDestroy()
    }

    override fun getClassLoader(): ClassLoader {
        //不用系统的ClassLoader,用dexClassLoader加载
        return PluginManager.getInstance().getDexClassLoader() as? ClassLoader
                ?: super.getClassLoader()
    }

    override fun getResources(): Resources {
        //不用系统的resources,自己实现一个resources
        return PluginManager.getInstance().getResources() ?: super.getResources()
    }
}
复制代码

还有在使用context的时候,需要使用ProxyActivity的context,因为插件没有上下文,需要依赖宿主的上下文

Android热更新

热修复也是比较热门的技术,热修复的框架也是有很多,阿里AndFix(native解决方案,不需要冷启动)、QQ空间(Dex分包方案)、美团Robust (Instant Run 热插拔原理)、微信Tinker,这些框架的原理各有不同。tinker就是通过ClassLoader来实现热修复的原理。

QQ空间超级补丁,“超级补丁”很多情况下意味着补丁文件很大,而将这样一个大文件夹加载在内存中构建一个Element对象,插入到数组最前端是需要耗费时间的,无疑会印象应用启动的速度。因此Tinker 提出了另外一种思路,Tinker的思路是这样的,通过修复好的class.dex 和原有的class.dex比较差生差量包补丁文件patch.dex,在手机上这个patch.dex又会和原有的class.dex 合并生成新的文件fix_class.dex,用这个新的fix_class.dex 整体替换原有的dexPathList的中的内容,可以说是从根本上把bug给干掉了。有兴趣的同学可以看看鸿翔的这篇分析Android 热修复 Tinker 源码分析之DexDiff / DexPatch

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值