R.java是android编译时通过aapt来生成的,生成的全部都是int类型的id值.当前我有一个很奇葩的想法,我想给每个id都带上附加的类型说明,以用于在使用时能校验得类型对不对.添加的依据是使用XML的注释.如一个strings.xml
1 | <!-- String --> |
我想对name生成一个自定义的注解,如1
2 (className=String.class)
public static final int name=0x0x7f040001
然后就开干了,既然是AAPT生成的,那自然也得找AAPT.因为此前已经对AAPT进行过一点分析,所以也算是轻车熟路.找到AAPT的目录,在frameworks/base/tools/aapt下,我们只是想给每一个项添加上这样的注解,那直接找到生成R.java的源文件就可以了.不难,就在Resource.cpp中.
直接找到写文件的方法,有两个,开始是writeResourceSymbols这个方法,这个写一些R.java的头注释,还有包名等等 ,然后就调用了writeSymbolClass来写各个symbol的具体值了.writeSymbolClass方法不难看,主要是通过遍历symbols->getSymbols()中的symbol来写出不同的语句.因为我想使用的是通过注释来生成 ,那么直接看注释即可,注释是包装在symbol的comment字段中,包括了所有,完整的注释内容.看了一下才发现,其实aapt中早就已经有这样的做法,就是通过检查是否注释中是否包含@deprecated来判断是否需要给这个记录添加@deprecated标注.
看来是跟写这个的人想到一块去了. 既然人家能这么做,我修改也是肯定没问题的.我的判断逻辑就直接跟源码方法一样,单纯地通过strstr来判断是否包含指定的字符串,代码如下:
1 | if (strstr(cmt.string(),"TargetClass") != NULL) { |
然后再在下面中根据这些标志位写上具体的标注即可
1 | if (hasString){ |
如此即可完成需求了.当然也可以按自己的要求在标注出现后把注释禁用了,也是一个标志位的事.
另外,由于TargetClass是自定义的类,为了避免生成R.java后有类找不到,有两种办法,一种就是writeResourceSymbols里把类import的语句也写在头部,另一种就是上面的,直接写全路径.第二种就更加灵活,怎么用都行.
然后最后生成的文件就是类似这样.
1 | .uc.gamesdk.annotations.TargetClass(className=String.class) |
完成是完成了,不过最后还是没想用这种办法,一来需要把aapt给换掉,二来我只是想做测试,加强一个类型错误检查,发布了我可不想要这些代码,虽然这些问题还是有办法解决,不过倒不如另谋他路来得可靠.
权当记录.