Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Exploring the Android Transform API

Exploring the Android Transform API

What do ProGuard, Multidex, Resource Merger and Realm have in common? Answer: All of these components owe key functionality to the Android Transform API. It is a centerpiece of the Android Gradle Plugin's internal architecutre, as it is responsible for processing intermediary build artifacts, and before the introduction of D8, it was even tasked with the bytecode transformation of Java 8 code for Android as well. To third-party developers, it offers a hook into the creation of an APK through a centralized concept, the Transform, which can inspect and modify classes or resources. Little documentation and a lack of accessibility to the topic have rendered the Transform API a "hidden gem" in the Android plugin infrastructure.

Marcel Schnelle

February 07, 2019
Tweet

More Decks by Marcel Schnelle

Other Decks in Programming

Transcript

  1. public static void main(String[] args) { process(i -> System.out.println(i +

    " is the answer!")); } private static void process(IntConsumer consumer) { consumer.accept(42); } class MyProgram { } interface IntConsumer { void accept(int value); }
  2. interface IntConsumer { void accept(int value); } class MyProgram {

    private static void process(IntConsumer consumer) { consumer.accept(42); } public static void main(String[] args) { process(i -> System.out.println(i + " is the answer!")); } } #FGPSF"(1 Uncaught translation error: com.android.dx.cf.code.SimException: ERROR in MyProgram.main:([Ljava/lang/String;)V: invalid opcode ba - invokedynamic requires --min-sdk-version >= 26 (currently 19) 1 error; aborting BUILD FAILED in 1s
  3. interface IntConsumer { void accept(int value); } class MyProgram {

    private static void process(IntConsumer consumer) { consumer.accept(42); } public static void main(String[] args) { process(i -> System.out.println(i + " is the answer!")); } } 8JUI"(1 BUILD SUCCESSFUL in 1s
  4. Transform"1*  fun getName(): String
 6OJRVFJEFOUJpFSPGUIFTransform  fun isIncremental(): Boolean


    (FUBMMDMBTTpMFTPSKVTUBEJ⒎PGDIBOHFEpMFT  fun getInputTypes(): Set<ContentType>
 $MBTTFTPS3FTPVSDFT  fun getScopes(): MutableSet<in Scope>
 )PXNVDIEFUBJM
  5. Transform#transform(TransformInvocation)  inputs: Collection<TransformInput>
 5IFpMFTNBOJQVMBUFECZUIF5SBOTGPSN  referencedInputs: Collection<TransformInput>
 5IFpMFTOPUNBOJQVMBUFECZUIF5SBOTGPSN 

    secondaryInputs: Collection<TransformInput>
 SFMBUFEUPJODSFNFOUBMQSPDFTTJOH  context: Context
 "DDFTTUPMPHHJOHCVJMEJOGP  outputProvider: TransformOutputProvider
 'BDUPSZGPSPVUQVUGPMEFSTUPXSJUFUIFSFTVMUTUP
  6. // Create an immutable list of 3 strings (Java 9)

    List<String> values = List.of("Hello", "Mr.", "Hoge"); // Create an immutable list of 3 strings (Kotlin) val values = listOf("Hello", "Mr.", "Hoge") // Create an immutable list of 3 strings (Java 7) List<String> values = new ArrayList<>(3); values.add("Hello"); values.add("Mr."); values.add("Hoge"); values = Collections.unmodifiableList(values);
  7. )BDLJOH+BWB"1*TJOUPBOESPJEKBS  $PQZplatforms/android-28BOESFOBNFUPplatforms/android-1000  3FQMBDFNFOUJPOTPG"1*-FWFMXJUIpackage.xml, build.prop, source.properties  3FQMBDFjava.utilQBDLBHFJOTJEFandroid.jarXJUIDMBTTFTUBLFOGSPN +%,jar

    uf <jar-file> <updated-class-files>  6QEBUFbuild.gradleUPQPJOUUPandroid-1000JOTUFBE  (SBEMF4ZOD  8FIBWFUIF+BWB"1*TOPX  *EJTDPVSBHFNBOJQVMBUJPOPGUIF"OESPJE1MBUGPSNMJLFUIJT EFNPOTUSBUJPOPOMZ/FWFSCVJMEBHBJOTUBNPOLFZQBUDIFE+"3