Publishing Android Library to GitHub Package Registry
GitHub introduced a software package hosting service that allows you to host your software packages privately or publicly. Much like NPM, you can use the packages as dependencies on your project. In my opinion, I think the idea of having the source code for a particular project with its packages in one platform is great because it increases the accessibility of your software to the developers who are interested in it; they can easily checkout the codebase without switching browsers. Also GitHub made it easy to publish packages with just a few configs.
Without further ado lets dive into how you can publish an Android library to GitHub packages. If you want to learn more about GPR checkout this link About GitHub Packages
Applying Maven Plugin
The first step is to apply the maven plugin to your build.gradle
file. We shall be using the Maven Publish plugin.
apply plugin: 'maven-publish'
Add the Gradle Publishing Task
Next you customize the publication task by setting the groupId
, artifactId
and version
for the library. We define the method getArtifactId
to return the artifactId
of our library, usually the package name the Android library.
Also remember to update the library version each time you are publishing to GPR. Maven publish plugin provides capabilities for customizing the generated pom
file. In our case we are just setting the project name and description. Please check out MavenPom in the DSL Reference for the complete documentation of available properties and methods.
Inside the pom.withXml
method, we are manually adding the library dependencies to our pom file because the publication doesn't know about our dependencies. We are also checking for transitive dependencies and excluding them. Refer to this Gist for more.
def getArtifactId = { ->
return "your-library"
}
publishing {
publications {
bar(MavenPublication) {
groupId 'com.somecompany'
artifactId getArtifactId()
version '1.0.0'
artifact("$buildDir/outputs/aar/${getArtifactId()}-release.aar")
artifact androidJavadocsJar
artifact androidSourcesJar
pom {
name = 'Name of your Project'
description = 'Your project description goes here.'
}
pom.withXml {
final dependenciesNode = asNode().appendNode('dependencies')
ext.addDependency = { dep, String scope ->
if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified")
return // ignore invalid dependencies
final dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dep.group)
dependencyNode.appendNode('artifactId', dep.name)
dependencyNode.appendNode('version', dep.version)
dependencyNode.appendNode('scope', scope)
if (!dep.transitive) {
// If this dependency is not transitive, we should force exclude all its dependencies from the POM
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
exclusionNode.appendNode('groupId', '*')
exclusionNode.appendNode('artifactId', '*')
} else if (!dep.properties.excludeRules.empty) {
// Otherwise add specified exclude rules
final exclusionsNode = dependencyNode.appendNode('exclusions')
dep.properties.excludeRules.each { rule ->
final exclusionNode = exclusionsNode.appendNode('exclusion')
exclusionNode.appendNode('groupId', rule.group ?: '*')
exclusionNode.appendNode('artifactId', rule.module ?: '*')
}
}
}
// List all "implementation" dependencies (for old Gradle)
configurations.implementation.getDependencies().each { dep -> addDependency(dep, "implementation") }
// List all "api" dependencies (for new Gradle) as "implementation" dependencies
configurations.api.getDependencies().each { dep -> addDependency(dep, "implementation") }
// List all "implementation" dependencies (for new Gradle) as "runtime" dependencies
configurations.implementation.getDependencies().each { dep -> addDependency(dep, "runtime") }
}
}
}
}
Note You can name
bar
to anything. I just used it as a placeholder but it should be the name of your publication.
Publishing to GitHub Package Registry
Setting Credential and Adding Repository
GPR requires authentication before publishing. Therefore you will be required to provide a GitHub Personal Access Token together with your username. If you don't have a personal access token see this link on how to create one. Personal access token.
Once you have obtained the access token save them in the local.properties
file of your project or on the System
environment variables. In our case we have saved the GitHub username and access token to the properties named gpr.usr
and gpr.key
respectively. We then read the file content into a variable named properties
.
def properties = new Properties()
properties.load(new FileInputStream(rootProject.file("local.properties")))
//Declared inside the closure `publishing` at the same level as `publications`
publishing {
publications { /** Refer to publications content above **/}
repositories {
maven {
name = "GitHubPackages"
/** Configure path of the package repository on Github using your username and repository */
url = uri("https://maven.pkg.github.com/githubusername/your-repository")
credentials {
/** get credentials from local.properties in root project folder file with */
username = properties['gpr.usr'] ?: System.getenv("GPR_USER")
password = properties['gpr.key'] ?: System.getenv("GPR_API_KEY")
}
}
}
}
repositories
closure is part of thepublishing
task and is included within the same level aspublications
Publishing our library
Finally lets publish our library. First you can list the available gradle
tasks by running this command.
./gradlew tasks
Among the listed tasks, we have publish
- used to publish all the publications declared in the project (remember we named ours bar
). But also notice we have a publishBarPublicationToGitHubPackagesRepository
task that is specific to our publication.
publishToMavenLocal
task is used to publish all publications to the local Maven cache and publishBarPublicationToMavenLocal
to publish our specific publication.
To wrap this up we handle the publication with the following command. The command does the following: cleans the build directory, bundles our Android library into an aar
file that will be stored in the build/output/aar
directory of our project. Then finally publishes the bundled aar
file to GPR.
./gradlew :your-libary:clean && ./gradlew :your-library:assembleRelease && ./gradlew publish
That's it. I hope you find this article helpful and that you will consider using GitHub Package Register in your next project.