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

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

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

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

try {
            // 读取本地的一个.skin或 .apk 里面的资源
            Resources superRes = getResources();
            // 创建AssetManager
            AssetManager 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());

            // 获取资源 id
            int 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。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值