Skip to content

Conversation

@vaslabs
Copy link
Contributor

@vaslabs vaslabs commented Oct 31, 2025

This is related to #6064

Improvements

  • Aligning base module and androidTest dependencies is no longer necessary
  • Properly passing compile classpath to R8 makes the R8 workaround error -> warning mapping not necessary
  • The test apk size is now greatly reduced (from >20MB to <1MB in most cases)
  • With the new AndroidR8InstrumentedTestsModule , androidTests apk can also be minified as the androidGeneratedMinifyKeepRules is only available in R8 modules
App Mill Size Gradle Size
Jetchat 760KB 1019KB
JetNews 742KB 999KB
Architecture Samples 4.3MB 5.6MB

Fixes

  • Cyclic dependency issue when compiling r classes
  • Jetchat android tests

Implementation details

Introduced a new AndroidR8InstrumentedTestsModule which builds the test apk excluding the dependency tree of the base module (base apk) with 2 important tasks:

  • androidR8CompileOnlyClasspath incorporates the whole base apk (but as a jar file)
  • androidResolvedPackagableMvnDeps excludes the dependencies of the base module via androidPackagableMvnDeps and is used in place of resolvedRunMvnDeps .

Extensions

To do the dependency resolution again by excluding the dependency tree, without breaking the examples, I needed a way to pass the bom to the defaultResolver().classpath . Thus I extended the methods needed and fixed any MiMa issues with @unroll , although I haven't used it before, this is what I've found from looking around, so please let me know if this was a mistake

Further work

Testing a few apps, there was a case where a test dependency was pulling com.google.android.material:material which in turn depends on appcompat android resources, so aapt2 linking was failing.

I tried to see if aapt2 link -I argument would be of any help, but it seems I'm missing something, it appears only one artifact can be passed to it, tried several usage variations without luck

Gradle incorporates these resources without an issue, so it means we need to find a way to link the resources against the base module resources and at the same time avoid duplicate contents

I think it's a very niche use case, as typically runtime usage of these resources will be done in the base apk. For now, I added the appcompat explicitly in the androitTest mvnDeps so the linking goes through

@autofix-ci
Copy link
Contributor

autofix-ci bot commented Oct 31, 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).

@vaslabs
Copy link
Contributor Author

vaslabs commented Oct 31, 2025

with the R8 classpath fix I'm very close to replicating the same test apk as gradle

image

@lefou
Copy link
Member

lefou commented Nov 1, 2025

This PR is far from functional, just posting if someone knows a few tips on the best way to exclude the dependency tree of the app module from the androidTest one

Each JavaModule has a coursierProject representing the internal coursier representation of the dependencies and constraints. Those get collected in transitiveCoursierProjects before resolution starts. Maybe, you can hook in there, to make the app module dep tree intransitive or something like that.

vaslabs added a commit to vaslabs-ltd/compose-samples-with-mill that referenced this pull request Nov 1, 2025
@vaslabs
Copy link
Contributor Author

vaslabs commented Nov 1, 2025

This PR is far from functional, just posting if someone knows a few tips on the best way to exclude the dependency tree of the app module from the androidTest one

Each JavaModule has a coursierProject representing the internal coursier representation of the dependencies and constraints. Those get collected in transitiveCoursierProjects before resolution starts. Maybe, you can hook in there, to make the app module dep tree intransitive or something like that.

thanks, I have it somewhat functional now. The problem is this as the steps in the packaging flow goes (just thinking out loud):

  1. The dependency tree is needed for compilation
  2. when packaging the test apk, the dependencies that were used for the base apk need to be excluded. This is somewhat problematic to do on a jar by jar basis (I started with this approach) because the versions don't always match between what the test deps pull and what the base module pulls

This extends beyond the jars, anything like android resources, native libs, meta info files. So it seems on a first glance that this transitiveCoursierProjects can be useful, if the androidTest compileClasspath has the base apk deps so that we can compile the test code , but not package it.

Thanks for the tip, now that I have 2 complex examples working, I can make this less hacky!

EDIT: Hm, I think after introducing the androidR8Jar I can use that in the android compile classpath and have no module dependency between the 2

@vaslabs
Copy link
Contributor Author

vaslabs commented Nov 1, 2025

For the case of jet-chat I've even managed to exclude redundant things that are included in the gradle test apk

Mill with this PR

image

Gradle

image

@vaslabs
Copy link
Contributor Author

vaslabs commented Nov 1, 2025

EDIT: Hm, I think after introducing the androidR8Jar I can use that in the android compile classpath and have no module dependency between the 2

The problem is that I still have to compute the dependency exclusions, because the test deps might bring the same dependencies as in base module/apk and even worse , different versions.

@vaslabs
Copy link
Contributor Author

vaslabs commented Nov 1, 2025

I've done some cleanup, avoiding duplication by overriding the resolvedRunMvnDeps.

I've tried a few other methods but it starts to get a bit complicated to play with coursier + manage the kotlin friend paths, I ended up having even more duplication.

I think with the latest commit, the implementation is fairly clean, but I'm open of course to further comments and suggestions to try .

In terms of technical things and results, this PR allows mill to produce tiny test apks.

Some result comparisons:

App Mill Size Gradle Size
Jetchat 760KB 1019KB
JetNews 742KB 999KB
Architecture Samples 4.3MB 5.6MB

With the newest changes, there's a problem with androidtodo, so still not ready but will update accordingly

EDIT: I've added a small workaround for now for androidtodo and also kept backwards compatibility if the new AndroidR8InstrumentedTests is not extended

In addition to these size improvements, there's further improvement of setting up mill demonstrated here with a lot of duplicated dependencies not being needed in android test . Also the r8 error to warning mapping is no longer needed

If one wishes to reproduce these results, this branch should be built locally and then start an emulator and run mill Jetchat.app.androidTest .

@vaslabs
Copy link
Contributor Author

vaslabs commented Nov 1, 2025

I need to figure out how to fix mima due to the added bom argument in a few methods, but apart from that , I'm open to review and comments

@vaslabs vaslabs marked this pull request as ready for review November 1, 2025 17:57
@vaslabs vaslabs marked this pull request as draft November 2, 2025 07:07
@vaslabs vaslabs marked this pull request as ready for review November 2, 2025 07:59
@lihaoyi lihaoyi merged commit 581a433 into com-lihaoyi:main Nov 2, 2025
24 of 25 checks passed
@lefou lefou added this to the after 1.0.6 milestone Nov 2, 2025
vaslabs added a commit to vaslabs-ltd/compose-samples-with-mill that referenced this pull request Nov 5, 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.

3 participants