插件化实现一

通过安装应用的方式实现app插件化

重要提醒:这种方式实现的插件化,需要在插件应用和主应用的manifest.xml中添加一个sharedUserId属性,并且属性值都要相同

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.eyesee.loaddex"
    android:sharedUserId="@string/sharedUserId">
1,javabean对象,保存查到的插件apk信息
public class PluginBean {
    private String pkgLabel = "";
    private String pkgName = "";

    public PluginBean(String label,String name){
        pkgLabel = label;
        pkgName = name;
    }

    public String getPkgLabel() {
        return pkgLabel;
    }

    public void setPkgLabel(String pkgLabel) {
        this.pkgLabel = pkgLabel;
    }

    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PluginBean that = (PluginBean) o;
        return Objects.equals(pkgLabel, that.pkgLabel) &&
                Objects.equals(pkgName, that.pkgName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(pkgLabel, pkgName);
    }

    @Override
    public String toString() {
        return "PluginBean{" +
                "pkgLabel='" + pkgLabel + '\'' +
                ", pkgName='" + pkgName + '\'' +
                '}';
    }
}
2.查找插件apk信息,获取插件apk中资源文件的class对象
public class PackageUtils {

    /**
     * 查找手机内所有的插件
     * @return 返回一个插件list
     */
    public static List<PluginBean> findAllPlugin(Context context){
        List<PluginBean> plugins = new ArrayList<>();
        PackageManager pm = context.getPackageManager();
        List<PackageInfo> packageInfos = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
        for (PackageInfo packageInfo : packageInfos) {
            //apk包名
            String pkgName = packageInfo.packageName;
            //apk的sharedUserId
            String sharedUserId = packageInfo.sharedUserId;
            //判断apk是否为插件应用,通过sharedUserId,应用包名
            if(sharedUserId != null && sharedUserId.equals(context.getResources().getString(R.string.sharedUserId))
                    && !pkgName.equals(context.getPackageName())){
                //插件apk名称
                String label = pm.getApplicationLabel(packageInfo.applicationInfo).toString();
                PluginBean bean = new PluginBean(label,pkgName);
                plugins.add(bean);
            }
        }
        return plugins;
    }

    /**
     * 加载已安装的apk
     * @param pkgName 插件应用包名
     * @param pluginContext 插件应用上下文
     * @return 对应资源的ID
     */
    public static int dynamicLoadApk(String pkgName,Context pluginContext) throws Exception{

        //第一个参数为包含dex的apk或jar的路径,第二个参数为父加载器
        PathClassLoader pathClassLoader = new PathClassLoader(pluginContext.getPackageResourcePath(),ClassLoader.getSystemClassLoader());

        //方法一,通过自身的加载器反射出mipmap类,进而使用该类的资源
        //Class<?> clazz = pathClassLoader.loadClass(pkgName+".R$mipmap");
        //方法二 参数:1,类的全类名 2,是否初始化类 3,加载时使用的类加载器
        Class<?> clazz = Class.forName(pkgName+".R$mipmap",true,pathClassLoader);

        //得到插件apk中内部类mipmap,通过它得到资源ID,查找资源中名称one的图片资源
        Field field = clazz.getDeclaredField("one");
        int resourceId = field.getInt(R.mipmap.class);
        return resourceId;
    }

    /**
     * 图片资源的ID
     */
    public static Class<?> getMipmapClazz(String pkgName,Context pluginContext) throws Exception{

        //第一个参数为包含dex的apk或jar的路径,第二个参数为父加载器
        PathClassLoader pathClassLoader = new PathClassLoader(pluginContext.getPackageResourcePath(),ClassLoader.getSystemClassLoader());

        //方法一,通过自身的加载器反射出mipmap类,进而使用该类的资源
        //Class<?> clazz = pathClassLoader.loadClass(pkgName+".R$mipmap");
        //方法二 参数:1,类的全类名 2,是否初始化类 3,加载时使用的类加载器
        Class<?> clazz = Class.forName(pkgName+".R$mipmap",true,pathClassLoader);
        return clazz;
    }

    /**
     * string字符串资源ID
     * */
    public static Class<?> getStringClazz(String pkgName,Context pluginContext) throws Exception{

        //第一个参数为包含dex的apk或jar的路径,第二个参数为父加载器
        PathClassLoader pathClassLoader = new PathClassLoader(pluginContext.getPackageResourcePath(),ClassLoader.getSystemClassLoader());

        //方法一,通过自身的加载器反射出mipmap类,进而使用该类的资源
        //Class<?> clazz = pathClassLoader.loadClass(pkgName+".R$mipmap");
        //方法二 参数:1,类的全类名 2,是否初始化类 3,加载时使用的类加载器
        Class<?> clazz = Class.forName(pkgName+".R$string",true,pathClassLoader);
        return clazz;
    }
}
3.使用插件中的资源
private void checkLoadApk(Context context) {
    List<PluginBean> allPlugin = PackageUtils.findAllPlugin(context);
    if(allPlugin != null && !allPlugin.isEmpty()){
        for (PluginBean bean : allPlugin) {
            HashMap<String,String> map = new HashMap<>();
            //包名
            map.put("pkgName",bean.getPkgName());
            datas.add(map);
        }
        resource(datas,context);
    } else {
        Toast.makeText(context,"没有找到插件,请先下载",Toast.LENGTH_SHORT).show();;
    }
}

private void resource(List<HashMap<String, String>> datas,Context context) {
    String pkgName = "";
    if(!datas.isEmpty()){
        for (HashMap<String, String> data : datas) {
            pkgName = data.get("pkgName");
        }
    }

    //为插件app创建一个上下文,仅适合获取已经安装的插件apk
    try {
        Context pluginContext = context.createPackageContext(pkgName, CONTEXT_IGNORE_SECURITY | CONTEXT_INCLUDE_CODE);
        int id = PackageUtils.dynamicLoadApk(pkgName, pluginContext);
        drawable = pluginContext.getResources().getDrawable(id);

        Class<?> stringClazz = PackageUtils.getStringClazz(pkgName, pluginContext);
        //得到插件apk中内部类mipmap,通过它得到资源ID
        Field field1 = stringClazz.getDeclaredField("text1");
        Field field2 = stringClazz.getDeclaredField("text2");
        Field field3 = stringClazz.getDeclaredField("text3");

        int resourceId1 = field1.getInt(R.string.class);
        int resourceId2 = field2.getInt(R.string.class);
        int resourceId3 = field3.getInt(R.string.class);

        text_1 = pluginContext.getResources().getString(resourceId1);
        text_2 = pluginContext.getResources().getString(resourceId2);
        text_3 = pluginContext.getResources().getString(resourceId3);

    }catch (Exception e){
        e.printStackTrace();
        Log.d("cai",e.getMessage());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值