Open aasitnikov opened 4 years ago
I've created Transformer, that implements bytecode transformation described above. It uses Transformer API from AGP, and uses JavaAssist to patch bytecode.
To apply it, write the following lines in build.gradle:
android.registerTransform(new EmbedRClassesBytecodeTransformer(
["my.embedded.library"], // list all embedded modules here
"my.fat.library"
))
This transformer can be used in the plugin as is - plugin knows packages of current and embedded modules, and can register transform easily.
UPD: In newer versions (1.2.20+) we need to specify order between tasks
// Explicitly specify order between bytecode transformer and fat-aars mergeClasses
// If transform would occur before mergeClasses, output won't have emdedded classes
android.libraryVariants.all {
def name = it.name.capitalize()
tasks.named("transformClassesWithFatAarRTransformFor$name").configure {
it.dependsOn(tasks.named("mergeClasses$name"))
}
}
@aasitnikov do you have a working demo where you implemented this?
@yallam08 Made a little example app, where this transformer is used https://github.com/aasitnikov/fat-aar-bytecode-patching
@kezong What do you think of adding this bytecode transformer to plugin?
@aasitnikov This is a good idea. You can pull request for the bytecode transformer. To be safe, best to add a switch that can back to the original method.
@aasitnikov the demo works fine, even if I didn't uncomment the register transform statement.
It is supported in 1.3.1
Because we embed modules into one fat-aar, aapt wont generate R class for these modules. So, fat-aar generates R.java classes by itself, and puts it into "lib/r-classes.jar" inside resulting aar.
Imagine we have a resource, that was present in one version of some other library, and was removed in next version. For example, take
TextAppearance.MaterialComponents.Tab
- it was a private resource of MaterialComponents:1.0.0, and it was removed in MaterialComponents:1.1.0. If we compile our using version 1.0.0, fat-aar generates following R.java class:When consumer of this aar uses MaterialComponents 1.0.0 and compiles an apk, aapt will generate
my.fat.library.R.java
class withTextAppearance_MaterialComponents_Tab
field in it. But if consumer compiles it's apk with MaterialComponents:1.1.0,my.fat.library.R.style.TextAppearance_MaterialComponents_Tab
won't be generated by aapt, when compiling app module. So, in runtime, whenmy.emdedded.library.R
class first loaded,NoSuchFieldError
will be thrown in static initialiser.Fat-aar plugin can solve this problem using bytecode patching. Plugin should patch classes from embedded aar, changing imports of R classes to match fat-aar's package. In example above, in every class of embedded library, references to
my.emdedded.library.R
should be replaced withmy.fat.library.R
. Then there will be no need to generate R.java classes into r-classes.jar.If implemented, this change will solve a lot of current issues: #75, #90, #136, #161, #170 and probably #169, #180