diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index a3f5a665d60..2918f145c5a 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -6,7 +6,6 @@ .xref:javalib/intro.adoc[] * xref:javalib/installation-ide.adoc[] * xref:javalib/builtin-commands.adoc[] -* xref:javalib/android-examples.adoc[] * xref:javalib/module-config.adoc[] * xref:javalib/dependencies.adoc[] * xref:javalib/testing.adoc[] @@ -14,6 +13,7 @@ * xref:javalib/publishing.adoc[] * xref:javalib/build-examples.adoc[] * xref:javalib/web-examples.adoc[] +* xref:javalib/android-examples.adoc[] .xref:scalalib/intro.adoc[] * xref:scalalib/installation-ide.adoc[] diff --git a/docs/modules/ROOT/pages/javalib/android-examples.adoc b/docs/modules/ROOT/pages/javalib/android-examples.adoc index 4e7323bbca3..28a26118678 100644 --- a/docs/modules/ROOT/pages/javalib/android-examples.adoc +++ b/docs/modules/ROOT/pages/javalib/android-examples.adoc @@ -1,4 +1,4 @@ -= Android Build Examples += (Experimental) Android Builds :page-aliases: android_app_examples.adoc ++++ @@ -7,12 +7,9 @@ gtag('config', 'AW-16649289906'); ++++ -This page provides examples of using Mill as a build tool for Android applications. -Each example highlights a specific aspect of Mill, allowing you to configure, test, and build Android apps efficiently. -By the end of this guide, you will understand how Mill can manage Android project structures, compile modules, and handle APK packaging. - -For detailed information, refer to Mill's https://com-lihaoyi.github.io/mill[official documentation], -and the https://developer.android.com/studio[Android Developer Guide]. +This page provides an example of using Mill as a build tool for Android applications. +This workflow is still pretty rough and nowhere near production ready, but can serve as +a starting point for further experimentation and development. == Relevant Modules @@ -26,18 +23,24 @@ These are the main Mill Modules that are relevant for building Android apps: include::partial$example/javalib/android/1-hello-world.adoc[] -This example demonstrates how to create a basic "Hello World" Android application using the Mill build tool. It outlines the minimum setup required to compile Java code, package it into an APK, and run the app on an Android device. +This example demonstrates how to create a basic "Hello World" Android application +using the Mill build tool. It outlines the minimum setup required to compile Java code, +package it into an APK, and run the app on an Android device. == Understanding `AndroidSdkModule` and `AndroidAppModule` -The two main modules you need to understand when building Android apps with Mill are `AndroidSdkModule` and `AndroidAppModule`. +The two main modules you need to understand when building Android apps with Mill +are `AndroidSdkModule` and `AndroidAppModule`. `AndroidSdkModule`: -* This module manages the installation and configuration of the Android SDK, which includes tools like `aapt`, `d8`, `zipalign`, and `apksigner`. These tools are crucial for compiling, packaging, and signing Android applications. +* This module manages the installation and configuration of the Android SDK, which includes +tools like `aapt`, `d8`, `zipalign`, and `apksigner`. These tools are used +for compiling, packaging, and signing Android applications. `AndroidAppModule`: -This module provides the step-by-step workflow for building an Android app. It handles everything from compiling the code to generating a signed APK for distribution. +This module provides the step-by-step workflow for building an Android app. It handles +everything from compiling the code to generating a signed APK for distribution. 1. **Compiling Java code**: The module compiles your Java code into `.class` files, which is the first step in creating an Android app. 2. **Packaging into JAR**: It then packages the compiled `.class` files into a JAR file, which is necessary before converting to Android's format. @@ -46,18 +49,4 @@ This module provides the step-by-step workflow for building an Android app. It h 5. **Optimizing with zipalign**: The APK is optimized using `zipalign` to ensure better performance on Android devices. 6. **Signing the APK**: Finally, the APK is signed with a digital signature, allowing it to be distributed and installed on Android devices. -== Testing Your Application - -You can perform manual testing on your Android APK to ensure it functions as expected. The Mill team is working on automating testing procedures for Android applications, which will be shared in future updates. - -== Why Use Mill for Android Development? - -Mill provides several advantages over other build tools, including: - -* **Efficiency**: Mill's build process is fast and optimized for minimal configuration, which speeds up the Android app creation process. - -* **Modularity**: Mill allows you to easily extend and customize your builds by leveraging its modular design. - -* **Scalability**: Mill can scale well for larger projects while maintaining simplicity in configuration. -By using Mill, you can streamline your Android app development, saving time and reducing complexity. diff --git a/example/javalib/android/1-hello-world/build.mill b/example/javalib/android/1-hello-world/build.mill index 63b06f1e87d..968d9108da2 100644 --- a/example/javalib/android/1-hello-world/build.mill +++ b/example/javalib/android/1-hello-world/build.mill @@ -52,18 +52,3 @@ object `package` extends RootModule with AndroidAppModule { // └── MainActivity.java // ---- // -// ### Mill Modules Overview: -// -// This project relies on three main modules: -// -// 1. **`AndroidSdkModule`**: This module manages all Android SDK interactions, including -// tools like `aapt` for resource packaging, `d8` for bytecode conversion, and `apksigner` for signing APKs. -// -// 2. **`JavaModule`**: This provides Java compilation tasks, including class file generation -// and creating JAR files, which are later converted to DEX format for Android. -// -// 3. **`AndroidAppModule`**: This module provides the step-by-step workflow for building an Android app. -// It handles everything from compiling the code to generating a signed APK for distribution. -// -// The combination of these modules allows us to automate the entire build process, -// from compiling Java code to producing a signed APK ready for distribution. diff --git a/scalalib/src/mill/javalib/android/AndroidAppModule.scala b/scalalib/src/mill/javalib/android/AndroidAppModule.scala index acbec541c98..aabdd926cc0 100644 --- a/scalalib/src/mill/javalib/android/AndroidAppModule.scala +++ b/scalalib/src/mill/javalib/android/AndroidAppModule.scala @@ -15,37 +15,14 @@ import mill.scalalib.JavaModule * including compiling Java sources, creating DEX files, generating resources, packaging * APKs, optimizing, and signing APKs. * - * The overall build process includes: - * - * 1. Compilation: Compiles the Java source code into `.class` files. - * - * 2. Packaging: Packages the compiled `.class` files into a JAR file. - * - * 3. Conversion to DEX: Converts the JAR file into DEX format (Android's runtime format). - * - * 4. APK Creation: Packages the DEX files and other resources into an APK. - * - * 5. Optimization: Optimizes the APK for better performance using zipalign. - * - * 6. Signing: Signs the APK with a digital signature for distribution. - * - * By following these steps, developers can automate their Android application build - * workflow using Mill and the Android SDK. - * - * Resources for further reading: - * - * [[https://com-lihaoyi.github.io/mill Mill Documentation]] - * * [[https://developer.android.com/studio Android Studio Documentation]] */ +@mill.api.experimental trait AndroidAppModule extends JavaModule { /** * Abstract method to provide access to the Android SDK configuration. * - * The `AndroidSdkModule` provides access to important SDK tools such as `aapt` (for packaging resources), - * `d8` (for compiling to DEX), `zipalign` (for APK optimization), and `apksigner` (for APK signing). - * * This method must be implemented by the concrete class to specify the SDK paths. * * @return The Android SDK module that is used across the project. @@ -53,16 +30,16 @@ trait AndroidAppModule extends JavaModule { def androidSdkModule: AndroidSdkModule /** - * Generates the Android resources (such as layouts, strings, and other assets) needed for the application. + * Generates the Android resources (such as layouts, strings, and other assets) needed + * for the application. * - * This method uses the Android `aapt` tool to compile resources specified in the project's `AndroidManifest.xml` - * and any additional resource directories. It creates the necessary R.java files and other compiled resources - * for Android. These generated resources are crucial for the app to function correctly on Android devices. + * This method uses the Android `aapt` tool to compile resources specified in the + * project's `AndroidManifest.xml` and any additional resource directories. It creates + * the necessary R.java files and other compiled resources for Android. These generated + * resources are crucial for the app to function correctly on Android devices. * * For more details on the aapt tool, refer to: * [[https://developer.android.com/tools/aapt2 aapt Documentation]] - * - * @return A `PathRef` pointing to the directory where the generated resources are stored. */ def androidResources: T[PathRef] = Task { val genDir: os.Path = T.dest // Directory to store generated resources. @@ -85,13 +62,6 @@ trait AndroidAppModule extends JavaModule { /** * Adds the Android SDK JAR file to the classpath during the compilation process. - * - * This method makes sure that the Android framework classes (like `android.view.View`) - * are available when compiling the Java sources. - * - * For more Information please check: JavaModule [[unmanagedClasspath]] - * - * @return A collection of paths that make up the unmanaged classpath, which includes the Android JAR. */ def unmanagedClasspath: T[Agg[PathRef]] = Task { Agg(androidSdkModule.androidJarPath()) @@ -101,12 +71,8 @@ trait AndroidAppModule extends JavaModule { * Combines standard Java source directories with additional sources generated by * the Android resource generation step. * - * This method ensures that generated files like `R.java` (which contain references to resources) + * Ensures that generated files like `R.java` (which contain references to resources) * are included in the source set and compiled correctly. - * - * For more Information please check: JavaModule [[generatedSources]] - * - * @return A sequence of source paths including both regular sources and generated ones. */ def generatedSources: T[Seq[PathRef]] = Task { super.generatedSources() ++ Seq(androidResources()) @@ -119,25 +85,8 @@ trait AndroidAppModule extends JavaModule { * suitable for Android (DEX). D8 converts the Java `.class` files into a jar file which is * suitable for DEX (Dalvik Executable) format and is required for Android runtime. * - * Why use D8 instead of standard JAR packaging: - * - * D8 Compiler: Converts Java bytecode into jar(with DEX support) files, optimized for Android. - * - * - Provides performance optimizations for Android devices, such as desugaring, - * which enables newer Java language features. - * - * - Results in smaller APK sizes, leading to faster and more efficient apps. - * - * Standard JAR Command: Simply packages `.class` files without applying Android-specific - * optimizations. It lacks the performance and size benefits provided by D8. - * - * Conclusion: Using D8 for creating JARs ensures smaller, faster applications optimized - * for the Android ecosystem. - * * For more details on the d8 tool, refer to: * [[https://developer.android.com/tools/d8 d8 Documentation]] - * - * @return A `PathRef` pointing to the generated JAR file. */ def androidJar: T[PathRef] = Task { val jarFile: os.Path = T.dest / "app.jar" @@ -158,14 +107,6 @@ trait AndroidAppModule extends JavaModule { /** * Converts the generated JAR file into a DEX file using the `d8` tool. - * - * DEX (Dalvik Executable) files are the binary format for Android applications. This method - * takes the JAR file created in the previous step and converts it into one or more DEX files. - * - * This step is crucial because Android devices do not execute `.class` files directly; - * they require the code to be in DEX format. - * - * @return A `PathRef` pointing to the folder containing the generated DEX files. */ def androidDex: T[PathRef] = Task { val dexOutputDir: os.Path = T.dest @@ -187,8 +128,6 @@ trait AndroidAppModule extends JavaModule { * The `aapt` tool takes the DEX files (compiled code) and resources (such as layouts and assets), * and packages them into an APK (Android Package) file. This APK file is unsigned and requires * further processing to be distributed. - * - * @return A `PathRef` pointing to the unsigned APK file. */ def androidUnsignedApk: T[PathRef] = Task { val unsignedApk: os.Path = T.dest / "app.unsigned.apk" @@ -213,14 +152,8 @@ trait AndroidAppModule extends JavaModule { /** * Optimizes the APK using the `zipalign` tool for better performance. * - * The `zipalign` tool ensures that all uncompressed data in the APK is aligned on a 4-byte boundary. - * This is required for better performance on Android devices. This step is done after the APK - * is created but before it is signed. - * * For more details on the zipalign tool, refer to: * [[https://developer.android.com/tools/zipalign zipalign Documentation]] - * - * @return A `PathRef` pointing to the aligned APK file. */ def androidAlignedUnsignedApk: T[PathRef] = Task { val alignedApk: os.Path = T.dest / "app.aligned.apk" @@ -250,8 +183,6 @@ trait AndroidAppModule extends JavaModule { * * For more details on the apksigner tool, refer to: * [[https://developer.android.com/tools/apksigner apksigner Documentation]] - * - * @return A `PathRef` pointing to the signed APK. */ def androidApk: T[PathRef] = Task { val signedApk: os.Path = T.dest / "app.apk" @@ -286,8 +217,6 @@ trait AndroidAppModule extends JavaModule { * * For more details on the keytool utility, refer to: * [[https://docs.oracle.com/javase/8/docs/technotes/tools/windows/keytool.html keytool Documentation]] - * - * @return A `PathRef` pointing to the keystore file. */ def androidKeystore: T[PathRef] = Task { val keystoreFile: os.Path = T.dest / "keystore.jks" diff --git a/scalalib/src/mill/javalib/android/AndroidSdkModule.scala b/scalalib/src/mill/javalib/android/AndroidSdkModule.scala index 3b667091d88..9bec5e3419d 100644 --- a/scalalib/src/mill/javalib/android/AndroidSdkModule.scala +++ b/scalalib/src/mill/javalib/android/AndroidSdkModule.scala @@ -11,13 +11,10 @@ import mill._ * an Android development environment, streamlining the process of building, * compiling, and packaging Android applications in a Mill project. * - * The trait handles tasks such as fetching the Android SDK, managing versions - * of the build tools, providing paths to necessary executables, and setting up - * resources required for compiling, optimizing, and signing Android apps. - * - * For more information, refer to Mill's [[https://com-lihaoyi.github.io/mill documentation]], - * and the official Android [[https://developer.android.com/studio documentation]]. + * For more information, refer to the official Android + * [[https://developer.android.com/studio documentation]]. */ +@mill.api.experimental trait AndroidSdkModule extends Module { /**