> 文章列表 > Android插件机制总结--类的加载

Android插件机制总结--类的加载

Android插件机制总结--类的加载

加载插件(另一个.apk或.skin文件)的资源(如:换肤)

实现步骤:所有的资源是加载通过Resource获取的,new Resource() ,核心参数是AssetManager

示例:获取插件apk里的图片资源

try {// 读取本地的一个.skin或 .apk 里面的资源Resources superRes = getResources();// 创建AssetManagerAssetManager asset = AssetManager.class.newInstance();// 添加本地下载好的插件 Method method = AssetManager.class.getDeclaredMethod("addAssetPath",String.class);// method.setAccessible(true); 如果是私有的// 反射执行方法method.invoke(asset, Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator + "app-skin.apk");Resources resource = new Resources(asset,superRes.getDisplayMetrics(),superRes.getConfiguration());// 获取资源 idint drawableId = resource.getIdentifier("img_yangmi","drawable","com.example.skin");Drawable drawable = resource.getDrawable(drawableId);mImageIv.setImageDrawable(drawable);} catch (Exception e) {e.printStackTrace();}

热修复

阿里热修复解决方案:

1.添加依赖库

implementation 'com.alipay.euler:andfix:0.5.0@aar'

2.Application中初始化并加载.apatch包

try {mPatchManager = new PatchManager(this);//获取当前应用的版本PackageManager packageManager = this.getPackageManager();PackageInfo packageInfo = packageManager.getPackageInfo(this.getPackageName(), 0);String versionName = packageInfo.versionName;mPatchManager.init(versionName);//加载apatch包mPatchManager.loadPatch();
} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();
}

3.使用命令生成拆分包:new.apk old.apk fix.apatch

4.app启动后,网络请求后台获取差分包 fix.apatch,下载到本地

File fixFile = new File(Environment.getExternalStorageDirectory(), "fix.apatch");
if (fixFile.exists()) {try {//立即生效不需要重启BaseApplication.mPatchManager.addPatch(fixFile.getAbsolutePath());Log.e(TAG, "修复成功");} catch (IOException e) {e.printStackTrace();Log.e(TAG, "修复失败");}
}

原理:加载dex文件,PATCH.MF文件(解压反编译apatch包后可以看到这个文件)中记录了被修改的类,遍历类,通过反射获取注解信息找到修改的方法,使用jni动态替换方法。

腾讯热修复Tinker的实现方案

类创建的流程:

PathClassLoader

=>BaseDexClassLoader

=>ClassLoader 变量pathList

=>PathDexList 方法findClass

=>dexElements dex或resource元素数组

=>for循环遍历,找到dex便return

实现步骤:

1. 获取已经运行的 dexElement (注意:这里是.dex文件,不是.apk)

1.1 反射获取pathList

1.2 反射获取pathList里面的dexElements

2. 获取下载好的补丁的dexElement

2.1 移动到系统能够访问的dex目录下

2.2 ClassLoader读取fixDex路径

3. 把补丁的dexElement插到 已经运行的dexElement的最前面

3.1 合并

3.2 把合并的数组注入到原来的applicationClassLoader中

插件化架构

1 启动插件apk里的activity,

采用热修复的方案,把插件apk的class加载到ApplicationClassLoader,会出现资源混乱覆盖的问题,可参考360插件的解决方案。

2 使用360开源DroidPlugin插件

GitHub - Qihoo360/DroidPlugin: A plugin framework on android,Run any third-party apk without installation, modification or repackage

增量更新

流程: 服务端生成差分包(update.patch),客户下载差分包进行合并生成新的apk版本,然后安装。

1.服务器生成差分包,供app下载;

2.访问后台接口,需不需要更新版本,如需要则下载;

3.下载完差分包之后,调用方法去合并生成新的apk;

4.校验签名,即获取本地apk的签名,与新的apk做对比;

5.安装新的apk。