Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/calmerism/Tamed/llms.txt

Use this file to discover all available pages before exploring further.

Building Tamed from source gives you the most control: you can target any device architecture, enable optional integrations like Last.fm scrobbling with your own API keys, and sign the output with your own keystore. This guide covers every step from cloning the repository to producing a signed release APK, including code-quality checks required before opening a pull request.

Prerequisites

Make sure the following tools are installed and on your PATH before you begin. These are the minimum versions validated against the Tamed build system.
ToolMinimum VersionNotes
Android StudioLadybug 2024.2.1Bundles a compatible Gradle plugin and Kotlin toolchain
JDK21Amazon Corretto or Azul Zulu recommended for deterministic builds
Android SDKAPI Level 34 (Upside Down Cake)Install via Android Studio SDK Manager
Git2.40Required for submodule-aware cloning
The project compiles with sourceCompatibility = JavaVersion.VERSION_21 and targets JVM_21 in the Kotlin compiler options. Android Studio Ladybug ships with JBR 21, so no extra JDK installation is needed if you use the bundled runtime.

Step 1 — Clone the Repository

1

Clone and enter the project directory

git clone https://github.com/calmerism/Tamed.git && cd Tamed
2

Open in Android Studio

Launch Android Studio and choose File → Open, then select the Tamed directory you just cloned. The IDE will detect the Gradle project automatically.
3

Wait for Gradle sync

Android Studio triggers a Gradle sync immediately after opening. The first sync downloads all dependencies (Media3, Hilt, Compose, Ktor, Room, and the internal modules). This can take several minutes on a first run depending on your internet connection.Dependency resolution uses Version Catalogs (libs.versions.toml), so all library versions are locked to tested combinations — no manual version alignment is required.

Step 2 — Configure local.properties (Optional)

Tamed reads optional API keys and signing credentials from local.properties at the project root. This file is excluded from version control and never committed. Create it if it does not exist:
# Android SDK path (Android Studio writes this automatically)
sdk.dir=/Users/yourname/Library/Android/sdk

# Last.fm scrobbling
LASTFM_API_KEY=your_lastfm_api_key
LASTFM_SECRET=your_lastfm_secret

# Music Together collaborative sessions
TOGETHER_BEARER_TOKEN=your_together_bearer_token

# Canvas animated artwork
CANVAS_BASE_URL=https://your-canvas-endpoint
CANVAS_BEARER_TOKEN=your_canvas_bearer_token

# Release signing (optional — falls back to debug keystore if absent)
RELEASE_STORE_FILE=keystore/release.keystore
STORE_PASSWORD=your_store_password
KEY_ALIAS=your_key_alias
KEY_PASSWORD=your_key_password
All keys are optional at build time. If a key is absent, the corresponding feature is compiled in but remains inactive at runtime. You can also supply any of these values as environment variables under the same names, which is useful for CI pipelines.
Every key shown above is also readable from environment variables, so CI systems can inject secrets without writing a file to disk.

Step 3 — Build Commands

Tamed defines two product flavors along the abi dimension: arm64 (arm64-v8a only) and universal (armeabi-v7a + arm64-v8a + x86 + x86_64). Combine a flavor with a build type to produce your target APK.
CommandOutput fileUse case
./gradlew :app:assembleArm64Debugapp/build/outputs/apk/arm64/debug/app-arm64-debug.apkLocal testing on arm64 devices
./gradlew :app:assembleArm64Releaseapp/build/outputs/apk/arm64/release/Tamed.apkNamed release APK matching the GitHub release artifact
./gradlew :app:assembleUniversalDebugapp/build/outputs/apk/universal/debug/app-universal-debug.apkLocal testing on all ABI targets
./gradlew :app:assembleUniversalReleaseapp/build/outputs/apk/universal/release/app-universal-release.apkAll ABIs: armeabi-v7a, arm64-v8a, x86, x86_64
./gradlew bundleReleaseapp-release.aabApp Bundle for Play Store distribution
./gradlew cleanFlushes the build cache to resolve stale sync issues
The universal flavor is the right choice for emulators and any device that is not arm64. Its APK is larger because it bundles native libraries for all four ABIs, but it runs everywhere.

APK Output Paths

app/build/outputs/apk/arm64/debug/app-arm64-debug.apk
app/build/outputs/apk/arm64/release/Tamed.apk
app/build/outputs/apk/universal/debug/app-universal-debug.apk
app/build/outputs/apk/universal/release/app-universal-release.apk
app/build/outputs/bundle/arm64Release/app-arm64-release.aab

Step 4 — Signing

Release builds require a signing configuration. Tamed resolves the keystore in this order:
  1. The path specified by RELEASE_STORE_FILE in local.properties or the environment.
  2. The default Android debug keystore at ~/.android/debug.keystore, if the above file does not exist.
  3. The raw path value as-is (the build will fail if neither file is present).
When the debug keystore fallback is active, Tamed automatically uses android as both the store password and key password, and androiddebugkey as the key alias. This means a release build still succeeds out of the box without any keystore setup, though you should use a proper keystore for any APK you distribute.
APKs signed with the debug keystore cannot be upgraded to APKs signed with a different keystore. Decide on your signing setup before distributing a build to users.
To generate a production keystore with the JDK keytool:
keytool -genkeypair -v \
  -keystore keystore/release.keystore \
  -alias my-key-alias \
  -keyalg RSA -keysize 2048 \
  -validity 10000

Troubleshooting

Heap Memory — GC overhead limit exceededIf Gradle runs out of heap during compilation, increase the JVM memory in gradle.properties:
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g
The project ships with a 6 GB default (-Xmx6144M), but lower-memory machines may need to reduce this value to avoid thrashing.
Compose Compiler Version MismatchIf the build fails with a Compose compiler error, verify that the Kotlin version declared in libs.versions.toml aligns with the standalone Compose Compiler Gradle plugin (alias(libs.plugins.compose.compiler)). Version alignment is managed through the version catalog.

Code Quality Gates

Before opening a pull request, all three quality gates must pass cleanly. Run them from the project root:
# Android lint — checks XML, Compose, and API-level compatibility
./gradlew lintDebug

# Kotlin style — enforces consistent formatting via ktlint
./gradlew ktlintCheck

# Unit tests — runs architectural and domain-layer unit tests
./gradlew testDebugUnitTest
The lint configuration (app/lint.xml) has warningsAsErrors = false and abortOnError = false set for development builds, so lint warnings will not block a local build. The CI pipeline enforces stricter rules on pull requests.

Build docs developers (and LLMs) love