Skip to content

Commit f8a4652

Browse files
committed
more demo docused
1 parent 45a2a7d commit f8a4652

File tree

2 files changed

+101
-16
lines changed

2 files changed

+101
-16
lines changed
225 KB
Loading

website/blog/modules/ROOT/pages/15-android-build-flow.adoc

Lines changed: 101 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,49 @@
77
_{author}, {revdate}_
88

99

10-
Until recently, Gradle was the only realistic option for Android builds. Today, Mill - a fast, predictable build tool for Java, Scala, and Kotlin - can build Android applications end-to-end.
10+
Until recently, Gradle was the only realistic option for Android builds. Today, Mill provides an alternative to Gradle that is easier to use and learn.
1111

12-
In less than a year, Mill went from minimal Android support to producing installable APKs for projects as complex as xref:mill::android/hilt-sample.adoc[the Android Architecture Samples] and https://github.com/vaslabs/Pokedex_Compose_Multi_Module/tree/testing-mill[multi-module apps] with xref:mill::android/java.adoc#_using_third_party_native_libraries[native code] and xref:mill::android/compose-samples.adoc[Jetpack Compose].
12+
In less than a year, Mill went from minimal Android support to producing installable APKs for projects as complex as:
13+
14+
- xref:mill::android/hilt-sample.adoc[Jetpack compose + Dependency Injection with Hilt]
15+
- xref:mill::android/java.adoc#_using_third_party_native_libraries[Android Native]
16+
- xref:mill::android/compose-samples.adoc[Jetpack Compose].
1317
// end::header[]
14-
Multi-module Pokedex sample app (https://github.com/NicosNicolaou16/Pokedex_Compose_Multi_Module[original], https://github.com/vaslabs/Pokedex_Compose_Multi_Module/tree/testing-mill[with mill])
18+
19+
- Multi-module Pokedex sample app (https://github.com/NicosNicolaou16/Pokedex_Compose_Multi_Module[original], https://github.com/vaslabs/Pokedex_Compose_Multi_Module/tree/testing-mill[with mill])
1520
image:AndroidPokedexMultimoduleExample.png[A multi-module Android app built with Mill, showing a list of Pokémon and details for each pokemon.]
1621
17-
Unlike Gradle, where build steps are buried inside plugins and DSL magic, Mill exposes each Android step as a task you can run, override, or extend.
18-
Want to see the merged manifest? Run
19-
[,console]
20-
----
21-
./mill app.androidMergedManifest
22-
----
2322
24-
Curious what rules are passed to R8? Run
23+
=== Why you might prefer this to Gradle
24+
25+
Because Mill’s Android support is built out of simple, object-oriented modules (AndroidModule, AndroidAppModule, etc.), the entire pipeline is transparent and hackable. If something doesn’t work, you don’t need to wait for a plugin update — you can open the task in your IDE, see the source, and tweak it yourself. This is the same design that let us implement end-to-end Android support in under a year, and it’s what makes Mill attractive if you value control and debuggability in your build.
26+
27+
For instance, you can inspect Mill's android packaging process with:
28+
2529
[,console]
2630
----
27-
./mill app.androidProguard
28-
----
31+
$ ./mill __.androidApk
32+
[1/1] inspect
33+
app.androidApk(AndroidAppModule.scala:439)
34+
Signs the APK using a keystore to generate a final, distributable APK.
2935
30-
Because Mill’s Android support is built out of simple, object-oriented modules (AndroidModule, AndroidAppModule, etc.), the entire pipeline is transparent and hackable. If something doesn’t work, you don’t need to wait for a plugin update — you can open the task in your IDE, see the source, and tweak it yourself. This is the same design that let us implement end-to-end Android support in under a year, and it’s what makes Mill attractive if you value control and debuggability in your build.
36+
The signing step is mandatory to distribute Android applications. It adds a cryptographic
37+
signature to the APK, verifying its authenticity. This method uses the `apksigner` tool
38+
along with a keystore file to sign the APK.
3139
32-
This post is a walk through of the basic Android build flow in Mill: what it does, why it’s complex, and why Mill makes it easier to reason about.
40+
If no keystore is available, a new one is generated using the `keytool` utility.
41+
42+
For more details on the apksigner tool, refer to:
43+
[[https://developer.android.com/tools/apksigner apksigner Documentation]]
44+
45+
Inputs:
46+
androidSdkModule0.apksignerPath
47+
app.androidAlignedUnsignedApk
48+
app.androidSignKeyDetails
49+
...
50+
----
3351

52+
This post is a walk through of the basic Android build flow in Mill: what it does, why it’s complex, and why Mill makes it easier to reason about.
3453

3554
== The Android build process
3655

@@ -208,15 +227,81 @@ Start the emulator and run the app
208227
./mill show app.androidRun --activity com.example.android.architecture.blueprints.todoapp.TodoActivity
209228
----
210229

230+
The Android Todo App built with Mill
231+
image:AndroidTodoExample.png[The Todo app built with Mill, showing a list of tasks and a button to add new tasks.]
232+
211233
Run the instrumented tests and watch the app being tested inside the emulator:
212234

213235
[source,bash]
214236
----
215237
./mill app.androidTest
216238
----
217239

218-
The Android Todo App built with Mill
219-
image:AndroidTodoExample.png[The Todo app built with Mill, showing a list of tasks and a button to add new tasks.]
240+
Let's say you want to know how the apk is built. First, you can check the plan of `androidApk`, i.e which
241+
tasks it depends on:
242+
[,console]
243+
----
244+
$ ./mill plan app.androidApk
245+
[1/1] plan
246+
androidSdkModule0.sdkPath
247+
androidSdkModule0.buildToolsVersion
248+
androidSdkModule0.platformsVersion
249+
androidSdkModule0.remoteReposInfo
250+
androidSdkModule0.installAndroidSdkComponents
251+
androidSdkModule0.buildToolsPath
252+
androidSdkModule0.apksignerPath
253+
androidSdkModule0.zipalignPath
254+
app.mandatoryMvnDeps.super.javalib.JavaModule
255+
app.kotlinVersion
256+
----
257+
258+
259+
You can use this to visualise the relationships between these tasks and how they feed each other and ultimately the `androidApk` task:
260+
261+
[,console]
262+
----
263+
$ ./mill visualizePlan app.androidApk
264+
[3/3] visualizePlan
265+
[
266+
".../architecture-samples/out/visualizePlan.dest/out.dot",
267+
".../architecture-samples/out/visualizePlan.dest/out.json",
268+
".../architecture-samples/out/visualizePlan.dest/out.png",
269+
".../architecture-samples/out/visualizePlan.dest/out.svg",
270+
".../architecture-samples/out/visualizePlan.dest/out.txt"
271+
]
272+
[3/3] ============================== visualizePlan app.androidApk ============================== 2s
273+
----
274+
275+
You can also check the code of each task and what it does exactly inside your IDE:
276+
image:AndroidIDEExplore.png[Exploring the Mill Android build tasks in an IDE, showing the source code for the androidApk task.]
277+
278+
279+
In addition, due to xref:12-direct-style-build-tool.adoc#_direct_style_builds[Mill's direct style], you can reason what's going on with relative ease.
280+
281+
=== Example: tweak the build in your `build.mill`
282+
[source,scala]
283+
----
284+
import mill._
285+
import mill.androidlib._
286+
287+
object app extends AndroidAppModule {
288+
def androidApplicationNamespace = "com.example.app"
289+
def androidApplicationId = "com.example.app"
290+
def androidCompileSdk = 35
291+
292+
// Add extra files into the APK
293+
override def androidPackageableExtraFiles = super.androidPackageableExtraFiles()
294+
Seq(
295+
AndroidPackageableExtraFile(
296+
PathRef(moduleDir / "assets/about.txt"),
297+
os.RelPath("assets/about.txt")
298+
)
299+
)
300+
301+
}
302+
----
303+
304+
=== Further Exploration
220305

221306
You may also inspect xref:mill::android/android-initial-setup.adoc[the getting started docs] to find out more.
222307

0 commit comments

Comments
 (0)