更多问答 >>
-
2019-09-04 23:33
-
2019-09-09 00:19
-
2019-09-11 00:24
-
每日一问 gradle项目构建,需要经历哪些核心task,整个构建流程哪些我们可以干涉?
2019-09-15 23:29 -
2019-09-15 23:30
-
每日一问 Parcelable 为什么效率高于 Serializable ?
2019-08-26 00:02 -
每日一问 今天聊一下Gradle 相关,BuildConfig这个类是如何生成的?
2019-08-20 23:27 -
2019-08-18 21:42
-
每日一问 Android 有哪些 位运算 的例子很值得借鉴?
2019-08-13 21:56 -
2019-08-12 09:58
最终打包出来的那些资源id,是会重新分配的(同一个资源生成的id,就算不在同一个R.class里,打包出来时也是相同的)。
做了个测试:
app依赖了模块test;
test模块中的string.xml有个test_value;
在test模块中引用(com.test.R),看到这个test_value的id值是
-1900002
;而在app中(com.app.R)引用时,id值为
-1900023
;这时候可以看出,相同的资源,id确实是不同。
打包成apk后,把它拖进AS里,点开
classes.dex
:首先找到app包名下的R$string,右键查看字节码,发现test_value的id值由原来的
-1900023
,变成了0x7f10005d
;接着找test模块包名下的R$string,查看字节码发现id值一样是
0x7f10005d
;由此看来,id值在打包成apk的时候,确实是重新分配了,而且同一个资源的id值,也统一了。
源码分析
那它究竟是如何重新分配这些id值的呢?
上一次也分析过https://www.wanandroid.com/wenda/show/8985,很多任务都是在ApplicationTaskManager里的createTasksForVariantScope方法中创建的。那现在再来看一下这个方法:可以看到,创建BuildConfig任务之后,接着调用了一个createApkProcessResTask方法,看上面注释,是用来处理资源和生成源码文件的。一步步点进去看看:
看看这个processLibraryMainSymbolTable方法:
看中间的注释,可以确定下面一句就是生成R.java的了,它会为tablesToWrite里面的每一个item都生成一个R文件,看一下这个tablesToWrite怎么来的:
妈耶!看开头的注释:"We have to rewrite the IDs",也就是必须重写这些id的意思了,再看一下它接下来调用的mergeAndRenumberSymbols方法:
可以看到调用了IdProvider的sequential方法,点开看下:
emmm,0x7f开头的id值,确实是对应的我们开头打包后的那个test_value的id值(0x7f10005d)。
到这里基本可以确定,最终打包的资源id,就是通过这个IdProvider的匿名子类来重新创建的,而且同一个资源所对应的id,也是一样的。秀啊大佬,学习了
翻源码的大佬
何时才能像你一样优秀尼? 低头瞅了瞅怀中的妹子,留下了悔恨的泪水。
半碟花生米就喝这么高了
秀啊
评论大佬从Android Gradle Plugin的打包机制出发找出具体实现代码已给出答案。
说下从android appt(2)打包过程得出来的结果,android打包后的产物apk包中resources.arsc文件里面包含应用的静态资源表,包含了anim,color,id,layout,string等资源类型,在同一种类型中资源名称name必须是唯一的,对应的ID也就是同一个,而在AS中打包的时候如果出现主模块和子模块同名称的情况下,会采用主模块的资源文件或属性,这是在AS插件合并多模块资源时做出的处理(包括androidmanifest合并,策略也不同,过程比较复杂),如果用aapt2手动对工程打包,也是要先手动合并多模块的资源,androidmanifest.xml等其他文件,然后在进行apk生成。
以下是aapt手动打包命令: