# Use CloudRepo with an Android project

> Resolve dependencies from CloudRepo in an Android project with a repository block in settings.gradle.kts, and keep your token out of your build files.

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.

## Before you start

- A Maven repository that holds a library to depend on. If you have none, [create one](/docs/manage/repositories.html#creating-a-repository) and [publish a library to it](/docs/publish/gradle.html). 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](/docs/authenticate/repository-tokens.html) 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.

## Keep the token out of your build files

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/gradle.properties`

```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](#build-in-github-actions).

## Add the repository to settings.gradle.kts

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

```text
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.

**Gradle**

**1. Add the Gradle wrapper.** A project that Android Studio made has one already, so skip this step. In a new directory, with [Gradle](https://gradle.org/install/) installed, this creates `gradlew` and the `gradle/wrapper` directory beside it:

**Terminal**

```bash
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`

```kotlin
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`

```groovy
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](/docs/consume/gradle.html#keep-your-own-groups-off-other-repositories).

## Depend on a library from it

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

**Gradle**

**1. Name the plugin in the root project.**

`build.gradle.kts`

```kotlin
plugins {
    id("com.android.application") version "9.4.1" apply false
}
```

**2. Add the dependency to the app module.**

`app/build.gradle.kts`

```kotlin
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`

```groovy
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`

```xml
<manifest>
    <application />
</manifest>
```

`app/src/main/kotlin/com/example/docs/app/Hello.kt`

```kotlin
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**

```bash
./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.

## Build in GitHub Actions

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](/docs/ci/github-actions.html) 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`

```yaml
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
```

## When Gradle answers 401, 403 or 404

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](/docs/consume/gradle.html), for exclusive content and the plain-Gradle forms; [Publish Gradle artifacts to CloudRepo](/docs/publish/gradle.html), to put a library in the repository; [Repository tokens](/docs/authenticate/repository-tokens.html), for every client’s credential; [Proxy repositories](/docs/consume/proxy-repositories.html), to pull Google Maven or Maven Central through CloudRepo.

---

The page: https://www.cloudrepo.io/docs/formats/android.html
