文章目录

  • 使用场景
    • 通过资源名和资源类型获取ID
    • 自动生成AutoR.java文件

使用场景

一般而言是不需要手动生成R.java文件的,对app开发而言,无疑是画蛇添足,对sdk开发而言,因为Android提供了aar的依赖方式,可以将资源文件一起打包入aar,最后集成方一起编辑生成R.java即可。
然而,快要2019年了,仍然有一些强势的集成方/游戏开发商仍然在使用Eclipse开发,不支持aar的一来方式,要求SDK是jar包的形式。对于sdk包含UI的开发方而言是十分痛苦的。
这种提供jar包+res的业务场景下就需要SDK开发者改变资源的获取方式,不能再通过原生R.String.xxx的方式获取资源,因为只有最后一次编译的时候才能确定资源的ID,之前的任何一次打包产生的ID值都是没有意义的。

据此分析,需要做两件事情:

  • 自动生成一个类似R.java一样的文件AutoR.java,包括所有的资源类型的引用,这个java文件最终一起打包进SDK的jar包。
  • 通过资源名和资源类型可以获取到宿主APP最终打包后的资源ID值

通过资源名和资源类型获取ID

通过资源名和资源类型可以获取资源ID,方式有两种,代码如下:

第一种反射宿主app的R文件方式,注意这里的mPackageName是宿主的package:

Class<?> cls = Class.forName(mPackageName + ".R$" + resType);return cls.getField(resName).getInt(cls);

第二种:调用系统api获取:

mContext.getResources().getIdentifier(resName, resType, mPackageName);

资源的获取方面:
除了Android系统自带的资源第一种反射的方式无法获取外,两者几乎是等价的,不存在某一种方式能获取到资源,另一种却获取不到的情况。

性能方面:
测试循环一万次,第一种反射的方式在我的2014年macbookpro上耗时157ms;
第二种方式耗时1900ms,而R.string.xxx的方式,循环1万次的耗时是0ms……

因此显然,应该优先使用反射方式获取资源文件。
代码如下:

import android.annotation.SuppressLint;import android.content.Context;import android.util.Log;/* AUTO-GENERATED FILE.  DO NOT MODIFY. * * This class was automatically generated by the * AutoR tool .  * It should not be modified by hand. */public final class AutoR {    private static String mPackageName;    @SuppressLint("StaticFieldLeak")    private static Context mContext;    private static volatile boolean RExist;    public static void init(Context context){        if (context != null) {            mContext = context;            mPackageName = context.getPackageName();            try {                Class.forName(mPackageName + ".R");                RExist = true;            }            catch (ClassNotFoundException e) {                //some game situation                Log.i("autoR", "No R class");                RExist =false;            }        }else {            Log.e("autoR","don't init AutoR with null");        }    }    private static int getResId(String resName, String resType) {        if (mContext != null) {            //android system resource            if (!resName.isEmpty() && resName.startsWith("android_")) {                return mContext.getResources().getIdentifier(resName.replace("android_", ""), resType, "android");            }            // R exist            if (RExist) {                try {                    Class<?> cls = Class.forName(mPackageName + ".R$" + resType);                    return cls.getField(resName).getInt(cls);                } catch (IllegalAccessException e) {                    e.printStackTrace();                    Log.e("autoR", "IllegalAccessException:" + e.getMessage());                } catch (ClassNotFoundException e) {                    e.printStackTrace();                    Log.e("autoR", "ClassNotFoundException:" + e.getMessage());                } catch (NoSuchFieldException e) {                    e.printStackTrace();                    Log.e("autoR", "NoSuchFieldException:" + e.getMessage());                }            } else {                return mContext.getResources().getIdentifier(resName, resType, mPackageName);            }        }else {            Log.e("autoR","you should init AutoR first");        }        return 0;    }}

在你sdk的初始方法中调用AutoR.inti(context.getApplicationContext)即可。为了避免内存泄露,这里的context应该是ApplcationContext。
第一个问题就此解决。

自动生成AutoR.java文件

其实很简单,打开任何一份系统自动生成的R.java文件,类似如下:

。。。。    public static final class string {        public static int status_string = 0x7f150202;    。。。    }。。。    

这是一个String类型的资源,系统编译的时候会自动确定他的常亮ID值,我们需要做的就是将这个ID值,替换为上一节中的AutoR.getResId("status_string","string")

因此,我们的策略:

  • 系统prebuild task之前插入一个task,手动先调用Android sdk的aapt命令生产R.java,然后根据R.java生成AutoR.java
  • 同时将sdk源码中的import xx.R全部替换为import xx.AutoR
  • 将所有调用资源的地方修改为AutoR.string.xxxx

具体不多说,可以参考源码。

源码地址AutoR

更多相关文章

  1. GitHub 标星 2.5K+!教你通过玩游戏的方式学习 VIM!
  2. 一款常用的 Squid 日志分析工具
  3. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  4. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  5. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  6. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  7. 一款霸榜 GitHub 的开源 Linux 资源监视器!
  8. 备份、恢复android软件设置
  9. Android原生页面Activity与React页面相互跳转

随机推荐

  1. 如何查看Android 中native的Service
  2. Android(安卓)Theme
  3. [AndroidTips]Android软件测试的日志文件
  4. Ubuntu下批处理转换jpg 2 png格式
  5. AIDL实例分析和讲解
  6. 翻译引用 android的按键响应
  7. 一招破解Android SDk 更新问题
  8. ListView 美化小细节
  9. Android 数据库Sqlite的使用(3)
  10. Android(安卓)Telechips89xx背光控制流程