Building an Android App With Claude Code: Kotlin, Compose and Gradle
Short answer
Android suits Claude Code well because the whole toolchain – Gradle, lint, unit tests and even the emulator – runs from the terminal. Start from an Android Studio template, pin dependencies in a version catalog, give the agent fixed Gradle commands as its definition of done, and review manifest permissions, R8 rules and target SDK yourself before release.
Of all the mobile stacks, native Android is probably the easiest one to hand to a terminal-based coding agent. There is no proprietary IDE dependency for builds, Gradle tasks are scriptable, and Kotlin with Jetpack Compose produces compact, reviewable code. This guide focuses on the mechanics: which commands to give Claude Code, how to phrase Compose tasks, and the Android-specific mistakes agents tend to make.
Starting point: template, not blank page
Create the project with Android Studio's "Empty Activity" (Compose) template, or from a starter your team maintains. That gives you a working Gradle wrapper, a version catalog (libs.versions.toml), and sane defaults for minSdk, compileSdk and targetSdk. Let the agent extend a known-good build instead of inventing one: Gradle plugin and Kotlin version mismatches are the single most common source of wasted agent iterations.
Pick the applicationId now. It becomes permanent with your first Play Store upload.
Commands the agent should own
Write these into CLAUDE.md as the definition of done. The agent runs them after every change and fixes what fails.
| Command | Purpose | When |
|---|---|---|
./gradlew assembleDebug | Compile and package a debug APK | After every change |
./gradlew testDebugUnitTest | JVM unit tests (view models, repositories) | After every change |
./gradlew lint | Android lint: API levels, accessibility, manifest issues | Before each commit |
./gradlew connectedDebugAndroidTest | Instrumented and Compose UI tests on an emulator | Before merging features |
./gradlew bundleRelease | Release AAB with R8 shrinking | Before every store upload |
Running an emulator headlessly on a CI machine or Linux workstation is possible but resource-hungry. Many teams let the agent run unit tests constantly and run instrumented tests in CI or on demand.
Prompt patterns for Jetpack Compose
Compose rewards precise requests. Patterns that produce good results:
- State first, UI second. "Define a
UiStatedata class and aViewModelexposingStateFlow<UiState>for the order list, with loading, empty, error and content states. Then write the composable that renders each state. Add unit tests for the view model." - Stateless composables. Ask for composables that receive state and callbacks as parameters, plus a
@Previewfor each state. These are easy to test and easy to review. - Name the libraries. "Use Hilt for DI, Retrofit with kotlinx.serialization, Room for persistence, Navigation Compose" – otherwise each session may pick something different.
- Constrain the scope. "Only modify files in
feature/orders." Agents like to "improve" neighboring code.
Agent mistakes specific to Android
- Dependency sprawl. Adding libraries directly in
build.gradle.ktsinstead of the version catalog, or pulling in a second networking or image library. Require catalog entries and review every new one. - Manifest creep. New permissions appear quietly, sometimes from libraries via manifest merging. Inspect the merged manifest before each release; extra permissions affect the Data safety form and can trigger policy questions.
- Lifecycle blind spots. Collecting flows without lifecycle awareness, losing state on rotation or process death. Ask explicitly for
collectAsStateWithLifecycleandSavedStateHandlewhere state must survive. - Main-thread work. Database or file access on the main thread causes ANRs that hurt your Play Store vitals.
- R8 surprises. The debug build works, the release build crashes because serialization or reflection classes were stripped. Always test the release build before uploading.
- Outdated APIs. Models trained on years of Android code sometimes reach for deprecated APIs. Lint flags many of these; treat its warnings as tasks.
A project layout the agent can navigate
Agents work best when the codebase tells them where things belong. A single app module is fine for a prototype, but once the app has more than a handful of screens, a simple modular layout pays off:
app– application class, navigation graph, dependency injection setup.core/ui– theme, typography, shared components, so the agent stops redefining colors per screen.core/data– networking, database, repositories.feature/*– one module or package per feature, each with its screens, view models and tests.
Describe this layout in CLAUDE.md with one sentence per folder. When you ask for a new feature, name the target folder explicitly. The result is smaller diffs, fewer accidental changes to shared code and faster incremental Gradle builds, which in turn shortens the agent's feedback loop.
Testing strategy in one paragraph
Have the agent write unit tests for every view model and repository, Compose UI tests for the two or three flows that make money or create accounts, and a screenshot or smoke test that launches the release build. Ask it to write the failing test before fixing any bug you report. For a wider look at verifying generated code, see testing strategies for AI-generated code; for instruction-file structure, AGENTS.md and CLAUDE.md explained.
From APK to Play Store
A working debug APK is perhaps half the journey. Google Play adds a closed-testing period for many new personal accounts, Play App Signing, the Data safety form and target SDK requirements. The full sequence is in from Claude Code to Google Play; the equivalent with OpenAI's agent is in Codex + Kotlin: releasing an agent-built Android app.
If you want the release pipeline done properly the first time, appsubmitter.io sets up CI/CD, handles signing and submission in your own Play Console account and helps when a review comes back with questions. Ongoing feature work with a mix of AI and human developers is what apprat.io is built for.
Frequently asked questions
Can Claude Code run the Android emulator?
Yes, it can start an emulator and run instrumented tests through Gradle if the Android SDK and system images are installed. It is resource-intensive, so many teams run those tests in CI and keep unit tests in the agent's inner loop.
Should I use Jetpack Compose or XML views with Claude Code?
Compose is usually the better fit for new apps: code is compact, previews are easy and state handling is explicit. XML views remain fine for maintaining existing apps.
Why does my agent-built release build crash when the debug build works?
Usually R8 code shrinking removed classes used through reflection or serialization. Add keep rules or use libraries with built-in rules, and always test the release build before uploading.
Do I still need Android Studio?
Not for building, but it remains the best tool for layout inspection, profiling, debugging on devices and managing emulators. Most teams use it alongside Claude Code.
Talk to us about your project
Honest advice on your idea, prototype or app.
- 30 minutes
- Free
- No obligation
