插件化 - ContentProvider加载

Android  ContentProvider 是一个SQLite数据库,分为数据提供方和数据使用方。 二者通过匿名共享内存来传输数据,数据不需要从一个地址复制到另一个地址,当数据量很大的时候,速度是非常快的。

并不是所有的数据传递都需要ContentProvider, 比如 Activity 跳转需要传递 字符串,整数之类的数据,这些数据的传递是基于Binder来实现的, Binder跨进程通信速度也很快。当要传输数据量不超过1M的时候,使用Binder; 数据量超过1M时,就需要使用ContentProvider.

ContentProvider的插件化

Android Apk 安装时,所有的ContentProvider的安装都是通过ActivityThread的installContentProvider方法实现的。可以使用该方式将插件的ContentProvider 加载进来。

具体步骤

1)将插件apk 和 宿主apk 的dex 合并起来

2)读取插件中的ContentProvider信息,借助PackageParser的parsePackage方法,然后提供generateProviderInfo 方法,把得到的Package 对象转换为ProviderInfo对象。

3)将插件ContentProvider放入宿主中,通过修改ContentProvider的packageName

4)  通过反射执行ActivityThread的installContentProviders, 将插件contentprovider 作为参数。

具体代码如下:

public static List<ProviderInfo> parseProviders(File apkFile) {
    try{
        //获取PackageParser对象实例
        Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
        Object packageParser = packageParserClass.newInstance();

        // 首先调用parsePackage获取到apk对象对应的Package对象
        Class[] p1 = {File.class, int.class};
        Object[] v1 = {apkFile, PackageManager.GET_PROVIDERS};
        Object packageObj = ReflectUtil.invokeInstanceMethod(packageParser, "parsePackage",p1, v1);

        // 读取Package对象里面的services字段
        // 接下来要做的就是根据这个List<Provider> 获取到Provider对应的ProviderInfo
        List providers = (List) ReflectUtil.getFieldObject(packageObj, "providers");

        // 调用generateProviderInfo 方法, 把PackageParser.Provider转换成ProviderInfo

        //准备generateProviderInfo方法所需要的参数
        Class<?> packageParser$ProviderClass = Class.forName("android.content.pm.PackageParser$Provider");
        Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState");
        Object defaultUserState = packageUserStateClass.newInstance();
        int userId = (Integer) ReflectUtil.invokeStaticMethod("android.os.UserHandle", "getCallingUserId",null,null);
        Class[] p2 = {packageParser$ProviderClass, int.class, packageUserStateClass, int.class};

        List<ProviderInfo> ret = new ArrayList<>();
        // 解析出intent对应的Provider组件
        for (Object provider : providers) {
            Object[] v2 = {provider, 0, defaultUserState, userId};
            ProviderInfo info = (ProviderInfo) ReflectUtil.invokeInstanceMethod(packageParser, "generateProviderInfo",p2, v2);
            ret.add(info);
        }
        return ret;
    }catch (Exception e){
        e.printStackTrace();
    }
    return null;
}

 

public static void installProviders(Context context, File apkFile){
    try{
        List<ProviderInfo> providerInfos = parseProviders(apkFile);

        for (ProviderInfo providerInfo : providerInfos) {
            providerInfo.applicationInfo.packageName = context.getPackageName();
        }

        Object currentActivityThread = ReflectUtil.getStaticFieldObject("android.app.ActivityThread", "sCurrentActivityThread");

        Class[] p1 = {Context.class, List.class};
        Object[] v1 = {context, providerInfos};

        ReflectUtil.invokeInstanceMethod(currentActivityThread, "installContentProviders", p1, v1);
    }catch (Exception e){
        e.printStackTrace();
    }

}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值