关于ClassLoader,一看你就懂,超详细java中的ClassLoader详解,android的Classloader有些不一样Android插件化开发之动态加载基础之ClassLoader工做机制前端
最经换了工做,公司的项目比较庞大,不少地方都运用了插件化,插件化说简单就是把部分功能进行打包成专门的apk、dex等文件,当宿主app须要用到此功能的时候才去加载插件;插件不只能够实现一些功能的热插拔;以及不须要去安装app,只是在使用到的状况下再去下载,这样就减少宿主的apk的体积;还能够去经过更新插件来完成功能的更新。插件化技术已经比较成熟了,不少大公司的产品也都是使用插件化开发,也有不少比较成熟的插件化框架,例如DynamicAPK、RePlugin 、Small等等java
android里面有PathClassLoader以及DexClassLoader:android
咱们能够加载其余地方的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中,便可以实现对插件资源的访问。app
具体实现时,因为AssetManager并非一个public的类,须要经过反射去建立,而且部分Rom对建立的Resource类进行了修改,因此须要考虑不一样Rom的兼容性。框架
还有一个问题就是插件的activity没有进行注册,咱们在宿主中注册一个空的Activity,专门用来加载插件app中的activity,这个Activity叫ProxyActivity。咱们还须要配置一下ProxyActivityide
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,由于插件没有上下文,须要依赖宿主的上下文源码分析
热修复也是比较热门的技术,热修复的框架也是有不少,阿里AndFix(native解决方案,不须要冷启动)、QQ空间(Dex分包方案)、美团Robust (Instant Run 热插拔原理)、微信Tinker,这些框架的原理各有不一样。tinker就是经过ClassLoader来实现热修复的原理。this
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