Skip to content

Building and Installing the App

This page covers what is needed to build the Android app, how to produce an APK, and how to install it on a phone or emulator. It reflects the project configuration in android-app/ at the time of writing.

ToolVersionNotes
Android StudioA release that supports Android Gradle Plugin 8.12Android Studio will warn on sync if it is too old.
JDK17 or newerRequired to run Gradle / AGP 8.x. The JDK bundled with Android Studio works. The app code itself compiles to Java 11.
Android SDK PlatformAPI 36Install through Settings → Languages & Frameworks → Android SDK.
Gradle8.14.4Downloaded automatically by the Gradle wrapper (gradlew). Do not install separately.

No other tools, accounts or API keys are needed for a debug build.

These values are set in android-app/app/build.gradle.kts and android-app/gradle/libs.versions.toml:

SettingValue
applicationId / namespacecom.example.myapplication
minSdk21 (Android 5.0)
targetSdk / compileSdk36
Android Gradle Plugin8.12.3
Kotlin2.0.21
Java source / target11
versionCode / versionName1 / 1.0

The app does not have a settings screen for the server address. It is compiled into the app as BuildConfig fields in app/build.gradle.kts:

buildConfigField("String", "BASE_URL", "\"https://p27payload.benb.au/api/\"")
buildConfigField("String", "MEDIA_BASE", "\"https://p27payload.benb.au\"")
  • BASE_URL is the Payload REST API root used by Retrofit. It must end with a /, or Retrofit will throw on startup.
  • MEDIA_BASE is prepended to relative image paths returned by Payload (e.g. /api/media/file/...).

Both the defaultConfig (debug) and release blocks currently point at the development server on Ben’s machine (see Payload overview). To point the app at a different server, both pairs of lines need to be changed, followed by a Gradle sync and rebuild.

When running Payload locally on port 3000, an emulator reaches the host computer at 10.0.2.2, not localhost:

buildConfigField("String", "BASE_URL", "\"http://10.0.2.2:3000/api/\"")
buildConfigField("String", "MEDIA_BASE", "\"http://10.0.2.2:3000\"")

Android 9 (API 28) and newer block plain http:// traffic by default, so a local HTTP server also needs a network security config that allows cleartext traffic to 10.0.2.2. This must not be shipped in a release build.

  1. Clone the repository and open the android-app/ folder (not the repository root) in Android Studio.
  2. Wait for the Gradle sync to finish. On first open, Android Studio creates local.properties containing the path to the Android SDK. This file is machine-specific and must not be committed.
  3. If the sync fails with a Java version error, set Settings → Build, Execution, Deployment → Build Tools → Gradle → Gradle JDK to a JDK 17+ (e.g. the bundled JetBrains Runtime).
  4. Select a device or emulator in the toolbar and press Run. This builds and installs the debug version.

To produce an APK file without running it: Build → Build App Bundle(s) / APK(s) → Build APK(s).

From the android-app/ folder:

Terminal window
# macOS / Linux
./gradlew assembleDebug
# Windows
gradlew.bat assembleDebug

The APK is written to:

android-app/app/build/outputs/apk/debug/app-debug.apk

The debug APK is signed automatically with the Android debug key, so it can be installed on any device straight away. It is the build to share with the team and client for testing.

If ./gradlew fails with Permission denied, the script has lost its executable flag. Run chmod +x gradlew locally, or fix it in the repository with git update-index --chmod=+x gradlew.

Terminal window
./gradlew assembleRelease

The project has no signing configuration yet, so this produces app/build/outputs/apk/release/app-release-unsigned.apk, which Android will refuse to install.

To produce an installable release APK, sign it through Build → Generate Signed App Bundle / APK in Android Studio, creating a new keystore when prompted. The keystore file and its passwords:

  • must never be committed to the repository;
  • must be backed up safely. An app signed with a lost keystore can never be updated, since Android and Google Play only accept updates signed with the same key.

Code shrinking (isMinifyEnabled) is currently off for release builds.

  1. On the phone, enable Developer options (tap Build number in About phone seven times), then turn on USB debugging.
  2. Connect the phone and accept the debugging prompt.
  3. Install:
Terminal window
adb install -r app/build/outputs/apk/debug/app-debug.apk

-r replaces an existing install and keeps its data.

  1. Send the APK to the phone (e.g. Google Drive, email, or downloaded from a GitHub build).
  2. Open it on the phone. Android asks for permission to install apps from that source (Chrome, Files, etc.). Allow it for that app only.
    • On Android 5–7 this is a single Unknown sources switch under Settings → Security.
  3. Tap Install.

Switching between debug and release builds

Section titled “Switching between debug and release builds”

Debug and release APKs are signed with different keys. Installing one over the other fails with INSTALL_FAILED_UPDATE_INCOMPATIBLE. Uninstall the existing app first; this also clears its saved login.

These do not stop a debug build but should be resolved before the app is handed over or published:

  • applicationId is com.example.myapplication. Google Play rejects com.example.* IDs. It has to be changed to a real ID before the first store release and cannot be changed afterwards.
  • The server address is hardcoded for both debug and release builds (see Backend URL). A release build currently talks to the development server.
  • No release signing is configured, so release builds are unsigned.
  • Duplicate dependencies: Material and ConstraintLayout are declared both in the version catalog and as hardcoded strings in app/build.gradle.kts, with different ConstraintLayout versions (2.2.1 and 2.1.4). Gradle resolves to the higher version, so this does not break the build, but the hardcoded lines should be removed.
  • No automated build is set up yet. Every APK is currently built on a team member’s machine.
ErrorCause / fix
Android Gradle plugin requires Java 17 to runSet the Gradle JDK to 17+ (see Building in Android Studio). From the command line, point JAVA_HOME at a JDK 17+.
SDK location not foundlocal.properties is missing. Open the project in Android Studio once, or create it with sdk.dir=/path/to/Android/sdk.
Permission denied: ./gradlewSee Building from the command line.
INSTALL_FAILED_UPDATE_INCOMPATIBLEA build signed with a different key is installed. Uninstall it first.
App opens but no listings loadThe device cannot reach BASE_URL. Check internet access and that the server in build.gradle.kts is up.