Skip to content

Use CloudRepo with an Android project

View as Markdown

An Android build is a Gradle build, and CloudRepo is a Maven repository, so an Android project resolves dependencies from CloudRepo the way any Gradle project does. What is particular to Android is where the repository goes: an Android Studio project lists the repositories its dependencies come from in settings.gradle.kts, not in each module’s build file. This page adds a CloudRepo repository there, keeps the token out of the project, and builds a small app that depends on a library held in that repository.

  • A Maven repository that holds a library to depend on. If you have none, create one and publish a library to it. The sample app below depends on com.example.docs:docs-gradle:1.0.0, the example library that page publishes; change that line to the group, name and version of a library your repository holds.
  • A repository token that reaches it. Read only is enough to build an app. See Repository tokens to create one. Your username is the email address of the account that created the token, and your password is the token.
  • Your repository’s URL, https://<organization>.mycloudrepo.io/repositories/<repository>: your organization’s name, then the repository’s name as the admin portal shows it.
  • An Android SDK and a JDK 17 or later. The blocks below use Android Gradle plugin 9.4.1, which needs Gradle 9.6.0 or later, Gradle 9.8.1 and compile SDK 36. In your own project, keep the versions it has.

Put the credential in ~/.gradle/gradle.properties, outside every project, so it is never committed. Keep the file readable by you alone (chmod 600 ~/.gradle/gradle.properties), because it holds the token. The build files below read these two properties and hold no token.

~/.gradle/gradle.properties
cloudrepoUsername=you@example.com
cloudrepoToken=YOUR_REPOSITORY_TOKEN

In CI, set the same two names as environment variables instead; see Build in GitHub Actions.

The sample is the usual Android Studio shape, a root project with an app module:

settings.gradle.kts
build.gradle.kts
app/
build.gradle.kts
src/main/AndroidManifest.xml
src/main/kotlin/com/example/docs/app/Hello.kt

If you already have a project, make the same edits to your own files.

1. Add the Gradle wrapper. A project that Android Studio made has one already, so skip this step. In a new directory, with Gradle installed, this creates gradlew and the gradle/wrapper directory beside it:

Terminal
gradle wrapper --gradle-version 9.8.1

2. List the repository. dependencyResolutionManagement lists the repositories every module of the project resolves from. If your settings.gradle.kts already has one, add the maven { } block to the repositories inside it; the rest of this file is what a new Android Studio project has.

settings.gradle.kts
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://your-org.mycloudrepo.io/repositories/your-repo")
credentials {
username = providers.gradleProperty("cloudrepoUsername").get()
password = providers.gradleProperty("cloudrepoToken").get()
}
}
}
}
rootProject.name = "demo-app"
include(":app")

A Groovy settings.gradle takes the same block:

settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = "https://your-org.mycloudrepo.io/repositories/your-repo"
credentials {
username = providers.gradleProperty("cloudrepoUsername").get()
password = providers.gradleProperty("cloudrepoToken").get()
}
}
}
}

Android Studio’s default settings file sets FAIL_ON_PROJECT_REPOS, as the block above does. A module that declares its own repositories { } then fails the build, so keep every repository in the settings file. If your project does not set it, Gradle’s default, PREFER_PROJECT, goes the other way: a module’s own repositories { } replaces the settings list for that module, so the maven { } block must be in the module’s list too.

A dependency whose group exists on Google Maven or Maven Central as well as in your repository is fetched from whichever repository Gradle asks first, in the order you list them. To make sure your own groups come only from CloudRepo, see Keep your own groups off other repositories.

The dependency goes in the module that uses it, like any other. The root build file only names the Android Gradle plugin.

1. Name the plugin in the root project.

build.gradle.kts
plugins {
id("com.android.application") version "9.4.1" apply false
}

2. Add the dependency to the app module.

app/build.gradle.kts
plugins {
id("com.android.application")
}
android {
namespace = "com.example.docs.app"
compileSdk = 36
defaultConfig {
applicationId = "com.example.docs.app"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"
}
}
dependencies {
implementation("com.example.docs:docs-gradle:1.0.0")
}

In a Groovy app/build.gradle the dependency line is:

app/build.gradle
dependencies {
implementation 'com.example.docs:docs-gradle:1.0.0'
}

3. Use it. The sample app needs a manifest to build; this is the smallest one. Your app’s manifest declares its activities.

app/src/main/AndroidManifest.xml
<manifest>
<application />
</manifest>
app/src/main/kotlin/com/example/docs/app/Hello.kt
package com.example.docs.app
import com.example.docs.App
val message: String = App.name()

4. Build. In your own project this is your usual build. In the sample, from the root directory:

Terminal
./gradlew assembleDebug

Expected: BUILD SUCCESSFUL, and the app at app/build/outputs/apk/debug/app-debug.apk. Gradle fetched the library from your CloudRepo repository.

Keep the token in a GitHub secret and hand it to Gradle through the environment, so no file is written on the runner. Gradle turns an environment variable named ORG_GRADLE_PROJECT_ plus a property name into that project property, so the build files on this page work unchanged. See Publish from GitHub Actions for how to store the secret. A Read only token is enough for a job that only builds. GitHub’s hosted Ubuntu runners have an Android SDK installed (their ANDROID_HOME points at it), so the job needs no step to install one.

.github/workflows/build.yml
name: Build
on:
push:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- name: Build the app
env:
ORG_GRADLE_PROJECT_cloudrepoUsername: you@example.com
ORG_GRADLE_PROJECT_cloudrepoToken: ${{ secrets.CLOUDREPO_TOKEN }}
run: ./gradlew assembleDebug

Gradle reports the status it received. Check these in order:

  • 401 Unauthorized. The credential was refused. The username must be the email address of the account that created the token, and the password the token itself. A token that is expired or revoked fails the same way: the Repository Tokens page in the admin portal shows its status. A property that Gradle cannot find fails before any request, with Gradle’s own message.
  • 403 Forbidden. The token does not reach this repository. A token reaches only the repositories ticked when it was created.
  • 404 Not Found. The path is wrong: check the organization and repository names in the URL, and the group, name and version of the dependency. A proxy repository that the token does not reach also answers 404, not 403.

More: Pull Gradle dependencies from CloudRepo, for exclusive content and the plain-Gradle forms; Publish Gradle artifacts to CloudRepo, to put a library in the repository; Repository tokens, for every client’s credential; Proxy repositories, to pull Google Maven or Maven Central through CloudRepo.