Skip to content

Conversation

@irodotos7
Copy link
Contributor

@irodotos7 irodotos7 commented Apr 8, 2025

A step back from this PR #4743

I created a smaller, clear PR with the R8 task only and without the separation of Debug and Release Install paths

Motivation

As part of Mill’s Android integration, we want to use the R8 optimization tool to create smaller dex files

image

image

Provided in this PR

  1. Run the R8 task which will shrink the dex files according to the proguard rules

@autofix-ci
Copy link
Contributor

autofix-ci bot commented Apr 8, 2025

Hi! I'm autofix logoautofix.ci, a bot that automatically fixes trivial issues such as code formatting in pull requests.

I would like to apply some automated changes to this pull request, but it looks like I don't have the necessary permissions to do so. To get this pull request into a mergeable state, please do one of the following two things:

  1. Allow edits by maintainers for your pull request, and then re-trigger CI (for example by pushing a new commit).
  2. Manually fix the issues identified for your pull request (see the GitHub Actions output for details on what I would like to change).

@irodotos7 irodotos7 force-pushed the android/R8-optimization-small-version branch from 80021b9 to 03252dc Compare April 8, 2025 14:45
@irodotos7 irodotos7 marked this pull request as ready for review April 8, 2025 14:45
@irodotos7
Copy link
Contributor Author

@lefou @vaslabs a new smaller PR for the R8 task :)

Copy link
Member

@lefou lefou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I added some nits. Also, it would be good to have some scaladoc on at least those tasks that the user is supposed to override or to call.

@lefou lefou changed the title smallest version of R8 Use R8 optimization tool in Android modules Apr 9, 2025
@irodotos7 irodotos7 force-pushed the android/R8-optimization-small-version branch from 0c3d90f to eac130c Compare April 10, 2025 06:43
@lefou
Copy link
Member

lefou commented Apr 10, 2025

Have you tried to render the docs? It looks rather unreadable to me.

Looks like the example itself is just a copy of the android/javalib/1-hello-world example. We don't need to re-iterate all introductory docs. It's enough to say, that we expand the simple example (link) to show how to use the R8 optimization tool, and maybe why a user want this.

Also, to effectively see the docs, you need to include it into the website.

diff --git a/website/docs/modules/ROOT/pages/android/java.adoc b/website/docs/modules/ROOT/pages/android/java.adoc
index aed8dd649e5..7e44f2df7de 100644
--- a/website/docs/modules/ROOT/pages/android/java.adoc
+++ b/website/docs/modules/ROOT/pages/android/java.adoc
@@ -67,3 +67,7 @@ The `AndroidAppBundle` trait is used to create and manage Android App Bundles (A
 - **androidUnsignedBundle:** Uses the `bundleTool` to build an unsigned AAB from the bundle zip.
 
 - **androidBundle:** Signs the AAB using a specified keystore with the `jarsigner` tool, producing a signed Android App Bundle (AAB).
+
+== Using the R8 optimization tool in Android modules
+
+include::partial$example/android/javalib/5-R8.adoc[]

Then generate a small version of the site to be read locally:

> mill website.fastPages
...
[2504] You can browse the pages at: file:///.../mill/out/website/fastPages.dest/site/index.html

Also, the example should pass the test.

> mill example.android.javalib[5-R8].local.server.testForked

It doesn't for me, but that's probably because I missed some steps to setup android dev at all. I think our own intro page isn't detailed enough for me. 😜

@lefou
Copy link
Member

lefou commented Apr 10, 2025

Feel free to ignore the callouts I requested before (I can put them in myself later). Just make it look reasonable.

@irodotos7
Copy link
Contributor Author

Feel free to ignore the callouts I requested before (I can put them in myself later). Just make it look reasonable.

Okay. Thank you :)

@irodotos7
Copy link
Contributor Author

Have you tried to render the docs? It looks rather unreadable to me.

