Quick start
Go from one Kotlin file to an app running on an emulator or your phone, then add a second screen and turn on live reload. About ten minutes, most of it the first Gradle download.
Key takeaways
- A folder with a single
MainActivity.ktis a complete project. --runbuilds, installs and launches.--watchdoes that again on every save.- Add files and screens freely: packages and the manifest are handled for you.
Before you start
Install the requirements: Python 3.8+, JDK 17+ and the Android SDK, plus an emulator or a phone with USB debugging.
1. Write one Kotlin file
Create a folder called tap-counter with a file MainActivity.kt. The button is deliberately large and placed at the bottom, where a thumb can reach it (see the thumb zone):
package com.example.tapcounter
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface(Modifier.fillMaxSize()) {
TapCounter()
}
}
}
}
}
@Composable
fun TapCounter() {
var taps by rememberSaveable { mutableIntStateOf(0) }
Column(
modifier = Modifier.fillMaxSize().padding(24.dp),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("$taps", style = MaterialTheme.typography.displayLarge, modifier = Modifier.padding(top = 96.dp))
Button(onClick = { taps++ }, modifier = Modifier.fillMaxWidth().height(72.dp)) {
Text("Tap", style = MaterialTheme.typography.headlineSmall)
}
}
}
No build.gradle.kts, no manifest, no res/ folder. rememberSaveable keeps the count when the phone rotates; designing for interruptions explains why that matters.
2. Run it
python3 android_scaffold.py tap-counter --name "Tap Counter" --run
The script prints what it found, then works through each step:
[*] Scanned source 'tap-counter':
- Scaffold Mode : Creating new scaffold
- Kotlin Files : 1 file(s)
- Base Package : com.example.tapcounter
- Launcher Activity : com.example.tapcounter.MainActivity
- Output Directory : android_build
- Generates the Gradle project, manifest and launcher icon in
android_build/. - Builds a debug APK with the Gradle wrapper.
- Boots an emulator, or uses the phone you've plugged in.
- Installs and opens the app.
- Copies the APK to
apk/, ready to send to any Android phone.
The first run downloads the Gradle distribution and the AndroidX libraries, which can take a few minutes. Later builds are incremental and much faster.
3. Add a second screen
Drop another Activity into the folder, in any subfolder or package you like:
package com.example.tapcounter.history
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
class HistoryActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { Text("History") }
}
}
Run the same command again. The file is placed in com/example/tapcounter/history/ and HistoryActivity is registered in the manifest automatically. Most Compose apps keep a single Activity and switch screens inside it, which is what the Thumb Inventory example does, but both work.
4. Turn on live reload
python3 android_scaffold.py tap-counter --watch
Change the button label, save, and the app relaunches with your change a few seconds later. Read live reload with --watch for how it decides what to rebuild.
5. Share the APK
The debug APK in apk/ can be sent through any chat app or email and installed on another phone after allowing installs from that source. It is signed with a debug key, which is fine for prototypes and internal tools but not for the Play Store.
Next steps
- Learn what the generated project contains.
- Read designing for small screens before you build the real thing.
- Open
src/and run the Thumb Inventory example with--watch.
Frequently asked questions
What is the smallest possible android_scaffold project?
A folder, or even a single .kt file, containing one class that extends ComponentActivity. You can pass the file directly: python3 android_scaffold.py MainActivity.kt --run.
What if my file has no package line?
It is given the base package, which comes from your MainActivity, or the shortest declared package, or com.example.singlefileapp if no file declares one.
Where does the generated project go?
Into ./android_build by default. Change it with --output. It is a normal Gradle project, so you can also open it in Android Studio.