---
name: android-dev
description: Build Android apps from the ARM64 Oracle server — SDK setup, Gradle/AGP compatibility, Box64 for AAPT2, common build errors, and ADB sideload to connected devices.
category: software-development
metadata:
  hermes:
    emoji: "📱"
---

# Android Development on ARM64 Oracle Server

Build Android APKs on the ARM64 Oracle Cloud server without Android Studio.

## Environment

- Ubuntu 24.04 ARM64 (Oracle Cloud)
- Java 17 OpenJDK: `sudo apt install -y openjdk-17-jdk-headless`
- Box64 for x86_64 binaries (AAPT2): `sudo apt install -y box64`
- Gradle: download binary to `/opt/gradle-8.11.1`, symlink to `/usr/local/bin/gradle`
- Android SDK: `/opt/android-sdk/` owned by `ubuntu`

## Initial Setup

```bash
# 1. Java
sudo apt install -y openjdk-17-jdk-headless

# 2. Box64 (CRITICAL for ARM64 — AAPT2 is x86_64 only)
sudo apt install -y box64 unzip

# 3. Android SDK command-line tools
sudo mkdir -p /opt/android-sdk/cmdline-tools
sudo chown -R ubuntu:ubuntu /opt/android-sdk
cd /tmp
curl -sL -o cmdline-tools.zip "https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
unzip -q cmdline-tools.zip
mv cmdline-tools /opt/android-sdk/cmdline-tools/latest

# 4. Install SDK components
export ANDROID_HOME=/opt/android-sdk
export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$PATH
yes | sdkmanager --licenses
sdkmanager "platform-tools" "platforms;android-36" "build-tools;34.0.0"

# 5. Gradle (AGP 8.9.x requires Gradle 8.11.1+)
curl -sL -o /tmp/gradle.zip "https://services.gradle.org/distributions/gradle-8.11.1-bin.zip"
sudo unzip -q /tmp/gradle.zip -d /opt
sudo ln -sf /opt/gradle-8.11.1/bin/gradle /usr/local/bin/gradle
```

## Project Setup

Every project needs `local.properties`:
```
sdk.dir=/opt/android-sdk
```

Every project needs `gradle.properties`:
```
android.useAndroidX=true
org.gradle.jvmargs=-Xmx2048m
```

## Gradle/AGP Version Compatibility

| AGP | Min Gradle | compileSdk |
|-----|-----------|------------|
| 8.2.0 | 8.5 | 34 |
| 8.9.1 | 8.11.1 | 35-36 |

**PITFALL:** Health Connect `1.1.0` requires AGP 8.9.1+ AND compileSdk 36. If you get "requires libraries to compile against version 36", install `platforms;android-36` and set `compileSdk = 36`.

## Common Build Errors

### `android.useAndroidX` not enabled
```
> Configuration `:app:debugRuntimeClasspath` contains AndroidX dependencies, but `android.useAndroidX` is not enabled
```
Fix: create `gradle.properties` with `android.useAndroidX=true`.

### AAPT2 daemon startup failed
AAPT2 is x86_64; ARM64 needs Box64: `sudo apt install -y box64`.

### Gradle version too old
```
Minimum supported Gradle version is 8.11.1. Current version is 8.10.2.
```
Fix: update `gradle/wrapper/gradle-wrapper.properties` distributionUrl.

### compileSdk too low
```
requires libraries to compile against version 36; currently compiled against android-34
```
Fix: `sdkmanager "platforms;android-36"` and set `compileSdk = 36`.

## Health Connect API Gotchas (1.1.0 vs earlier)

Health Connect 1.1.0 (AGP 8.9.1+) changed the API surface significantly from alpha/beta versions:

- **Aggregate response types:** `StepsRecord.COUNT_TOTAL` returns `Long` (compare with `> 0L`), `ActiveCaloriesBurnedRecord.ACTIVE_CALORIES_TOTAL` returns `Energy` (use `.inKilocalories`), not raw Ints.
- **Sleep:** `SleepSessionRecord` no longer has `.stage` property. Stage info moved to `SleepStageRecord`.
- **Exercise:** `ExerciseSessionRecord.exerciseType` returns an Int constant, not a nullable object. Use `.toString()` instead of `?.name`.
- **ExerciseSegment:** `.segmentType` also returns Int constant. `.repetitionsCount` may not exist in some builds.
- **Nutrition:** `NutritionRecord.time` is now `startTime`/`endTime`. `.calories` renamed to `.energy`. `.biometric` removed. Use `.totalCarbohydrate`, `.totalFat`, `.protein` with `.inGrams`.
- **Hydration:** `HydrationRecord.time` → `startTime`. `.title` removed.
- **BloodPressure:** `bodyPosition` and `measurementLocation` are Int constants (not nullable enums with `.name`). Use `.toString()`.
- **Mindfulness:** Requires `@OptIn(ExperimentalHealthConnectApi::class)`. Skip if not needed.

**Rule:** When porting Health Connect code between versions, prefer `.toString()` over `.name` and use the explicit unit accessors (`.inKilocalories`, `.inGrams`, `.inMillimetersOfMercury`).

## ADB Sideload

```bash
# Connect to device over Tailscale
adb connect <tailscale_ip>:<wireless_debug_port>
adb devices  # verify "device" status

# Install APK
adb install app/build/outputs/apk/debug/app-debug.apk
```

See `pixel-6a` skill for device-specific ADB instructions.

## Project Structure Reference

Minimal Android project:
```
project/
├── build.gradle.kts          # Top-level: AGP + Kotlin plugin versions
├── settings.gradle.kts       # pluginManagement + dependencyResolutionManagement
├── gradle.properties         # android.useAndroidX=true + JVM args
├── local.properties          # sdk.dir=/opt/android-sdk
├── gradle/wrapper/
│   └── gradle-wrapper.properties  # distributionUrl with Gradle version
└── app/
    ├── build.gradle.kts      # namespace, compileSdk, dependencies
    └── src/main/
        ├── AndroidManifest.xml
        ├── java/<package>/
        │   └── *.kt
        └── res/
            ├── layout/
            │   └── activity_main.xml
            └── values/
                └── strings.xml
```

## Building

```bash
cd project
./gradlew assembleDebug --no-daemon
# APK at: app/build/outputs/apk/debug/app-debug.apk
```

## References

- Load `health-bridge` for Health Connect bridge architecture, permissions, APK rebuild/deploy, and Pixel Health Bridge troubleshooting.
- `scripts/rebuild-health-bridge.sh` — One-shot rebuild + deploy the Health Bridge APK.
