安卓热修篇-Shadow思想篇-插桩式插件化

目录

 

简介

市面上实现插件化的方式大体可分为两种,一种是hook方式,一种是插桩式。其中hook方式,因为需要hook系统API,随着系统API的变化需要不断做适配。因此插件化方案未来趋势,我更看好代理方式实现的方案

 

大概步骤

  • 设计标准
  • 开发插件时遵循这个标准
  • 宿主使用自定义的ClassLoader,Resources准备加载插件的环境
  • 在宿主的清单文件用一个空的Activity插桩,加载插件Activity

 

实现案例

设计标准(可作为一个独立的module,因为宿主和插件需要同一套标准)

public interface IActivityInterface {
    public void setAppContext(Activity activity);

    public void onCreate(Bundle bundle);

    public void setContentView(int layoutId);
}

开发插件遵循这套标准(注意,以下只截取了代码片段)

public class BaseActivity implements IActivityInterface {

    private Activity mActivity;

    @Override
    public void setAppContext(Activity activity) {
        Log.i("我是插件", "setAppContext");
        mActivity = activity;
    }

    @Override
    public void onCreate(Bundle bundle) {
        Log.i("我是插件", "onCreate");
    }

    @Override
    public void setContentView(int layoutId) {
        Log.i("我是插件", "setContentView");
        mActivity.setContentView(layoutId);
    }
}
public class PluMainActivity extends BaseActivity {

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_plu);
    }

}

宿主使用自定义的ClassLoader,Resources准备加载插件的环境

  • 1)ClassLoader的处理

Android中的ClassLoader类加载器派生出的有DexClassLoader和PathClassLoader。这两者的区别是

DexClassLoader: 能够加载未安装的jar/apk/dex

PathClassLoader: 只能加载系统中已经安装的apk

同时,由于虚拟机在安装期间会为类打上CLASS_ISPREVERIFIED标志,当满足以下条件时:

在类加载时,由于ClassLoader的双亲委托机制,加载时如果加载了插件中的类了,那么宿主的类便不会再加载而会使用插件的,反之对插件也是一样。这就很容易触发上述所说的verify的问题,从而报出异常“java.lang.IllegalAccessError: Class ref in pre-verified class...”

如何避免?

可以通过自定义ClassLoader修改类加载逻辑,使得插件和宿主中的类隔离,各自加载。

各自加载的好处:插件和宿主依赖的通用模块无需特殊处理。

package com.sq.a37syplu10.plugin.loader;

import android.os.Build;

import dalvik.system.DexClassLoader;

public class ApkClassLoader extends DexClassLoader {

    private ClassLoader mGrandParent;
    private final String[] mInterfacePackageNames;

    public ApkClassLoader(String dexPath,
                          String optimizedDirectory,
                          String librarySearchPath,
                          ClassLoader parent,
                          String[] interfacePackageNames) {

        super(dexPath, optimizedDirectory, librarySearchPath, parent);

        ClassLoader grand = parent;
        mGrandParent = grand.getParent();
        this.mInterfacePackageNames = interfacePackageNames;
    }

    @Override
    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
        String packageName;
        int dot
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值