

ByteX R文件内联应用实践
source link: https://zhuanlan.zhihu.com/p/413839599
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ByteX R文件内联应用实践
我们有这样的一个工程项目的依赖结构为App Moudle依赖 Libarray Moudle A, Libarray Moudle A依赖 Libarray Moudle B。下图为R文件的工程结构

可以看出每个moudle都有各自的R文件,同时上层R文件会融合下层的R文件资源,所以我们在开发过程中上层工程不需要区分包名直接就可以访问底层资源。
同样带来了一些问题:
- 如R文件越来越多是否冗余了,导致包大小增大
- 上层的R文件很容易出现R Field过多,导致MultiDex 65536的问题。
ByteX思路 R文件内联
其实在app工程的R资源已经进行了内联处理
application库的源码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
工程编译后的代码(反编译apk查看)

但是moudle工程下的R资源未进行内联处理
public class MoudleActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_moudle);
}
}
moudle工程编译后的代码(反编译apk查看)
为什么moudle工程的没有进行内联处理?这是因为 Library/AAR的class文件,在主工程编译时,不会再次进行编译,Library/AAR的class文件原封不动的打包进apk。而资源id为常量是在主工程编译时才形成的,但Library/AAR生成class时,使用的是上面说到的变量,所以一直被保留了下来。
byteX 通过ASM对class文件进行操作对使用到R类变量的地方进行常量值替换,然后删除R文件从而达到减少包大小的目的。
byteX应用后可以看出moudle的R资源也内联了,同时R的类文件也消失了
ByteX应用配置
// apply ByteX宿主
apply plugin: 'bytex'
ByteX {
enable true
enableInDebug true
logLevel "DEBUG"
}
apply plugin: 'bytex.shrink_r_class'
shrinkR {
enable true
enableInDebug true
logLevel "DEBUG"
//对于反射获取R文件的地方配置白名单
keepList = [
// keep android.support.constraint.R里所有id
"android.support.constraint.R.id",
"androidx.constraintlayout.R.id",
"androidx.constraintlayout.widget.R.id",
]
}
开发注意事项
注意:对于使用改方式反射获取资源id的地方需要在byteX配置文件中进行keep
public static int getId(String num){
try {
String name = "drawable" + num;
Field field = R.drawable.class.getField(name);
return field.getInt(null);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
对于如下方式反射获取资源id的地方无需考虑(该方式通过native层读取resources.arsc文件获取资源id与R文件内联无影响),但是需要在androidResGuard资源混淆的配置文件中进行配置
int resId = res.getIdentifier("download_filter_" + mMediaTypeOnShow,
"string", packageName);
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK