Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Hello world Kotlin Jetpack Compose Example; Fixes:#3550 #3696

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.helloworld.app">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="35"/>
<application android:label="Hello World" android:debuggable="true">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.helloworld.app

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting("Hello, World!")
}
}
}

@Composable
fun Greeting(name: String) {
Text(text = name)
}
45 changes: 45 additions & 0 deletions example/kotlinlib/android/2-jetpack-compose-hello-world/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//// SNIPPET:BUILD
package build

import mill._
import kotlinlib._
import coursier.maven.MavenRepository
import mill.kotlinlib.android.AndroidAppKotlinModule
import mill.javalib.android.AndroidSdkModule

val maven_google = Seq(
MavenRepository("https://maven.google.com/"),
MavenRepository("https://repo1.maven.org/maven2")
)

object androidSdkModule0 extends AndroidSdkModule {
def buildToolsVersion = "35.0.0"
}

object app extends AndroidAppKotlinModule {
def kotlinVersion = "2.0.20"
def androidSdkModule = mill.define.ModuleRef(androidSdkModule0)

override def mandatoryIvyDeps: T[Agg[Dep]] = Task {
super.mandatoryIvyDeps() ++ Agg(
// Jetpack Compose dependencies
ivy"androidx.compose.compiler:compiler:1.5.15",
ivy"androidx.activity:activity:1.8.2",
ivy"androidx.activity:activity-compose:1.8.2",
ivy"androidx.compose.runtime:runtime:1.3.1",
ivy"androidx.compose.material3:material3:1.0.1"
)
}

def repositoriesTask = T.task { super.repositoriesTask() ++ maven_google }

}

////SNIPPET:END

/** Usage

> ./mill show app.androidApk
".../out/app/androidApk.dest/app.apk"

*/
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package mill.kotlinlib.android

import mill.kotlinlib.KotlinModule
import mill.javalib.android.AndroidAppModule
import mill._
import coursier.Type
import upickle.default.ReadWriter

/**
* Trait for building Android applications using the Mill build tool.
Expand All @@ -18,4 +21,55 @@ import mill.javalib.android.AndroidAppModule
* [[https://developer.android.com/studio Android Studio Documentation]]
*/
@mill.api.experimental
trait AndroidAppKotlinModule extends AndroidAppModule with KotlinModule {}
trait AndroidAppKotlinModule extends AndroidAppModule with KotlinModule {
// Implicit ReadWriter for coursier.Type
implicit val coursierTypeRW: ReadWriter[Type] = upickle.default.readwriter[String].bimap(
t => t.value, // Convert coursier.Type to a String
Type(_) // Convert String back to coursier.Type
)

// Implicit ReadWriter for Set[coursier.Type]
implicit val coursierTypeSetRW: ReadWriter[Set[Type]] =
upickle.default.readwriter[Set[String]].bimap(
set => set.map(_.value), // Serialize Set[coursier.Type] to Set[String]
set => set.map(Type(_)) // Deserialize Set[String] to Set[coursier.Type]
)

// Artifact types to add "aar" type to the Set of artifact types
def artifactTypes: T[Set[Type]] =
T { super.artifactTypes() + coursier.Type("aar") }

// Task to extract JARs from AARs
def recompileAARs: T[Seq[PathRef]] = Task {
// Get all .aar files from the original compileClasspath
val aarFiles = super.compileClasspath().map(_.path).filter(_.ext == "aar").toSeq

// Extract classes.jar from each .aar file
val newJarFiles = aarFiles.map { aarFile =>
// Destination for extraction
val extractDir = T.dest / aarFile.baseName

// Unzip the .aar file
os.call(Seq("unzip", aarFile.toString, "-d", extractDir.toString))

// Return the PathRef to classes.jar file
PathRef(extractDir / "classes.jar")
}

newJarFiles
}

/**
* Updates the compile classpath to include classes `.jar` files.
* here we are also removing `.aar` coz they are not worthy after extraction
*/
def updatedCompileClasspath: T[Agg[PathRef]] = Task {
super.compileClasspath().filter(_.path.ext == "jar") ++ Agg.from(recompileAARs())
}

/**
* Overrides the classpath to include files as `.jar`.
*/
override def compileClasspath: T[Agg[PathRef]] = updatedCompileClasspath()

}
Loading