Android动态加载—Res文件

简介

动态加载res文件,就是将资源文件打包进一个统一的apk,而在我们的app安装后通过后台下载,然后再写到我们的应用中,将这个含有资源的apk,可以称为插件apk,而我们的app,可以称为宿主apk,在宿主中加载插件中的资源文件的方法。


介绍

  1. 下载
  2. 加载
  3. 获取资源文件

对于下载可以参考上一篇so文件的下载,没什么要说的,加载是从你的sdcard目录下复制到你的应用目录下例如:data/data/包名/app_dex目录下面,代码参考so文件的复制。

将apk复制到指定的目录后,就是获取其里面的资源了,而获取一个应用的资源,我么首先要知道这个资源对应的id是多少,而对于插件来说,它里面的资源id我们是不知道的,但是资源的name确实我们开发者定的,所有我们可以通过资源的name来获取id,方法是系统API : Resources.getIdentifier()

    public int getIdentifier(String name, String defType, String defPackage) {
        if (name == null) {
            throw new NullPointerException("name is null");
        }
        try {
            return Integer.parseInt(name);
        } catch (Exception e) {
            // Ignore
        }
        return mAssets.getResourceIdentifier(name, defType, defPackage);
    }

好了,拿到了资源id,我们就可以应用到我们需要的地方了。但是,在运行的时候你会发现获取的id是0,这是因为你用的Resources是宿主的resources,在宿主里面并没有找到你name所对应的id。所以,我们还需要创建一个插件所拥有的resources,让app拥有两个resources对象,当加载插件资源的时候用插件的resources

 protected void loadResources(File tmpDir) {
        try {
            File[] currentFiles=tmpDir.listFiles();
            String path;
            if (currentFiles == null || currentFiles.length == 0) {
                path = DuduUtil.resApkPath;
            } else {
                path = currentFiles[0].getAbsolutePath();
            }
            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPath = assetManager.getClass().getMethod(
                    "addAssetPath", String.class);//通过methodName和参数的数据类型得到要执行的Method。
            addAssetPath.invoke(assetManager, path);//assetManager对象中带有参数path的addAssetPath方法。返回值是Object,也既是该方法的返回值
            mAssetManager = assetManager;
        } catch (Exception e) {
            e.printStackTrace();
        }
        Resources superRes = super.getResources();
        mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),
                superRes.getConfiguration());
    }

解释一下反射的两个方法的意思:

  • getMethod
 public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
        return getMethod(name, parameterTypes, true);
    }

@param name
* the requested method’s name.
* @param parameterTypes
* the parameter types of the requested method.
* {@code (Class[]) null} is equivalent to the empty array.

Method字面理解方法的意思,getMethod参数的意思,name:方法的名字;parameterTypes方法参数的类型,获取assetManager对象里面名字为addAssetPath,参数类似为String的方法,即:

 public final int addAssetPath(String path) {
        synchronized (this) {
            int res = addAssetPathNative(path);
            makeStringBlocks(mStringBlocks);
            return res;
        }
    }
  • invoke
 @param receiver
          the object on which to call this method (or null for static methods)
 @param args
          the arguments to the method
 public native Object invoke(Object receiver, Object... args)
            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;

invoke字面理解:调用。receiver调用反射处理的method,参数是args

至此,插件apk的resources已经拿到,然后再通过name拿到id,但是拿到id之后并不能直接使用,因为我们之前直接setxxx(id)的时候,实在方法里面转换成了相应的资源,所以,还需要我们把插件的资源转换成向对应的资源

demo:https://github.com/fayou147/DyLoadResDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值