Monorepo for Aesthetic.Computer
aesthetic.computer
1# Aesthetic Computer - Android App
2
3Native Android wrapper for [aesthetic.computer](https://aesthetic.computer).
4
5## Build Flavors
6
7This project has two build flavors:
8
9| Flavor | App ID | Purpose |
10|--------|--------|---------|
11| **consumer** | `computer.aesthetic` | Play Store distribution |
12| **kiosk** | `computer.aesthetic.kiosk` | Dedicated device installations |
13
14### Consumer Flavor
15Simple WebView app that loads `https://aesthetic.computer`. For Google Play Store distribution.
16
17Features:
18- Clean WebView wrapper
19- Camera/microphone permissions for pieces that need them
20- Deep linking for `aesthetic.computer/*` URLs
21- Splash screen with purple branding
22
23### Kiosk Flavor
24Device owner mode app for dedicated installations (art exhibits, kiosks, etc).
25
26Features:
27- Local HTTPS server with self-signed SSL
28- Device admin/owner mode for lock task
29- Boot receiver for auto-start
30- Blocks back/home buttons
31- Hides system UI
32
33## Building
34
35### GitHub Actions (Recommended)
36
37The easiest way to build is via GitHub Actions:
38
391. **Automatic builds**: Push changes to `android/` on `main` branch
402. **Manual builds**: Go to Actions → "Android Build" → Run workflow
41 - Choose `debug` or `release`
42 - Choose `consumer`, `kiosk`, or `all`
433. **Download APKs**: From the workflow run artifacts
44
45APKs are available as downloadable artifacts for 30 days (debug) or 90 days (release).
46
47### Local Build Prerequisites
48- Java 17+ (`brew install openjdk@17` on Mac)
49- Android SDK (via Android Studio or standalone)
50- Set `ANDROID_HOME` environment variable
51- **Note**: Building in the devcontainer won't work (ARM64 can't run x86_64 Android SDK tools)
52
53### Build Commands
54
55```bash
56cd android
57
58# Consumer (Play Store)
59./gradlew assembleConsumerDebug # Debug APK
60./gradlew assembleConsumerRelease # Release APK (needs signing)
61
62# Kiosk (Device installations)
63./gradlew assembleKioskDebug
64./gradlew assembleKioskRelease
65
66# Build both
67./gradlew assembleDebug
68./gradlew assembleRelease
69```
70
71### Output Locations
72```
73app/build/outputs/apk/consumer/debug/app-consumer-debug.apk
74app/build/outputs/apk/consumer/release/app-consumer-release.apk
75app/build/outputs/apk/kiosk/debug/app-kiosk-debug.apk
76app/build/outputs/apk/kiosk/release/app-kiosk-release.apk
77```
78
79## Testing on Device
80
81### Via USB (Mac → Android device)
82
831. Enable Developer Mode on Android device:
84 - Settings → About Phone → Tap "Build Number" 7 times
85
862. Enable USB Debugging:
87 - Settings → Developer Options → USB Debugging → On
88
893. Connect device and accept the debugging prompt
90
914. Install APK:
92```bash
93# Install consumer debug build
94adb install app/build/outputs/apk/consumer/debug/app-consumer-debug.apk
95
96# Or force reinstall
97adb install -r app/build/outputs/apk/consumer/debug/app-consumer-debug.apk
98```
99
100### Via Wireless ADB (from devcontainer)
101
102If your Mac host and Android device are on the same network:
103
1041. On device: Settings → Developer Options → Wireless Debugging → Enable
1052. Get pairing code from device
1063. From Mac terminal:
107```bash
108adb pair <device-ip>:<pairing-port> # Enter pairing code
109adb connect <device-ip>:<debug-port>
110adb install path/to/app.apk
111```
112
113## Project Structure
114
115```
116android/
117├── app/
118│ ├── build.gradle.kts # Build config with product flavors
119│ └── src/
120│ ├── main/ # Shared code (theme, resources)
121│ │ ├── AndroidManifest.xml
122│ │ ├── java/computer/aesthetic/ui/theme/
123│ │ └── res/ # Icons, colors, strings
124│ │
125│ ├── consumer/ # Play Store version
126│ │ ├── AndroidManifest.xml
127│ │ └── java/computer/aesthetic/
128│ │ └── MainActivity.kt
129│ │
130│ └── kiosk/ # Device installation version
131│ ├── AndroidManifest.xml
132│ ├── java/computer/aesthetic/
133│ │ ├── MainActivity.kt
134│ │ ├── LocalHttpServer.kt
135│ │ ├── BootReceiver.kt
136│ │ └── MyDeviceAdminReceiver.kt
137│ └── res/
138│ ├── raw/keystore.bks
139│ └── xml/device_admin.xml
140│
141├── gradle/ # Gradle wrapper & version catalog
142└── build.gradle.kts # Root build config
143```
144
145## Play Store Release
146
147### 1. Generate Upload Keystore
148```bash
149keytool -genkey -v -keystore aesthetic-upload.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
150```
151
152### 2. Configure Signing
153Add to `app/build.gradle.kts`:
154```kotlin
155signingConfigs {
156 create("release") {
157 storeFile = file("../aesthetic-upload.jks")
158 storePassword = System.getenv("KEYSTORE_PASSWORD")
159 keyAlias = "upload"
160 keyPassword = System.getenv("KEY_PASSWORD")
161 }
162}
163
164buildTypes {
165 release {
166 signingConfig = signingConfigs.getByName("release")
167 // ...
168 }
169}
170```
171
172### 3. Build Release Bundle
173```bash
174./gradlew bundleConsumerRelease
175# Output: app/build/outputs/bundle/consumerRelease/app-consumer-release.aab
176```
177
178### 4. Upload to Play Console
1791. Create app in [Google Play Console](https://play.google.com/console)
1802. Upload `.aab` file to Internal Testing track
1813. Fill out store listing, content rating, privacy policy
1824. Promote to Production when ready
183
184## Kiosk Setup (Device Owner Mode)
185
186For dedicated devices that boot directly into the app:
187
188### 1. Factory Reset Device
189Start with a fresh device.
190
191### 2. Set Device Owner via ADB
192```bash
193adb shell dpm set-device-owner computer.aesthetic.kiosk/.MyDeviceAdminReceiver
194```
195
196### 3. Install Kiosk APK
197```bash
198adb install app-kiosk-release.apk
199```
200
201The device will now boot directly into Aesthetic Computer.
202
203## Dependencies
204
205- Kotlin 2.0.21
206- Jetpack Compose (BOM 2024.12.01)
207- AndroidX Core KTX 1.15.0
208- AndroidX Splashscreen 1.0.1
209- NanoHTTPD 2.3.1 (kiosk only)
210
211## Version History
212
213- **1.1.0** - Build flavor support (consumer vs kiosk)
214- **1.0.0** - Initial kiosk-only release