diff --git a/example/androidlib/java/1-hello-world/build.mill b/example/androidlib/java/1-hello-world/build.mill index 3d6a9be7d269..7b0be8298dcb 100644 --- a/example/androidlib/java/1-hello-world/build.mill +++ b/example/androidlib/java/1-hello-world/build.mill @@ -24,17 +24,6 @@ object app extends AndroidAppModule { def androidApplicationId = "com.helloworld.app" def androidApplicationNamespace = "com.helloworld.app" - /** - * 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: Option[String] = Some("releaseKey.jks") - 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" object test extends AndroidAppTests, TestModule.Junit4 { @@ -57,6 +46,18 @@ object app extends AndroidAppModule { ) } + /** + * 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. + */ + object release extends AndroidReleaseModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } + } } //// SNIPPET:END diff --git a/example/androidlib/java/2-app-bundle/build.mill b/example/androidlib/java/2-app-bundle/build.mill index f05d58782d5d..c298ca5592b8 100644 --- a/example/androidlib/java/2-app-bundle/build.mill +++ b/example/androidlib/java/2-app-bundle/build.mill @@ -17,19 +17,21 @@ object bundle extends AndroidAppBundle { def androidSdkModule = mill.api.ModuleRef(androidSdkModule0) def androidCompileSdk = 35 + def androidApplicationId = "com.helloworld.app" + def androidApplicationNamespace = "com.helloworld.app" + /** * 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 androidApplicationId = "com.helloworld.app" - def androidApplicationNamespace = "com.helloworld.app" - - def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") - def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } - def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } - def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } + object release extends AndroidReleaseModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } + } } //// SNIPPET:END diff --git a/example/androidlib/java/4-sum-lib-java/build.mill b/example/androidlib/java/4-sum-lib-java/build.mill index 20ef34f00105..c913e94feccd 100644 --- a/example/androidlib/java/4-sum-lib-java/build.mill +++ b/example/androidlib/java/4-sum-lib-java/build.mill @@ -40,16 +40,6 @@ object lib extends AndroidLibModule, PublishModule { developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi")) ) - /** - * 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 androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } - def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } - def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } - object test extends AndroidLibTests, TestModule.Junit4 { def mvnDeps = Seq(mvn"junit:junit:4.13.2") } diff --git a/example/androidlib/java/5-R8/build.mill b/example/androidlib/java/5-R8/build.mill index b1e189655ee1..67c209203abd 100644 --- a/example/androidlib/java/5-R8/build.mill +++ b/example/androidlib/java/5-R8/build.mill @@ -31,19 +31,7 @@ object app extends AndroidR8AppModule { // <2> def androidApplicationId = "com.helloworld.app" def androidApplicationNamespace = "com.helloworld.app" - /** - * 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: Option[String] = Some("releaseKey.jks") - 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" - override def androidIsDebug: T[Boolean] = Task { false } def androidProjectProguardFiles = Task.Sources( "proguard-rules.pro" @@ -58,10 +46,6 @@ object app extends AndroidR8AppModule { // <2> object it extends AndroidAppInstrumentedTests, AndroidR8AppModule { def androidSdkModule = mill.api.ModuleRef(androidSdkModule0) - override def androidIsDebug: T[Boolean] = Task { - false - } - override def androidReleaseSettings: T[AndroidBuildTypeSettings] = Task { AndroidBuildTypeSettings(isMinifyEnabled = false) } @@ -78,6 +62,18 @@ object app extends AndroidR8AppModule { // <2> ) } + object release extends AndroidReleaseModule, AndroidR8ReleaseModule + + /** + * 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: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } } // <1> Create and configure an Android SDK module to manage Android SDK paths and tools. diff --git a/example/androidlib/java/6-native-libs/build.mill b/example/androidlib/java/6-native-libs/build.mill index 3ffb464d1258..1c0ea3afd9b5 100644 --- a/example/androidlib/java/6-native-libs/build.mill +++ b/example/androidlib/java/6-native-libs/build.mill @@ -24,16 +24,6 @@ object app extends AndroidNativeAppModule { // <1> def androidApplicationId = "com.helloworld.app" def androidApplicationNamespace = "com.helloworld.app" - /** - * 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 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" def androidExternalNativeLibs = Task { // <2> @@ -58,6 +48,18 @@ object app extends AndroidNativeAppModule { // <1> ) } + /** + * 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. + */ + object release extends AndroidReleaseModule, AndroidNativeAppVariantModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } + } } // <1> You need to extend AndroidNativeLibs trait to use native libraries in the app. diff --git a/example/androidlib/kotlin/1-hello-kotlin/build.mill b/example/androidlib/kotlin/1-hello-kotlin/build.mill index eccccd80c698..a72107af30f2 100644 --- a/example/androidlib/kotlin/1-hello-kotlin/build.mill +++ b/example/androidlib/kotlin/1-hello-kotlin/build.mill @@ -28,20 +28,10 @@ object app extends AndroidAppKotlinModule { def androidApplicationId = "com.helloworld.app" def androidApplicationNamespace = "com.helloworld.app" - /** - * 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: Option[String] = Some("releaseKey.jks") - 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 = "kotlin-test" override def androidEmulatorPort: String = "5556" - override def androidIsDebug: T[Boolean] = Task { false } + override def androidIsDebug: T[Boolean] = Task { true } object test extends AndroidAppKotlinTests, TestModule.Junit4 { def junit4Version = "4.13.2" @@ -55,7 +45,7 @@ object app extends AndroidAppKotlinModule { // configuration but the apk signature will not match // the app apk override def androidIsDebug: T[Boolean] = Task { - false + true } def mvnDeps = Seq( @@ -65,6 +55,20 @@ object app extends AndroidAppKotlinModule { mvn"junit:junit:4.13.2" ) } + + /** + * 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. + */ + object release extends AndroidKotlinReleaseModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + 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 androidEmulatorPort = "5654" + } } //// SNIPPET:END @@ -117,7 +121,13 @@ object app extends AndroidAppKotlinModule { */ -// This command runs unit tests on your local environment. +// The android tests (existing typically in androidTest directory, aka instrumented tests) +// typically run on an android device. +// The createAndroidVirtualDevice command creates an AVD (Android Virtual Device) +// and the startAndroidEmulator command starts the AVD. The it task runs the integration tests +// against the available AVD. The stopAndroidEmulator command stops the AVD and the +// destroyAndroidVirtualDevice command destroys the AVD. +// The provided commands can be used in a CI/CD pipeline assuming the right setup is in place. /** Usage @@ -162,10 +172,31 @@ object app extends AndroidAppKotlinModule { */ -// The android tests (existing typically in androidTest directory, aka instrumented tests) -// typically run on an android device. -// The createAndroidVirtualDevice command creates an AVD (Android Virtual Device) -// and the startAndroidEmulator command starts the AVD. The it task runs the integration tests -// against the available AVD. The stopAndroidEmulator command stops the AVD and the -// destroyAndroidVirtualDevice command destroys the AVD. -// The provided commands can be used in a CI/CD pipeline assuming the right setup is in place. +// To create a release apk and run it, you can use the configured release submodule. +// Every AndroidAppModule can be configured with its own emulator, so you can easily +// avoid signature mismatches between debug and release as follows. + +/** Usage + +> ./mill app.release.createAndroidVirtualDevice + +> ./mill show app.release.startAndroidEmulator + +> ./mill app.release.androidInstall + +> ./mill show app.release.androidRun --activity com.helloworld.app.MainActivity +[ + "Starting: Intent { cmp=com.helloworld.app/.MainActivity }", + "Status: ok", + "LaunchState: COLD", + "Activity: com.helloworld.app/.MainActivity", + "TotalTime: ...", + "WaitTime: ...", + "Complete" +] + +> ./mill show app.release.stopAndroidEmulator + +> ./mill show app.release.deleteAndroidVirtualDevice + +*/ diff --git a/example/androidlib/kotlin/2-compose/app/releaseKey.jks b/example/androidlib/kotlin/2-compose/app/releaseKey.jks new file mode 100644 index 000000000000..4d1186a7dfc5 Binary files /dev/null and b/example/androidlib/kotlin/2-compose/app/releaseKey.jks differ diff --git a/example/androidlib/kotlin/2-compose/build.mill b/example/androidlib/kotlin/2-compose/build.mill index 64fb8212e99e..9197e654dec8 100644 --- a/example/androidlib/kotlin/2-compose/build.mill +++ b/example/androidlib/kotlin/2-compose/build.mill @@ -53,6 +53,18 @@ object app extends AndroidAppKotlinModule { mvn"androidx.tracing:tracing:1.2.0" ) + /** + * 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. + */ + object release extends AndroidKotlinReleaseModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } + } } //// SNIPPET:END diff --git a/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill b/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill index f38252c4c6ca..afc8d82c216c 100644 --- a/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill +++ b/example/androidlib/kotlin/4-sum-lib-kotlin/build.mill @@ -40,17 +40,6 @@ object lib extends AndroidLibKotlinModule, PublishModule { developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi")) ) - /** - * 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: Option[String] = Some("releaseKey.jks") - def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } - def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } - def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } - object test extends AndroidLibKotlinTests, TestModule.Junit4 { def junit4Version = "4.13.2" } @@ -78,6 +67,19 @@ object app extends AndroidAppKotlinModule { object test extends AndroidAppKotlinTests, TestModule.Junit4 { def junit4Version = "4.13.2" } + + /** + * 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. + */ + object release extends AndroidKotlinReleaseModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } + } } //// SNIPPET:END diff --git a/example/thirdparty/android-endless-tunnel/build.mill b/example/thirdparty/android-endless-tunnel/build.mill index 7bbec86eb8fc..9da61c822bbf 100644 --- a/example/thirdparty/android-endless-tunnel/build.mill +++ b/example/thirdparty/android-endless-tunnel/build.mill @@ -24,29 +24,23 @@ object `endless-tunnel` extends mill.api.Module { override def androidNativeLibName: T[String] = "libgame" + override def androidVirtualDeviceIdentifier: String = "cpp-test" + + override def androidCMakeExtraArgs: T[Seq[String]] = + super.androidCMakeExtraArgs() ++ Seq("-DANDROID_STL=c++_static") + /** * 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 androidReleaseKeyAlias: T[Option[String]] = Task { - Some("releaseKey") - } - - def androidReleaseKeyPass: T[Option[String]] = Task { - Some("MillBuildTool") + object release extends AndroidReleaseModule, AndroidNativeAppVariantModule { + def androidReleaseKeyName: Option[String] = Some("releaseKey.jks") + def androidReleaseKeyAlias: T[Option[String]] = Task { Some("releaseKey") } + def androidReleaseKeyPass: T[Option[String]] = Task { Some("MillBuildTool") } + def androidReleaseKeyStorePass: T[Option[String]] = Task { Some("MillBuildTool") } } - - def androidReleaseKeyStorePass: T[Option[String]] = Task { - Some("MillBuildTool") - } - - override def androidVirtualDeviceIdentifier: String = "cpp-test" - - override def androidCMakeExtraArgs: T[Seq[String]] = - super.androidCMakeExtraArgs() ++ Seq("-DANDROID_STL=c++_static") - } } diff --git a/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala b/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala index b94d379263fd..1886911c7f65 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidAppKotlinModule.scala @@ -333,4 +333,11 @@ trait AndroidAppKotlinModule extends AndroidKotlinModule, AndroidAppModule { out } + trait AndroidAppKotlinVariantModule extends AndroidKotlinVariantModule, AndroidAppKotlinModule { + override def sources: T[Seq[PathRef]] = outer.sources + override def resolutionParams: Task[ResolutionParams] = Task.Anon(outer.resolutionParams()) + } + + trait AndroidKotlinReleaseModule extends AndroidReleaseModule, AndroidAppKotlinVariantModule + } diff --git a/libs/androidlib/src/mill/androidlib/AndroidAppModule.scala b/libs/androidlib/src/mill/androidlib/AndroidAppModule.scala index 7b5311c94b33..e132aa8e604b 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidAppModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidAppModule.scala @@ -910,6 +910,17 @@ trait AndroidAppModule extends AndroidModule { outer => ) } + trait AndroidAppVariantModule extends AndroidVariantModule, AndroidAppModule { + override def androidApplicationId: String = outer.androidApplicationId + override def androidApplicationNamespace: String = outer.androidApplicationNamespace + + override def androidVirtualDeviceIdentifier: String = outer.androidVirtualDeviceIdentifier + } + + trait AndroidReleaseModule extends AndroidAppVariantModule, AndroidAppModule { + override def androidIsDebug: T[Boolean] = Task { false } + } + trait AndroidAppTests extends AndroidTestModule, AndroidAppModule { override def androidApplicationId: String = s"${outer.androidApplicationId}.test" override def androidApplicationNamespace: String = s"${outer.androidApplicationNamespace}.test" @@ -924,12 +935,6 @@ trait AndroidAppModule extends AndroidModule { outer => override def androidApplicationId: String = s"${outer.androidApplicationId}.test" override def androidApplicationNamespace: String = s"${outer.androidApplicationNamespace}.test" - override def androidReleaseKeyAlias: T[Option[String]] = outer.androidReleaseKeyAlias() - override def androidReleaseKeyName: Option[String] = outer.androidReleaseKeyName - override def androidReleaseKeyPass: T[Option[String]] = outer.androidReleaseKeyPass() - override def androidReleaseKeyStorePass: T[Option[String]] = outer.androidReleaseKeyStorePass() - override def androidReleaseKeyPath: T[Seq[PathRef]] = outer.androidReleaseKeyPath() - override def androidEmulatorPort: String = outer.androidEmulatorPort override def sources: T[Seq[PathRef]] = Task.Sources("src/androidTest/java") diff --git a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala index c71449a631c6..5ed3565de1aa 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidKotlinModule.scala @@ -224,6 +224,14 @@ trait AndroidKotlinModule extends KotlinModule with AndroidModule { outer => jars } + trait AndroidKotlinVariantModule extends AndroidVariantModule, AndroidKotlinModule { + override def kotlinVersion: T[String] = outer.kotlinVersion() + override def androidEnableCompose: T[Boolean] = outer.androidEnableCompose() + override def generatedSources: T[Seq[PathRef]] = outer.generatedSources() + override def androidCompiledModuleResources: T[Seq[PathRef]] = + outer.androidCompiledModuleResources() + } + trait AndroidKotlinTestModule extends KotlinTests, AndroidTestModule { override def kotlinVersion: T[String] = outer.kotlinVersion diff --git a/libs/androidlib/src/mill/androidlib/AndroidModule.scala b/libs/androidlib/src/mill/androidlib/AndroidModule.scala index 83b021d1b0fb..714fc41f78da 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidModule.scala @@ -871,6 +871,38 @@ trait AndroidModule extends JavaModule { outer => None } + trait AndroidVariantModule extends AndroidModule { + override def androidCompileSdk: T[Int] = outer.androidCompileSdk() + + override def androidMinSdk: T[Int] = outer.androidMinSdk() + + override def androidTargetSdk: T[Int] = outer.androidTargetSdk() + + override def androidSdkModule: ModuleRef[AndroidSdkModule] = outer.androidSdkModule + + override def androidManifest: T[PathRef] = outer.androidManifest() + + override def moduleDir: os.Path = outer.moduleDir + + override def androidNamespace: String = outer.androidNamespace + + override def sources: T[Seq[PathRef]] = outer.sources() + + override def androidResources: T[Seq[PathRef]] = outer.androidResources() + + override def mvnDeps: T[Seq[Dep]] = outer.mvnDeps() + + override def runMvnDeps: T[Seq[Dep]] = outer.runMvnDeps() + + override def compileMvnDeps: T[Seq[Dep]] = outer.compileMvnDeps() + + override def moduleDeps: Seq[JavaModule] = outer.moduleDeps + + override def bomMvnDeps: T[Seq[Dep]] = outer.bomMvnDeps() + + override def repositoriesTask: Task[Seq[Repository]] = Task.Anon(outer.repositoriesTask()) + } + trait AndroidTestModule extends JavaTests, AndroidModule { override def androidCompileSdk: T[Int] = outer.androidCompileSdk() diff --git a/libs/androidlib/src/mill/androidlib/AndroidNativeAppModule.scala b/libs/androidlib/src/mill/androidlib/AndroidNativeAppModule.scala index 57de74571058..46e2b5c32be5 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidNativeAppModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidNativeAppModule.scala @@ -4,7 +4,7 @@ import mill.T import mill.api.{PathRef, Task} @mill.api.experimental -trait AndroidNativeAppModule extends AndroidAppModule { +trait AndroidNativeAppModule extends AndroidAppModule { outer => def androidNativeSource: T[PathRef] = Task.Source { moduleDir / "src/main/cpp" @@ -123,7 +123,19 @@ trait AndroidNativeAppModule extends AndroidAppModule { */ override def androidPackageableExtraFiles: T[Seq[AndroidPackageableExtraFile]] = Task { super.androidPackageableExtraFiles() ++ androidPackageableNativeLibs() + } + + trait AndroidNativeAppVariantModule extends AndroidAppVariantModule, AndroidNativeAppModule { + + override def androidNativeSource: T[PathRef] = outer.androidNativeSource() + + override def androidExternalNativeLibs: T[Seq[PathRef]] = outer.androidExternalNativeLibs() + + override def androidNativeLibName: T[String] = outer.androidNativeLibName() + + override def androidCMakeExtraArgs: T[Seq[String]] = outer.androidCMakeExtraArgs() + override def androidCompileNative: T[PathRef] = outer.androidCompileNative() } } diff --git a/libs/androidlib/src/mill/androidlib/AndroidR8AppModule.scala b/libs/androidlib/src/mill/androidlib/AndroidR8AppModule.scala index 15866297782d..fc9986f7b8a6 100644 --- a/libs/androidlib/src/mill/androidlib/AndroidR8AppModule.scala +++ b/libs/androidlib/src/mill/androidlib/AndroidR8AppModule.scala @@ -448,4 +448,21 @@ trait AndroidR8AppModule extends AndroidAppModule { outer => } } + trait AndroidR8VariantModule extends AndroidVariantModule, AndroidR8AppModule { + override def androidProguard: T[PathRef] = outer.androidProguard() + + override def androidProjectProguardFiles: T[Seq[PathRef]] = outer.androidProjectProguardFiles() + + override def androidDefaultProguardFileNames: Task[Seq[String]] = + Task.Anon(outer.androidDefaultProguardFileNames()) + } + + trait AndroidR8ReleaseModule extends AndroidR8VariantModule { + override def androidReleaseSettings: T[AndroidBuildTypeSettings] = + outer.androidReleaseSettings() + + override def androidApplicationId = outer.androidApplicationId + override def androidApplicationNamespace = outer.androidApplicationNamespace + } + } diff --git a/website/docs/modules/ROOT/pages/android/android-release.adoc b/website/docs/modules/ROOT/pages/android/android-release.adoc index 9fc2e1994486..da5a26b956c5 100644 --- a/website/docs/modules/ROOT/pages/android/android-release.adoc +++ b/website/docs/modules/ROOT/pages/android/android-release.adoc @@ -5,10 +5,18 @@ By default, mill projects are considered in debug mode, so if your project is re The code snippets below should be added to your app object in the `build.mill` file. -== 1. Disable debug mode +== 1. Create a release submodule +To create a release build of your Android application, you need to define a release submodule that extends: + +- `AndroidReleaseModule` for Java projects +- `AndroidKotlinReleaseModule` for Kotlin projects + +Also extend with `AndroidNativeAppVariantModule` for NativeApp projects + +Example configuration: [source,scala] ---- -def androidIsDebug = Task { false } +object release extends AndroidKotlinReleaseModule ---- == 2. Configure signing information @@ -33,7 +41,7 @@ If you don't have a keystore yet, you can create one using the `keytool` command ---- == 3. (Optional) Enable ProGuard -If you want to enable ProGuard for code shrinking and obfuscation, you can do so by first extending your app object with `AndroidR8AppModule`. +If you want to enable ProGuard for code shrinking and obfuscation, you can do so by first extending your app object with `AndroidR8AppModule`, and your release submodule with `AndroidR8ReleaseModule`. You can then override the following methods. Example configuration: @@ -53,6 +61,8 @@ def androidProjectProguardFiles = Task.Sources("proguard-rules.pro") def androidDefaultProguardFileNames = Task.Anon { Seq("proguard-android-optimize.txt") } + +object release extends AndroidKotlinReleaseModule, AndroidR8ReleaseModule ---- == Some examples