Our mission is to make trucking efficient, reliable and convenient. We aim to ease the hassle of repetitive tasks and make our clients focus only on the important issues.To provide a convenient experience we use the mobile as part of our channels to engage and notify our clients in realtime. We largely use Android as it dominates a larger percentage of our users. In light of this, We have decided to share some of our struggles and difficulties in our tech blog. There are limited resources elaborating on the tech elements of establishing these platforms and running them smoothly.
Let’s get started. 💫
This is part 1 of a 3 part series.
Part 1 will focus on the development of workflow and how to improve developers’ productivity on large scale projects. This will include implementing Continuous Integration (CI) pipeline to automate publishing Android Library using Github Actions.
Requirements 📄
- GitFlow.
- Basic Gradle scripting knowledge.
Motivation ✨
Working on large scale projects has some interesting challenges.
A common obstacle is setting the project structure and coordination between the project’s Apps and Modules, and how it reflects on the development lifecycle.
For the project we are working on we have the following: Five different Android Apps, every app on its own project
( Some have common features and others do not ).
- Five Modules shared across the five apps.
- Three of the five modules depend on the other two modules.
- The Five Apps depend on the Five Modules. Check the diagram below visualizing the structure.
Within the structure shown below, we had a GitHub repository for each module as it’s shared across multiple apps.
Every app has its own repository, and the development workflow was the following:-
- We clone every module to our development machines.
- We include them on every app as local modules with its directory path on the machine so
settings.gradle
. The file wasgit
ignored as it would change for everyone working on the projects. - On making changes to modules or apps, we push them to their corresponding remote repositories, and we use GitFlow so we have to be updated with the latest version of the
develop
branch
Our Challenge 👨🏼💻
We all know the pain of creating a test build after finishing a feature. Conducting a manual build is really difficult as it may not as may have to do t more than one time, and in doing so triggers your inner desire to automate the process.
Based on this issue we decided to use a Continuous Integration (CI)
pipeline for this process, This requires all of our local modules to have a remote version as a Gradle dependency.
This also requires removing all of our local modules integration for all of our apps, which will affect our development workflow**, however we will address this later in the next article.**
Changing Local Modules to Gradle Dependencies
Publishing an Android library present two key challenges:
- Some of the modules have product flavors (Production/Staging) which are common to have.
- We want to include a snapshot version of the libraries if anyone wants to make changes and test its result on the apps before proceeding with Pull Request Review, which will be built automatically on
git push
to any branch exceptdevelop/master
.
Creating Android Library with Product Flavors and Snapshot Versions with Github Actions & Github Packages
Github Actions & Packages meet our requirements as Github Actions offer great support with Gradle, And are easily workable with the server setup boilerplate.
Github Packages is also a great place to host maven dependencies and provide private access options as those libraries will be used internally within the company’s projects.
Let’s start with Building 🏗️
Any Android library could be built into an aar
version which is used to publish on Github Packages.to build the aar
version if it doesn’t exist or after any changes to the library before publishing we use.
./gradlew assemble
and the output could be found in this directory after a successful build by making sure to select the release variant before building.
"${rootProject.rootDir}//module-name/build/outputs/aar/module-name-release.aar"
then we proceed to Github Packages configurations :
Step 1: Generate a Personal Access Token for GitHub
Inside your GitHub account:
**Settings -> Developer Settings -> Personal Access Tokens -> Generate new token**
Make sure you select the following scopes (“ write: packages”, “ read: packages”) and Generate a token
After Generating, copy the new personal access token as It will not appear again! The only option will be to regenerate a key or create a new key.
Step 2: Store your GitHub — Personal Access Token details
Create a github.properties
file within your root Android project.
In case of a public repository, make sure you add this file to .gitignore
to keep the token private.
Add properties gpr.usr=GITHUB_USERID
and gpr.key=PERSONAL_ACCESS_TOKEN
Replace GITHUB_USERID
with personal / organization Github User ID and PERSONAL_ACCESS_TOKEN
with the token generated in #Step 1.
The final file should look like this
gpr.usr=GITHUB_USERID
gpr.key=PERSONAL_ACCESS_TOKEN
Step 3: Update build.gradle Inside the Library Module
Add the following code to build.gradle inside the library module
def githubProperties = new Properties()
githubProperties.load(new FileInputStream(rootProject.file("github.properties"))) //Set env variable GPR_USER & GPR_API_KEY if not adding a properties file
repositories {
maven {
name = "GitHubPackages"
/** Configure path of your package repository on Github
** Replace GITHUB_USERID with your/organisation Github userID
** and REPOSITORY with the repository name on GitHub
*/
url = uri("<https://maven.pkg.github.com/GITHUB_USERID/REPOSITORY>")
credentials {
/** Create github.properties in root project folder file with
** gpr.usr=GITHUB_USERID-app & gpr.key=PERSONAL_ACCESS_TOKEN
** Set env variable GPR_USER & GPR_API_KEY if not adding a properties file**/
username = githubProperties['gpr.usr'] ?: System.getenv("GPR_USER")
password = githubProperties['gpr.key'] ?: System.getenv("GPR_API_KEY")
}
}
}
}
What we have done in the previous step is access the properties that we have added in github.properties
, and then used it as a credential to be able to access the library’s repository Github Packages using our personal access token.
Step 4: Creating Gradle Publishing Script
We will go step by step through the regular publish script until we customize it, so we may add support for product flavours
and snapshot versioning
- We will add the Maven Gradle Publishing plugin
apply plugin: 'maven-publish' // Apply this plugin at the top of your library build.gradle
and then add the publish script
def getVersionName = { ->
return "1.0.2" // Replace with version Name
}
def getArtifactId = { ->
return "sampleAndroidLibrary" // Replace with library name ID
}
publishing {
publications {
bar(MavenPublication) {
groupId 'com.sample.library' // Replace with group ID
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//module-name/build/outputs/aar/module-name-release.aar")
}
}
The final resulting file will look like this
apply plugin: 'maven-publish' // Apply this plugin at the top of your library build.gradle
def getVersionName = { ->
return "1.0.2" // Replace with version Name
}
def getArtifactId = { ->
return "sampleAndroidLibrary" // Replace with library name ID
}
def githubProperties = new Properties()
githubProperties.load(new FileInputStream(rootProject.file("github.properties"))) //Set env variable GPR_USER & GPR_API_KEY if not adding a properties file
publishing {
publications {
bar(MavenPublication) {
groupId 'com.sample.library' // Replace with group ID
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//library-name/build/outputs/aar/library-name-release.aar")
}
}
repositories {
maven {
name = "GitHubPackages"
/** Configure path of your package repository on Github
** Replace GITHUB_USERID with your/organisation Github userID
** and REPOSITORY with the repository name on GitHub
*/
url = uri("<https://maven.pkg.github.com/GITHUB_USERID/REPOSITORY>")
credentials {
/** Create github.properties in root project folder file with
** gpr.usr=GITHUB_USERID-app & gpr.key=PERSONAL_ACCESS_TOKEN
** Set env variable GPR_USER & GPR_API_KEY if not adding a properties file**/
username = githubProperties['gpr.usr'] ?: System.getenv("GPR_USER")
password = githubProperties['gpr.key'] ?: System.getenv("GPR_API_KEY")
}
}
}
}
We added the maven-publish
plugin that is provided out of the box for Android libraries to help us publish maven dependencies easier.
Next is library’s groupId
which is the Package name identifier in Projects.
Then artifactId
, which is the library name.
Lastly, the version which is the library version.
By executing the following code in the terminal.
./gradlew publish
Alternatively, Go to the Gradle tab in Android Studio > YOUR_PROJECT_NAME(root) -> Publish.
Once the task is successfully published you should be able to see the Package under the Packages tab of the GitHub Account
Step 5: Auto-Increment (Dynamically) Android Library Version on Publishing
Of course, we will not manually update the version with every new change but rather automate the Patch version (the latest number in the version number eg “2” in “1.0.2”) and then let the Major, Minor version to be updated manually. This happens with the following steps:
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['VERSION_PATCH'] = "0"
versionProps.store(versionPropsFile.newWriter(), null)
}
def runTasks = gradle.startParameter.taskNames
if ('publish' in runTasks) {
value = 1
}
def mVersionName = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps.store(versionPropsFile.newWriter(), null)
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['VERSION_PATCH']}"
println mVersionName
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
def getVersionName = { ->
return "${mVersionName}"
}
What this script does that it looks for a file in the project named version.properties
, and if it doesn’t exist, we will create one with a default value VERSION_PATCH = "0"
to then store the file in our project with
versionProps.store(versionPropsFile.newWriter(), null)
- We check to make sure the publish task (we will come to it later) is being run now. If it’s running we make a variable value to have 1 (the value that we will add to our current version patch), we do this as this script is always executed with every Gradle build (regardless if it’s a publish task or not). By doing this we confirm that we are currently publishing the library.
- The rest of the script is that we read the version.properties (which should be created after this step), and get the current version patch value and add our value variable to it to assign the output result to another variable mVersionName which we reuse in the getVersionName function. Finally, we use it for the publish maven task as our desired new version.
- We will add this script inside our publish task, the final build.gradle file should look like this
apply plugin: 'maven-publish' // Apply this plugin at the top of your library build.gradle
def getArtifactId = { ->
return "sampleAndroidLibrary" // Replace with library name ID
}
def githubProperties = new Properties()
githubProperties.load(new FileInputStream(rootProject.file("github.properties"))) //Set env variable GPR_USER & GPR_API_KEY if not adding a properties file
publishing {
publications {
bar(MavenPublication) {
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['VERSION_PATCH'] = "0"
versionProps.store(versionPropsFile.newWriter(), null)
}
def runTasks = gradle.startParameter.taskNames
if ('publish' in runTasks) {
value = 1
}
def mVersionName = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps.store(versionPropsFile.newWriter(), null)
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['VERSION_PATCH']}"
println mVersionName
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
def getVersionName = { ->
return "${mVersionName}"
}
groupId 'com.sample.library' // Replace with group ID
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//module-name/build/outputs/aar/module-name-release.aar")
}
}
repositories {
maven {
name = "GitHubPackages"
/** Configure path of your package repository on Github
** Replace GITHUB_USERID with your/organisation Github userID
** and REPOSITORY with the repository name on GitHub
*/
url = uri("<https://maven.pkg.github.com/GITHUB_USERID/REPOSITORY>")
credentials {
/** Create github.properties in root project folder file with
** gpr.usr=GITHUB_USERID-app & gpr.key=PERSONAL_ACCESS_TOKEN
** Set env variable GPR_USER & GPR_API_KEY if not adding a properties file**/
username = githubProperties['gpr.usr'] ?: System.getenv("GPR_USER")
password = githubProperties['gpr.key'] ?: System.getenv("GPR_API_KEY")
}
}
}
}
Step 6:Enabling Snapshot Versioning for Android Library with Github Packages
As we discussed we will need to enable a snapshot versioning for our library which is implemented using the same concept as auto-increment versioning.
Instead of storing a version number, we shall store a boolean indicating if this build is a snapshot, or not with the snapshot version.
The question presented is how will we change the boolean value? By creating a Gradle task which we shall run before any publishing, and set the boolean
to be true
if we want a snapshot version and false
if we want a stable version.
task setSnapshot {
doLast {
def versionPropsFile = file('version.properties')
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['IS_SNAPSHOT'] = isSnapshot
versionProps['SNAPSHOT_VERSION_PATCH'] = "0"
versionProps['VERSION_PATCH'] = "0"
versionProps.store(versionPropsFile.newWriter(), null)
}
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['IS_SNAPSHOT'] = isSnapshot
versionProps.store(versionPropsFile.newWriter(), null)
}
}
}
Sounds familiar right?
The only changes between this task and the dynamic versioning are that we introduced the IS_SNAPSHOT
, SNAPSHOT_VERSION_PATCH
properties in our version.properties
file.
We use a value isSnapshot
, but it wasn’t defined, and its value will be sent through a terminal command to trigger this Gradle task which we run before running the publish task.
We do however need to update our versioning logic, so we make use of the snapshot versioning option.
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['IS_SNAPSHOT'] = false
versionProps['SNAPSHOT_VERSION_PATCH'] = "0"
versionProps['VERSION_PATCH'] = "0"
versionProps.store(snapshotPropsFile.newWriter(), null)
}
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
}
def runTasks = gradle.startParameter.taskNames
if ('publish' in runTasks) {
value = 1
}
def mVersionName = ""
def mArtifact = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
def isSnapshot = versionProps['IS_SNAPSHOT']
if (isSnapshot != null && isSnapshot.toBoolean()) {
versionProps['SNAPSHOT_VERSION_PATCH'] = (versionProps['SNAPSHOT_VERSION_PATCH'].toInteger() + value).toString()
} else
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps.store(versionPropsFile.newWriter(), null)
if (isSnapshot != null && isSnapshot.toBoolean()) {
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['SNAPSHOT_VERSION_PATCH']}"
mArtifact = "snapshot"
} else {
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['VERSION_PATCH']}"
mArtifact = "sampleAndroidLibrary"
}
println mVersionName
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
def getVersionName = { ->
return "${mVersionName}"
}
def getArtifactId = { ->
return "${mArtifact}"
}
You will notice here that we check if the IS_SNAPSHOT
is true then we change the version value to SNAPSHOT_VERSION_PATCH
.
We then set our artifact value as snapshot so we could distinguish the snapshot version from a stable version.
In case of displaying false
we repeat our previous logic in #Step 5.
Let’s try to make a snapshot version of the library by running these commands in terminal
./gradlew -PisSnapshot=true setSnapshot --stacktrace
./gradlew publish
After a successful build we should see the following in the Github packages tab:
Step 7: Create Product Flavors for Android Library with Github Packages.
If your library has product flavors, for example, Production and Staging flavors and you want to create different versions for each one;
We will first check it’s binaries (aka aar
files).
By running the same ./gradlew assemble
task we will have an aar
file generated for every flavor of our library and their directories will show.
"${rootProject.rootDir}//library-name/build/outputs/aar/library-name-production-release.aar"
"${rootProject.rootDir}//library-name/build/outputs/aar/library-name-staging-release.aar"
As soon as we have the aar
files then we could publish them easily using a Maven Plugin and the coding scheme would present this
publishing {
publications {
production(MavenPublication) {
.....
groupId 'com.sample.library'
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//library-name/build/outputs/aar/library-name-production-release.aar")
}
staging(MavenPublication) {
.....
groupId 'com.sample.library'
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//library-name/build/outputs/aar/library-name-staging-release.aar")
}
}
As simple as that, we integrate our dynamic & snapshot versioning script with these and see the final build.gradle file
apply plugin: 'maven-publish' // Apply this plugin at the top of your library build.gradle
def githubProperties = new Properties()
githubProperties.load(new FileInputStream(rootProject.file("github.properties"))) //Set env variable GPR_USER & GPR_API_KEY if not adding a properties file
task setSnapshot {
doLast {
def versionPropsFile = file('version.properties')
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['IS_SNAPSHOT'] = isSnapshot
versionProps['SNAPSHOT_VERSION_PATCH'] = "0"
versionProps['VERSION_PATCH'] = "0"
versionProps.store(versionPropsFile.newWriter(), null)
}
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
versionProps['IS_SNAPSHOT'] = isSnapshot
versionProps.store(versionPropsFile.newWriter(), null)
}
}
}
publishing {
publications {
production(MavenPublication) {
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['IS_SNAPSHOT'] = false
versionProps['SNAPSHOT_VERSION_PATCH'] = "0"
versionProps['VERSION_PATCH'] = "0"
versionProps.store(snapshotPropsFile.newWriter(), null)
}
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
}
def runTasks = gradle.startParameter.taskNames
if ('publish' in runTasks) {
value = 1
}
def mVersionName = ""
def mArtifact = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
def isSnapshot = versionProps['IS_SNAPSHOT']
if (isSnapshot != null && isSnapshot.toBoolean()) {
versionProps['SNAPSHOT_VERSION_PATCH'] = (versionProps['SNAPSHOT_VERSION_PATCH'].toInteger() + value).toString()
} else
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps.store(versionPropsFile.newWriter(), null)
if (isSnapshot != null && isSnapshot.toBoolean()) {
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['SNAPSHOT_VERSION_PATCH']}"
mArtifact = "snapshot-production"
} else {
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['VERSION_PATCH']}"
mArtifact = "name-production"
}
println mVersionName
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
def getVersionName = { ->
return "${mVersionName}"
}
def getArtifactId = { ->
return "${mArtifact}"
}
groupId 'com.sample.library' // Replace with group ID
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//library-name/build/outputs/aar/library-name-production-release.aar")
}
staging(MavenPublication) {
def versionPropsFile = file('version.properties')
def value = 0
Properties versionProps = new Properties()
if (!versionPropsFile.exists()) {
versionProps['IS_SNAPSHOT'] = false
versionProps['SNAPSHOT_VERSION_PATCH'] = "0"
versionProps['VERSION_PATCH'] = "0"
versionProps.store(snapshotPropsFile.newWriter(), null)
}
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
}
def runTasks = gradle.startParameter.taskNames
if ('publish' in runTasks) {
value = 1
}
def mVersionName = ""
def mArtifact = ""
if (versionPropsFile.canRead()) {
versionProps.load(new FileInputStream(versionPropsFile))
def isSnapshot = versionProps['IS_SNAPSHOT']
if (isSnapshot != null && isSnapshot.toBoolean()) {
versionProps['SNAPSHOT_VERSION_PATCH'] = (versionProps['SNAPSHOT_VERSION_PATCH'].toInteger() + value).toString()
} else
versionProps['VERSION_PATCH'] = (versionProps['VERSION_PATCH'].toInteger() + value).toString()
versionProps.store(versionPropsFile.newWriter(), null)
if (isSnapshot != null && isSnapshot.toBoolean()) {
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['SNAPSHOT_VERSION_PATCH']}"
mArtifact = "snapshot-staging"
} else {
// 1: change major and minor version here
mVersionName = "1.0.${versionProps['VERSION_PATCH']}"
mArtifact = "name-staging"
}
println mVersionName
} else {
throw new FileNotFoundException("Could not read version.properties!")
}
def getVersionName = { ->
return "${mVersionName}"
}
def getArtifactId = { ->
return "${mArtifact}"
}
groupId 'com.sample.library' // Replace with group ID
artifactId getArtifactId()
version getVersionName()
artifact("${rootProject.rootDir}//library-name/build/outputs/aar/library-name-staging-release.aar")
}
}
repositories {
maven {
name = "GitHubPackages"
/** Configure path of your package repository on Github
** Replace GITHUB_USERID with your/organisation Github userID
** and REPOSITORY with the repository name on GitHub
*/
url = uri("<https://maven.pkg.github.com/GITHUB_USERID/REPOSITORY>")
credentials {
/** Create github.properties in root project folder file with
** gpr.usr=GITHUB_USERID-app & gpr.key=PERSONAL_ACCESS_TOKEN
** Set env variable GPR_USER & GPR_API_KEY if not adding a properties file**/
username = githubProperties['gpr.usr'] ?: System.getenv("GPR_USER")
password = githubProperties['gpr.key'] ?: System.getenv("GPR_API_KEY")
}
}
}
}
By running the Gradle sync, and then running the below commands we publish a snapshot production/staging version
./gradlew -PisSnapshot=true setSnapshot --stacktrace ./gradlew publish
VOILA! We have 4 different variants of our library that we could use based on various cases
Step 8: Custom Gradle Project Configuration for build variants
Our library’s version would look like this
//Stable
'com.sample.library:name-production:1.0.2'
'com.sample.library:name-staging:1.0.2'
//snapshot
'com.sample.library:snapshot-production:1.0.2'
'com.sample.library:snapshot-staging:1.0.2'
Let’s assume that we need to have the snapshot versions only on a debug variant, and the stable versions on release variants only. For that we use the following:
dependencies {
debugImplementation 'com.sample.library:snapshot-production:1.0.2'
releaseImplementation 'com.sample.library:name-production:1.0.2'
}
If your project doesn’t have different flavors such as the library then there is no need for changes, but if your project also has Production & Staging flavors, you only use the production versions. Also if we wanted to add a staging version we could do something like this
dependencies {
debugImplementation 'com.sample.library:snapshot-production:1.0.2'
releaseImplementation 'com.sample.library:name-production:1.0.2'
debugImplementation 'com.sample.library:snapshot-staging:1.0.2'
releaseImplementation 'com.sample.library:name-staging:1.0.2'
}
Unfortunately, Gradle will present an error because of duplicates, so let’s assume that we are on the debug variant now. Gradle will then sync and find those two exact same versions
debugImplementation 'com.sample.library:snapshot-production:1.0.2'
debugImplementation 'com.sample.library:snapshot-staging:1.0.2'
It won’t know which one to choose, so it will throw a duplicate exception. We solve this by generating two Build Variants (Release, Debug) and two Product Flavors (Production, Staging), and by calculating the scenarios we will have these combinations
productionRelease
productionDebug
stagingRelease
stagingDebug
We then want to implement a specific library configuration on each scenario. For example, in production release in our app we want production & release version library to read ‘com.sample.library:name-production:1.0.2’
Another example is stagingDebug, we want the staging flavor & snapshot (debug) version library to read ‘com.sample.library:snapshot-staging:1.0.2’ and so on…
We know that Gradle supports Flavor-based implementations e.g. productionImplementation also builds variant implementations e.g. debugImplementation.
However, our goal is to have something like productionDebugImplementation which combines both scenarios together. Luckily we could do this easily in our app build.gradle
file by defining these custom configurations
configurations {
productionReleaseImplementation
productionDebugImplementation
stagingReleaseImplementation
stagingDebugImplementation
}
We don’t have to inform Gradle anything about these configurations as it’s already aware of these combinations by default. We just need to declare them and then we can use them instead of the regular implementation.
Using the new configurations of our implementation for the transactions module would be displayed like this
productionReleaseImplementation 'com.sample.library:name-production:1.0.2'
productionDebugImplementation 'com.sample.library:snapshot-production:1.0.2'
stagingReleaseImplementation 'com.sample.library:name-staging:1.0.2'
stagingDebugImplementation 'com.sample.library:snapshot-staging:1.0.2'
Sync your project and everything would be working like a charm 🔥
That’s it for now.
This is part 1 of a series of 3 articles. In the next segment, we will focus on the development workflow, and improve developers productivity with large-scale projects. In the last article, we will present how we could implement a Continuous Integration (CI) pipeline to automate publishing the Android Library using Github Actions.
Lastly, none of this is possible without some good music, here’s a link to my playlist:
https://open.spotify.com/playlist/4wxECzEZHxVXlnsNKkgclu?si=YfYZAnBCTvivsnVrS2lkkQ 🎸 Happy coding and stay tuned 👋🏼
Ahmed Elshaer | Senior Android Engineer at Trella