Looks like the example itself is just a copy of the android/javalib/1-hello-world example. We don't need to re-iterate all introductory docs. It's enough to say, that we expand the simple example (link) to show how to use the R8 optimization tool, and maybe why a user want this.

Also, to effectively see the docs, you need to include it into the website.

diff --git a/website/docs/modules/ROOT/pages/android/java.adoc b/website/docs/modules/ROOT/pages/android/java.adoc
index aed8dd649e5..7e44f2df7de 100644
--- a/website/docs/modules/ROOT/pages/android/java.adoc
+++ b/website/docs/modules/ROOT/pages/android/java.adoc
@@ -67,3 +67,7 @@ The `AndroidAppBundle` trait is used to create and manage Android App Bundles (A
 - **androidUnsignedBundle:** Uses the `bundleTool` to build an unsigned AAB from the bundle zip.
 
 - **androidBundle:** Signs the AAB using a specified keystore with the `jarsigner` tool, producing a signed Android App Bundle (AAB).
+
+== Using the R8 optimization tool in Android modules
+
+include::partial$example/android/javalib/5-R8.adoc[]

Then generate a small version of the site to be read locally:

> mill website.fastPages
...
[2504] You can browse the pages at: file:///.../mill/out/website/fastPages.dest/site/index.html

Also, the example should pass the test.

> mill example.android.javalib[5-R8].local.server.testForked

It doesn't for me, but that's probably because I missed some steps to setup android dev at all. I think our own intro page isn't detailed enough for me. 😜

The fastPages doesn't work but the testForked its running okay

@lefou
Copy link
Member

lefou commented Apr 10, 2025

The fastPages doesn't work but the testForked its running okay

What's the error message? You can also try mill website.localPages, but then you must select the correct version to see your pages.

@lefou
Copy link
Member

lefou commented Apr 10, 2025

I removed the generated build-docs.adoc file. Mill already produces the documentation from the build.mill file. You need to render it with mill website.fastPages and the you can find your example module docs included in file:///.../mill/out/website/fastPages.dest/site/mill/main-branch/android/java.html#_using_the_r8_optimization_tool_in_android_modules.

I added some TODOs, where you should add a short explanation what R8 is and why a user should want to use it.

Next comes your example project. It currently does not contain any specific configuration for R8. The point of the example is to show the user how to enable and configure it. If that is mostly done via additional files, e.g. proguard files, use a "See Also" line and explain how it works.

@lefou
Copy link
Member

lefou commented Apr 10, 2025

Looks like I can't push to your branch. Here are my changes:

diff --git a/website/docs/modules/ROOT/pages/android/build-docs.adoc b/website/docs/modules/ROOT/pages/android/build-docs.adoc
deleted file mode 100644
index 10fade4c452..00000000000
--- a/website/docs/modules/ROOT/pages/android/build-docs.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-= Android Build File
-
-This is an example of a build file for an Android application using Mill. It demonstrates how to set up an Android project, configure the SDK, and define tasks for building and testing the application.
-
-[source,scala]
-----
-package build
-
-import mill._, javalib._
-import mill.javalib.android.{AndroidAppModule, AndroidSdkModule}
-import mill.javalib.android.AndroidTestModule
-
-// Create and configure an Android SDK module to manage Android SDK paths and tools. <3>
-object androidSdkModule0 extends AndroidSdkModule {
-  def buildToolsVersion = "35.0.0"
-}
-
-// Actual android application <4>
-object app extends AndroidAppModule {
-  def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)
-  def androidMinSdk = 19
-  def androidCompileSdk = 35
-
-  /**
-   * Configuration for ReleaseKey
-   * WARNING: Replace these default values with secure and private credentials before using in production.
-   * Never use these defaults in a production environment as they are not secure.
-   * This is just for testing purposes.
-   */
-  def androidReleaseKeyName: T[Option[String]] = Task { Some("releaseKey.jks") } // <5>
-  def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") }
-  def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") }
-  def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") }
-
-  override def androidVirtualDeviceIdentifier: String = "java-test"
-
-  // Unit tests for the application <6>
-  object test extends AndroidAppTests with TestModule.Junit4 {
-    def ivyDeps = super.ivyDeps() ++ Seq(
-      ivy"junit:junit:4.13.2"
-    )
-  }
-
-  // Instrumented tests (runs on device/emulator) <7>
-  object it extends AndroidAppInstrumentedTests with AndroidTestModule.AndroidJUnit {
-    def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)
-    override def instrumentationPackage = "com.helloworld.app"
-
-    /* TODO currently the dependency resolution ignores the platform type and kotlinx-coroutines-core has
-     * conflicting classes with kotlinx-coroutines-core-jvm . Remove the exclusions once the dependency
-     * resolution resolves conflicts between androidJvm and jvm platform types
-     */
-    def ivyDeps = super.ivyDeps() ++ Seq(
-      ivy"androidx.test.ext:junit:1.2.1".exclude(
-        ("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
-      ),
-      ivy"androidx.test:runner:1.6.2",
-      ivy"androidx.test.espresso:espresso-core:3.5.1".exclude(
-        ("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
-      ),
-      ivy"junit:junit:4.13.2"
-    )
-  }
-
-}
-----
-<1> High-level summary of the build file, describing how it sets up an Android project in Mill.
-<2> Explanation of how `AndroidAppModule` automatically provides tasks for building an Android app (resource generation, APK building, signing, etc.).
-<3> The `androidSdkModule0` object extends `AndroidSdkModule`, controlling SDK versioning and tool paths.
-<4> The `app` object defines the main Android application module by extending `AndroidAppModule`.
-<5> **Release key configuration**. These lines demonstrate how to declare release key credentials (FOR DEMO ONLY - DO NOT use in production).
-<6> The `test` object includes local JUnit-based unit tests.
-<7> The `it` object includes instrumented tests, which run on an emulator
diff --git a/example/android/javalib/5-R8/build.mill b/example/android/javalib/5-R8/build.mill
index 13d1f2e8088..9fca9959ea3 100644
--- a/example/android/javalib/5-R8/build.mill
+++ b/example/android/javalib/5-R8/build.mill
@@ -1,11 +1,4 @@
-//// SNIPPET:BUILD
-// This section sets up a basic Android project using Mill.
-// We utilize `AndroidAppModule` and `AndroidSdkModule` to streamline the process of
-// building an Android application with minimal configuration.
-//
-// By extending `AndroidAppModule`, we inherit all Android-related tasks such as
-// resource generation, APK building, DEX conversion, and APK signing.
-// Additionally, `AndroidSdkModule` is embedded, making SDK management seamless.
+// TODO: Some docs about R8 should go here
 
 package build
 
@@ -13,18 +6,16 @@ import mill._, javalib._
 import mill.javalib.android.{AndroidAppModule, AndroidSdkModule}
 import mill.javalib.android.AndroidTestModule
 
-// Create and configure an Android SDK module to manage Android SDK paths and tools.
-object androidSdkModule0 extends AndroidSdkModule {
+ object androidSdkModule0 extends AndroidSdkModule { // <1>
   def buildToolsVersion = "35.0.0"
 }
 
-// Actual android application
-object app extends AndroidAppModule {
+object app extends AndroidAppModule { // <2>
   def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)
   def androidMinSdk = 19
   def androidCompileSdk = 35
 
-  /**
+  /*
    * Configuration for ReleaseKey
    * WARNING: Replace these default values with secure and private credentials before using in production.
    * Never use these defaults in a production environment as they are not secure.
@@ -66,109 +57,13 @@ object app extends AndroidAppModule {
   }
 
 }
-//// SNIPPET:END
 
-////SNIPPET:END
+// <1> Create and configure an Android SDK module to manage Android SDK paths and tools.
+// <2> The actual Android application
 
-/** Usage
 
-> ./mill show app.androidApk
-".../out/app/androidApk.dest/app.apk"
+// TODO: Add some example how to use the R8 tool. To refer to other resources, use the "See Also" section like below.
 
-> ./mill show app.createAndroidVirtualDevice
-...Name: java-test, DeviceId: medium_phone...
+/** See Also: app/proguard-rules.pro */
 
-> ./mill show app.startAndroidEmulator
-
-> ./mill show app.androidReleaseInstall
-...All files should be loaded. Notifying the device...
-
-> ./mill show app.stopAndroidEmulator
-
-> ./mill show app.deleteAndroidVirtualDevice
-
-*/
-
-// This command triggers the build process, which installs the Android Setup, compiles the Java
-// code, generates Android resources, converts Java bytecode to DEX format, packages everything
-// into an APK, optimizes the APK using `zipalign`, and finally signs it.
-//
-// This Mill build configuration is designed to build a simple "Hello World" Android application.
-// By extending `AndroidAppModule`, we leverage its predefined Android build tasks, ensuring that
-// all necessary steps (resource generation, APK creation, and signing) are executed automatically.
-//
-// #### Project Structure:
-// The project follows the standard Android app layout. Below is a typical project folder structure:
-//
-// ----
-// .
-//├── app
-//│     └── src
-//│         ├── androidTest/java/com/helloworld/app/ExampleInstrumentedTest.java
-//│         ├── main
-//│         │     ├── AndroidManifest.xml
-//│         │     ├── java/com/helloworld/app/MainActivity.java
-//│         │     └── res
-//│         │         └── values
-//│         │             ├── colors.xml
-//│         │             └── strings.xml
-//│         └── test/java/com/helloworld/app/ExampleUnitTest.java
-//└── build.mill
-// ----
-//
-
-/** Usage
-
-> ./mill show app.test
-...compiling 2 Java source...
-
-> cat out/app/test/testForked.dest/worker-0/out.json
-["",[{"fullyQualifiedName":"com.helloworld.ExampleUnitTest.textSize_isCorrect","selector":"com.helloworld.ExampleUnitTest.textSize_isCorrect","duration":...,"status":"Success"}]]
-
-*/
-
-// This command runs unit tests on your local environment.
-
-/** Usage
-
-> ./mill show app.createAndroidVirtualDevice
-...Name: java-test, DeviceId: medium_phone...
-
-> ./mill show app.startAndroidEmulator
-
-> ./mill show app.adbDevices
-...emulator-5554...device...
-
-> ./mill show app.it
-...
-[
-  "",
-  [
-    {
-      "fullyQualifiedName": "com.helloworld.app.ExampleInstrumentedTest.useAppContext",
-      "selector": "com.helloworld.app.ExampleInstrumentedTest.useAppContext",
-      "duration": ...,
-      "status": "Success"
-    }
-  ]
-]
-...
-
-> cat out/app/it/testTask.dest/test-report.xml
-...
-<?xml version='1.0' encoding='UTF-8'?>
-<testsuites tests="1" failures="0" errors="0" skipped="0" time="...">
-        <testsuite name="com.helloworld.app.ExampleInstrumentedTest.useAppContext" tests="1" failures="0" errors="0" skipped="0" time="0.0" timestamp="...">
-        <properties>
-      </properties>
-        <testcase classname="com.helloworld.app.ExampleInstrumentedTest.useAppContext" name="com.helloworld.app.ExampleInstrumentedTest.useAppContext" time="...">
-        </testcase>
-      </testsuite>
-      </testsuites>
-...
-
-> ./mill show app.stopAndroidEmulator
-
-> ./mill show app.deleteAndroidVirtualDevice
-
-*/
+// TODO: you should explain the essential lines of that files. (Callouts might come in handy)
diff --git a/website/docs/modules/ROOT/pages/android/java.adoc b/website/docs/modules/ROOT/pages/android/java.adoc
index aed8dd649e5..8d0a37cb55e 100644
--- a/website/docs/modules/ROOT/pages/android/java.adoc
+++ b/website/docs/modules/ROOT/pages/android/java.adoc
@@ -67,3 +67,8 @@ The `AndroidAppBundle` trait is used to create and manage Android App Bundles (A
 - **androidUnsignedBundle:** Uses the `bundleTool` to build an unsigned AAB from the bundle zip.
 
 - **androidBundle:** Signs the AAB using a specified keystore with the `jarsigner` tool, producing a signed Android App Bundle (AAB).
+
+
+== Using the R8 optimization tool in Android modules
+
+include::partial$example/android/javalib/5-R8.adoc[]

@irodotos7
Copy link
Contributor Author

Looks like I can't push to your branch. Here are my changes:

diff --git a/website/docs/modules/ROOT/pages/android/build-docs.adoc b/website/docs/modules/ROOT/pages/android/build-docs.adoc
deleted file mode 100644
index 10fade4c452..00000000000
--- a/website/docs/modules/ROOT/pages/android/build-docs.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-= Android Build File
-
-This is an example of a build file for an Android application using Mill. It demonstrates how to set up an Android project, configure the SDK, and define tasks for building and testing the application.
-
-[source,scala]
-----
-package build
-
-import mill._, javalib._
-import mill.javalib.android.{AndroidAppModule, AndroidSdkModule}
-import mill.javalib.android.AndroidTestModule
-
-// Create and configure an Android SDK module to manage Android SDK paths and tools. <3>
-object androidSdkModule0 extends AndroidSdkModule {
-  def buildToolsVersion = "35.0.0"
-}
-
-// Actual android application <4>
-object app extends AndroidAppModule {
-  def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)
-  def androidMinSdk = 19
-  def androidCompileSdk = 35
-
-  /**
-   * Configuration for ReleaseKey
-   * WARNING: Replace these default values with secure and private credentials before using in production.
-   * Never use these defaults in a production environment as they are not secure.
-   * This is just for testing purposes.
-   */
-  def androidReleaseKeyName: T[Option[String]] = Task { Some("releaseKey.jks") } // <5>
-  def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") }
-  def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") }
-  def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") }
-
-  override def androidVirtualDeviceIdentifier: String = "java-test"
-
-  // Unit tests for the application <6>
-  object test extends AndroidAppTests with TestModule.Junit4 {
-    def ivyDeps = super.ivyDeps() ++ Seq(
-      ivy"junit:junit:4.13.2"
-    )
-  }
-
-  // Instrumented tests (runs on device/emulator) <7>
-  object it extends AndroidAppInstrumentedTests with AndroidTestModule.AndroidJUnit {
-    def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)
-    override def instrumentationPackage = "com.helloworld.app"
-
-    /* TODO currently the dependency resolution ignores the platform type and kotlinx-coroutines-core has
-     * conflicting classes with kotlinx-coroutines-core-jvm . Remove the exclusions once the dependency
-     * resolution resolves conflicts between androidJvm and jvm platform types
-     */
-    def ivyDeps = super.ivyDeps() ++ Seq(
-      ivy"androidx.test.ext:junit:1.2.1".exclude(
-        ("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
-      ),
-      ivy"androidx.test:runner:1.6.2",
-      ivy"androidx.test.espresso:espresso-core:3.5.1".exclude(
-        ("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
-      ),
-      ivy"junit:junit:4.13.2"
-    )
-  }
-
-}
-----
-<1> High-level summary of the build file, describing how it sets up an Android project in Mill.
-<2> Explanation of how `AndroidAppModule` automatically provides tasks for building an Android app (resource generation, APK building, signing, etc.).
-<3> The `androidSdkModule0` object extends `AndroidSdkModule`, controlling SDK versioning and tool paths.
-<4> The `app` object defines the main Android application module by extending `AndroidAppModule`.
-<5> **Release key configuration**. These lines demonstrate how to declare release key credentials (FOR DEMO ONLY - DO NOT use in production).
-<6> The `test` object includes local JUnit-based unit tests.
-<7> The `it` object includes instrumented tests, which run on an emulator
diff --git a/example/android/javalib/5-R8/build.mill b/example/android/javalib/5-R8/build.mill
index 13d1f2e8088..9fca9959ea3 100644
--- a/example/android/javalib/5-R8/build.mill
+++ b/example/android/javalib/5-R8/build.mill
@@ -1,11 +1,4 @@
-//// SNIPPET:BUILD
-// This section sets up a basic Android project using Mill.
-// We utilize `AndroidAppModule` and `AndroidSdkModule` to streamline the process of
-// building an Android application with minimal configuration.
-//
-// By extending `AndroidAppModule`, we inherit all Android-related tasks such as
-// resource generation, APK building, DEX conversion, and APK signing.
-// Additionally, `AndroidSdkModule` is embedded, making SDK management seamless.
+// TODO: Some docs about R8 should go here
 
 package build
 
@@ -13,18 +6,16 @@ import mill._, javalib._
 import mill.javalib.android.{AndroidAppModule, AndroidSdkModule}
 import mill.javalib.android.AndroidTestModule
 
-// Create and configure an Android SDK module to manage Android SDK paths and tools.
-object androidSdkModule0 extends AndroidSdkModule {
+ object androidSdkModule0 extends AndroidSdkModule { // <1>
   def buildToolsVersion = "35.0.0"
 }
 
-// Actual android application
-object app extends AndroidAppModule {
+object app extends AndroidAppModule { // <2>
   def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)
   def androidMinSdk = 19
   def androidCompileSdk = 35
 
-  /**
+  /*
    * Configuration for ReleaseKey
    * WARNING: Replace these default values with secure and private credentials before using in production.
    * Never use these defaults in a production environment as they are not secure.
@@ -66,109 +57,13 @@ object app extends AndroidAppModule {
   }
 
 }
-//// SNIPPET:END
 
-////SNIPPET:END
+// <1> Create and configure an Android SDK module to manage Android SDK paths and tools.
+// <2> The actual Android application
 
-/** Usage
 
-> ./mill show app.androidApk
-".../out/app/androidApk.dest/app.apk"
+// TODO: Add some example how to use the R8 tool. To refer to other resources, use the "See Also" section like below.
 
-> ./mill show app.createAndroidVirtualDevice
-...Name: java-test, DeviceId: medium_phone...
+/** See Also: app/proguard-rules.pro */
 
-> ./mill show app.startAndroidEmulator
-
-> ./mill show app.androidReleaseInstall
-...All files should be loaded. Notifying the device...
-
-> ./mill show app.stopAndroidEmulator
-
-> ./mill show app.deleteAndroidVirtualDevice
-
-*/
-
-// This command triggers the build process, which installs the Android Setup, compiles the Java
-// code, generates Android resources, converts Java bytecode to DEX format, packages everything
-// into an APK, optimizes the APK using `zipalign`, and finally signs it.
-//
-// This Mill build configuration is designed to build a simple "Hello World" Android application.
-// By extending `AndroidAppModule`, we leverage its predefined Android build tasks, ensuring that
-// all necessary steps (resource generation, APK creation, and signing) are executed automatically.
-//
-// #### Project Structure:
-// The project follows the standard Android app layout. Below is a typical project folder structure:
-//
-// ----
-// .
-//├── app
-//│     └── src
-//│         ├── androidTest/java/com/helloworld/app/ExampleInstrumentedTest.java
-//│         ├── main
-//│         │     ├── AndroidManifest.xml
-//│         │     ├── java/com/helloworld/app/MainActivity.java
-//│         │     └── res
-//│         │         └── values
-//│         │             ├── colors.xml
-//│         │             └── strings.xml
-//│         └── test/java/com/helloworld/app/ExampleUnitTest.java
-//└── build.mill
-// ----
-//
-
-/** Usage
-
-> ./mill show app.test
-...compiling 2 Java source...
-
-> cat out/app/test/testForked.dest/worker-0/out.json
-["",[{"fullyQualifiedName":"com.helloworld.ExampleUnitTest.textSize_isCorrect","selector":"com.helloworld.ExampleUnitTest.textSize_isCorrect","duration":...,"status":"Success"}]]
-
-*/
-
-// This command runs unit tests on your local environment.
-
-/** Usage
-
-> ./mill show app.createAndroidVirtualDevice
-...Name: java-test, DeviceId: medium_phone...
-
-> ./mill show app.startAndroidEmulator
-
-> ./mill show app.adbDevices
-...emulator-5554...device...
-
-> ./mill show app.it
-...
-[
-  "",
-  [
-    {
-      "fullyQualifiedName": "com.helloworld.app.ExampleInstrumentedTest.useAppContext",
-      "selector": "com.helloworld.app.ExampleInstrumentedTest.useAppContext",
-      "duration": ...,
-      "status": "Success"
-    }
-  ]
-]
-...
-
-> cat out/app/it/testTask.dest/test-report.xml
-...
-<?xml version='1.0' encoding='UTF-8'?>
-<testsuites tests="1" failures="0" errors="0" skipped="0" time="...">
-        <testsuite name="com.helloworld.app.ExampleInstrumentedTest.useAppContext" tests="1" failures="0" errors="0" skipped="0" time="0.0" timestamp="...">
-        <properties>
-      </properties>
-        <testcase classname="com.helloworld.app.ExampleInstrumentedTest.useAppContext" name="com.helloworld.app.ExampleInstrumentedTest.useAppContext" time="...">
-        </testcase>
-      </testsuite>
-      </testsuites>
-...
-
-> ./mill show app.stopAndroidEmulator
-
-> ./mill show app.deleteAndroidVirtualDevice
-
-*/
+// TODO: you should explain the essential lines of that files. (Callouts might come in handy)
diff --git a/website/docs/modules/ROOT/pages/android/java.adoc b/website/docs/modules/ROOT/pages/android/java.adoc
index aed8dd649e5..8d0a37cb55e 100644
--- a/website/docs/modules/ROOT/pages/android/java.adoc
+++ b/website/docs/modules/ROOT/pages/android/java.adoc
@@ -67,3 +67,8 @@ The `AndroidAppBundle` trait is used to create and manage Android App Bundles (A
 - **androidUnsignedBundle:** Uses the `bundleTool` to build an unsigned AAB from the bundle zip.
 
 - **androidBundle:** Signs the AAB using a specified keystore with the `jarsigner` tool, producing a signed Android App Bundle (AAB).
+
+
+== Using the R8 optimization tool in Android modules
+
+include::partial$example/android/javalib/5-R8.adoc[]

Thanks for the changes. I just added comments in the build file for the user. If you think something is not specified or needs more explanation, let me know

@lefou
Copy link
Member

lefou commented Apr 11, 2025

You haven't run the local page generator, have you?

Is there some way we can test/assert that R8 worked sufficiently well? E.g. check that the size is smaller than the size of the un-optimited build result. Something we could add to the tests?

@vaslabs
Copy link
Contributor

vaslabs commented Apr 11, 2025

This can also be helpful @irodotos7 to add more context .
My understanding is R8 is a drop in replacement for proguard and I think it's the default in modern applications (it used to be opt-in initially)

For example, gradle as part of the release apk creation runs task ':app:minifyReleaseWithR8' which is what the runR8 task tries to imitate, I would guess only advanced users would need to (if ever) modify this?

Some ideas

I think for the time being there's not much value documenting this extensively, we can hide the runR8 task instead (just have it as something that runs internally with androidReleaseInstall) .

For testing, we can do androidReleaseInstall and androidInstall and add an assertion that androidReleaseInstall generated APK is smaller?

EDIT: I wouldn't even have a separate R8 example, we know we haven't done a proper separation of release and debug install - yet -, I'd just have an androidReleaseApk in the basic example and do the size comparison until we complete the feature

WDYT?

.map(ref => {
def metaInfRoot(p: os.Path): os.Path = {
var current = p
while (!current.endsWith(os.rel / "META-INF")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed? and if it does, on first look it seems there will be an issue if there's no META-INF

@irodotos7 irodotos7 marked this pull request as draft April 14, 2025 08:30
@irodotos7 irodotos7 force-pushed the android/R8-optimization-small-version branch from 3de95b6 to 97a8f8f Compare April 15, 2025 06:29
@irodotos7 irodotos7 marked this pull request as ready for review April 15, 2025 06:31
@lihaoyi
Copy link
Member

lihaoyi commented Apr 19, 2025

I think this looks fine, @irodotos7 if you could rebase this on top of latest main I'll merge it

@irodotos7 irodotos7 force-pushed the android/R8-optimization-small-version branch from 3a3cb53 to 221a24b Compare April 23, 2025 07:19
# Conflicts:
#	example/androidlib/kotlin/1-hello-kotlin/app/proguard-rules.pro
#	example/androidlib/kotlin/1-hello-kotlin/app/test-proguard-rules.pro
#	libs/androidlib/src/mill/androidlib/AndroidModule.scala
@irodotos7 irodotos7 force-pushed the android/R8-optimization-small-version branch from c41b4ff to bcbb8d0 Compare April 23, 2025 08:11
@irodotos7
Copy link
Contributor Author

I think this looks fine, @irodotos7 if you could rebase this on top of latest main I'll merge it

@lihaoyi done

@lihaoyi lihaoyi merged commit 9af87fe into com-lihaoyi:main Apr 23, 2025
37 checks passed
@lefou lefou added this to the 0.13.0 milestone Apr 23, 2025
lihaoyi pushed a commit that referenced this pull request Apr 27, 2025
## Summary

- **better organisation** between androidmodule and androidappmodule
(separate properly what things are used in apps and things that are
shared between lib building and app building)
- R8 and D8 **dex generation** depending on build type settings
- **Instrumented tests** now use the android application namespace and
id and adding a "variant" indicator
- introduced a lite version of **build type settings** with main
motivation to control r8 and d8 but also serve as a scaffolding for
build variants
- **Android manifest** has less hardcoded parameters (uses-sdk and
instrumentation tags are now generated)
- Minor change into **testTask** to keep it consistent with the rest of
modules(Task.Anon) and thus the test-report is now in `testForked.dest`

## R8 and Proguard

Followed similar configuration style with gradle


![image](https://github.com/user-attachments/assets/c2c99135-6381-4c91-9ce2-ac5e666f5a33)

Although there's still work to be done in that area, if minification is
enabled, we use the R8 tool to generate the dex otherwise the d8 (which
also uses proguard for now) . This needs further work and clarification
as AGP seems to be using R8 by default when minification is enabled,
otherwise d8 is used.

Proguard default files are also fetched (as an opt-in setting) from the
Android SDK directories

## Build settings

I've introduced a first very minimal step for doing build variants,
mainly out of necessity to manage R8 and D8 variations better, but this
will be expanded once we need to fully support build variants.

The settings so far concerned the R8 use case at hand and it's a case
class that has the parameters to feed proguard files and flags into R8.

## R8 enhancements

Extending the work from #4892 ,
I've made some usability enhancements and enriched the examples to
demonstrate how instrumented tests can be used alongside R8 and release
builds.

I think R8 now can be fairly usable to generate minified and optimised
release builds without getting in the middle of development (e.g.
running tests and testing in the emulator) although more work needs to
be done towards that area, but we'll follow up after we do more
exploratory usability testing!

## Future work

Following this work, we can move to complete the work on architecture
samples by testing instrumented tests, unit tests and later on debug
variants.

The cleanup also reduced a lot of duplication between `AndroidAppModule`
and `AndroidModule` so it will make our development efforts a bit easier
to add more features!

More discovery work will follow to align the instrumented test apk
installation more in line with AGP
@vaslabs vaslabs mentioned this pull request Apr 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants