Building an Android App With Claude Code: Kotlin, Compose and Gradle

  • 4 min read

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.

CommandPurposeWhen
./gradlew assembleDebugCompile and package a debug APKAfter every change
./gradlew testDebugUnitTestJVM unit tests (view models, repositories)After every change
./gradlew lintAndroid lint: API levels, accessibility, manifest issuesBefore each commit
./gradlew connectedDebugAndroidTestInstrumented and Compose UI tests on an emulatorBefore merging features
./gradlew bundleReleaseRelease AAB with R8 shrinkingBefore 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 UiState data class and a ViewModel exposing StateFlow<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 @Preview for 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

  1. Dependency sprawl. Adding libraries directly in build.gradle.kts instead of the version catalog, or pulling in a second networking or image library. Require catalog entries and review every new one.
  2. 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.
  3. Lifecycle blind spots. Collecting flows without lifecycle awareness, losing state on rotation or process death. Ask explicitly for collectAsStateWithLifecycle and SavedStateHandle where state must survive.
  4. Main-thread work. Database or file access on the main thread causes ANRs that hurt your Play Store vitals.
  5. R8 surprises. The debug build works, the release build crashes because serialization or reflection classes were stripped. Always test the release build before uploading.
  6. 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

Book a free call [email protected]

Book a free call