反射获取drawable等资源

做android项目打包apk时,为了尽量减少apk的大小,加入了替换资源路径功能,类似于微信混淆压缩,把资源路径和资源的名称用较短的字符串替换,这样做的好处是apk确实变小了,坏处就是一些通过资源的名字,用反射的方式来获取资源失败了,因为名字变了,所以这时候就需要添加个资源白名单的功能,里面可以填写资源的名字。我再网上找了一些通过名称反射的方式来获取 drawable 资源的方法,先看看方法一,比较繁琐


    private LoadedResource mLoadedResource;
    
    public Drawable getDrawable(String packageName, String fieldName) {
        Drawable drawable = null;
        int resourceID = getResourceID(packageName, "drawable", fieldName);
        LoadedResource installedResource = getInstalledResource(packageName);
        if (installedResource != null) {
            drawable = installedResource.resources.getDrawable(resourceID);
        }
        return drawable;
    }

    public int getResourceID(String packageName, String type, String fieldName) {

        int resID = 0;
        LoadedResource installedResource = getInstalledResource(packageName);    // 获取已安装APK的资源
        if (installedResource != null) {
            String rClassName = packageName + ".R$" + type;    // 根据匿名内部类的命名, 拼写出R文件的包名+类名
            try {
                Class cls = installedResource.classLoader.loadClass(rClassName);    //  加载R文件
                resID = (Integer) cls.getField(fieldName).get(null);    //  反射获取R文件对应资源名的ID
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
        }
        return resID;
    }

    public LoadedResource getInstalledResource(String packageName) {

        LoadedResource resource = mLoadedResource;    // 先从缓存中取, 没有就去加载

        if (resource == null) {
            try {
                Context context = mContext.createPackageContext(packageName,
                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
                resource = new LoadedResource();
                resource.packageName = packageName;
                resource.resources = context.getResources();
                resource.classLoader = context.getClassLoader();
                mLoadedResource = resource;    // 得到结果缓存起来
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return resource;
    }


    public static class LoadedResource {
        public Resources resources;
        public String packageName;
        public ClassLoader classLoader;
    }

说明,"com.test.cn" 是自己项目的包名,user_pic.png 是放在 drawable 文件里面的图片,调用下面的方法,给 ImageView 设置图片:

    imageView.setImageDrawable(getDrawable("com.test.cn", "user_pic"));

方法二,比较简单粗暴,没那么多步骤:

    private int getResidByReflect(String packageName, String imageName){
        try {
            Field field = Class.forName(packageName + ".R$drawable").getField(imageName);
            int resid = field.getInt(field);
            return resid;
        } catch (Exception e) {
            return -1;
        }
    }

    imageView.setBackgroundResource(getResidByReflect("com.test.cn","user_pic"));

方法一获取的是 Drawable 类型,方法二获取的是资源id,传入的参数是一样的。

还有中获取图片的方式,借用阿里百川sdk中的代码,示例如下 

public class ResourceUtils {

    public ResourceUtils() {
    }

    public static String getString(Context var0, String var1) {
        return var0.getResources().getString(getIdentifier(var0, "string", var1));
    }

    public static int getRLayout(Context var0, String var1) {
        return getIdentifier(var0, "layout", var1);
    }

   public static int getRDrawable(Context var0, String var1) {
        return getIdentifier(var0, "drawable", var1);
    }

    public static int getRId(Context var0, String var1) {
        return getIdentifier(var0, "id", var1);
    }

    public static float getDimen(Context var0, String var1) {
        return getIdentifier(var0, "dimen", var1); 
    }
    
    public static int getIdentifier(Context var0, String var1, String var2) {
        return var0.getResources().getIdentifier(var2, var1, var0.getPackageName());
    }
}

为什么介绍这个呢?是因为以前项目中接入了阿里百川sdk,sdk中包含有淘宝登录等页面,它里面用到的都是反射,这样就造成了一些有趣的现象。项目继承sdk后,debug模式下使用的好好的,release模式也没问题;一旦切换到混淆路径release模式,刚跳转到淘宝页面就崩溃了,原因是资源图片找不到,原因就是资源路径被混淆,所以找不到了。阿里百川官方文档也没资源免混淆的说明,只能动手去翻sdk里面的代码,然后去添加相应的资源白名单,废了好一番力气。
 

发布了176 篇原创文章 · 获赞 11 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Deaht_Huimie/article/details/102481637
今日推荐