Publish Multi-module Private Android Library to jFrog

Pramod Ravikant
5 min readFeb 26

--

Scenario:

  1. You are building an Android library that can be used only by those with access.
  2. The Android library has multiple modules.
  3. Your library is on a private repo on GitHub or BitBucket.
  4. debug version of the library should be published on every merge to master.
  5. release version of the library should be published on every tag pushed.
  6. You need to use jFrog Artifactory to distribute your library.

Step 1: Prerequisites

Access

You need to have write access to the jFrog repo in which you want to publish your artifacts.

jFrog identity token

jFrog identity token to publish the artifacts. Follow the below steps to generate an identity token:

  1. Open your jFrog, click on your username on the top right, and open Edit profile.
  2. Under Authentication Settings, click on Generate an Identity Token. Make sure to keep a note of this token.
Open Edit Profile to generate an Identity Token

Adding secrets to GitHub

You need to add your jFrog username and the identity token to your GitHub secrets so that GitHub Actions can build your library and publish directly to jFrog Artifactory.

  1. Go to your repository Settings.
  2. Under the Secrets and variables menu, click on Action.
  3. Here, click on New repository secret and add the following secrets:

JFROG_USERNAME = Your jFrog username

JFROG_PASSWORD = jFrog identity token that you created earlier.

Adding new secrets to GitHub

Step 2: Publishing script

Imagine you have the following modules in your library project

  1. app — This is the sample app that implements your library.
  2. mylib-client — This is the main client module that is the entry to this library.
  3. mylib-resources — This is a module that has all the string, drawable, and other resources.
  4. mylib-services — This module contains the data layer.
  5. mylib-ui — This module contains the UI layer.

During publishing the library, you must skip the app module and publish only mylib-client the module. The other 3 modules will be added as a dependency to the main module.

Let’s get straight into integration now.

Open your project-level build.gradle file and add the following under the plugins section:

id 'com.jfrog.artifactory' version '4.29.1' apply false

Next, create a new subprojects section. We need to create this section to make sure all the modules are evaluated.

subprojects {
apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.artifactory'

afterEvaluate {
plugins.withId('com.android.library') {
println(project.name)

publishing {
publications {
release(MavenPublication) {
groupId = <YOUR_GROUP_ID>
artifactId = project.getName()
version = System.getenv("SDK_VERSION")

afterEvaluate {
from components.release
}

pom {
name = <YOUR_SDK_NAME>
description = <YOUR_SDK_DESCRIPTION>
url = <URL_TO_YOUR_SDK_OR_COMPANY>
developers {
developer {
id = <OPTIONAL_DEVELOPER_ID>
name = <OPTIONAL_DEVELOPER_NAME>
email = <OPTIONAL_DEVELOPER_EMAIL>
}
}
}
}
}

repositories {
maven {
url = System.getenv("REPO_URL")

credentials {
username = System.getenv("JFROG_USERNAME")
password = System.getenv("JFROG_PASSWORD")
}
}
}
}
}
}
}

Okay, let's break it down.

subprojects will traverse each module of your library.

release(MavenPublication) will publish the release version of your library.

YOUR_GROUP_ID = Something like com.companyname . With this, your library can then be accessed in the following way:

implementation "com.companyname.mylib-client:1.0.0"

Under repositories.maven section, url, username and password will be taken from GitHub Secrets. More about this is in the GitHub Actions section.

Step3 — Make the modules ready

Now that you have added the publishing script, we need to make sure that all the submodules we want should be added as an api dependency and not implementation dependency.

For example, change

implementation project(‘:mylib-ui’)api project(‘:mylib-ui’)

This is a crucial step. Skipping this will not add the submodules to your main module in the published library instead you will have to add all your submodules as separate dependencies in the host app.

Step 4 — GitHub workflow to publish artifacts

Goto GitHub Actions and create a new workflow called publish_debug.yml

name: Publish Artifactory - Debug

on:
workflow_dispatch:
push:
branches:
- master

jobs:
tests:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Run tests - Debug
run: ./gradlew clean testDebug
publish:
needs: [tests]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Publish
env:
SDK_VERSION: ${{ format('1.{0}.{1}', github.run_number, github.run_attempt) }}
REPO_URL: "https://YOUR_JFROG_DOMAIN/artifactory/YOUR_JFROG_REPO/"
JFROG_USERNAME: ${{ secrets.JFROG_USERNAME }}
JFROG_PASSWORD: ${{ secrets.JFROG_PASSWORD }}
run: ./gradlew publish

Now, whenever a PR is merged to the master branch, this workflow will run.

It will create a version for your library, and publish the artifacts to the REPO_URL with the credentials that you have provided with JFROG_USERNAME and JFROG_PASSWORD.

Similarly, you can create another workflow called publish_release.yml to publish the release version of the library every time you create a new release in GitHub.

name: Publish Artifactory - Release

on:
workflow_dispatch:
release:
types: [released]

jobs:
tests:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Run tests - Release
run: ./gradlew clean testRelease
publish:
needs: [tests]
runs-on: ubuntu-20.04
steps:
- name: SDK release version
run: |
VERSION=${GITHUB_REF_NAME#v}
echo "SDK_VERSION=$VERSION" >> $GITHUB_ENV
echo Releasing SDK version ${VERSION}
- uses: actions/checkout@v2
- name: Publish
env:
REPO_URL: "https://YOUR_JFROG_DOMAIN/artifactory/YOUR_JFROG_REPO/"
JFROG_USERNAME: ${{ secrets.JFROG_USERNAME }}
JFROG_PASSWORD: ${{ secrets.JFROG_PASSWORD }}
run: ./gradlew publish

Note that the version of your library in the release version is the tag that you push.

That’s it. You will be able to see your library added under artifacts in jFrog.

Step 5 — Accessing the library

Now that the library is published, we would like to add it as a dependency in one of our projects.

Open the gradle.properties file and add the following


mavenUser=YOUR_JFROG_USERNAME_HERE
mavenPassword=YOUR_JFROG_IDENTITY_TOKEN_HERE

Next, open your project-level build.gradle file and the following:

allprojects {
repositories {

...

maven {
url "YOUR JFROG REPO URL HERE"

credentials {
username "$mavenUser"
password "$mavenPassword"
}
}
}
}

With this, you have added credentials to access the private artifacts on jFrog.

Now you can go ahead and add your library as a dependency in the app-level build.gradle file like the below:

implementation "com.companyname.mylib-client:1.0.0"

That’s it. You should now have the library added as a dependency.

--

--

Pramod Ravikant

Techie & Thinker - #Android #ReactNative #PrincipalEngineer