The Ultimate Guide to Creating and Publishing Android Libraries

The Ultimate Guide to Creating and Publishing Android Libraries

I am often amazed by the number of useful third-party libraries in the Android development community. For a long time, I wanted to contribute something, but I didn't know how to do it. After browsing many other articles on how to publish an Android development library, I still found that some details were missing, and all the information was in different places. So, I will walk through the process and show you how I did it.

For beginners, I recommend using Android Studio to create all Android projects. Android Studio officially uses the Gradle build system. Please make sure you download the latest version of Android Studio.

[[185318]]

Introduction to related terms

Before we get started, there are some terms you should be familiar with.

Project — In Android Studio, a project is a complete Android app. An Android Studio project contains one or more modules. In Android Studio, a project is similar to a workspace in Eclipse.

Module – A module is a component of an app that can be built, tested, and debugged separately. A module contains the source code and resource files of an app. In Android Studio, a module is similar to a project in Eclipse.

AAR – The 'aar' package is a binary distribution of the Android development library project. (AAR format) The main output of the development library project is the .aar package (which means Android archive). It is a combination of compiled code (such as jar files or .so files) and resource files (such as manifest files, res files, asset files).

Maven Central Repository – A repository provided by the Maven community. It contains many commonly used development libraries. The Search Maven website can be used to browse the contents of the Maven Central Repository. The Gradle, Please website is another tool that can be used to search the central repository. If you add jCenter() to the repository configuration section of the project configuration file, Gradle will use the jCenter repository (jCenter instructions). Maven Central Repository is also often referred to as Maven Center or Central Repository.

Sonatype — Sonatype's Open Source Software Repository Hosting (OSSRH) service is the primary way for project authors and contributors to publish their components to a central repository. It is a deployment hosting service for open source projects provided by the Sonatype Nexus Professional organization using the Nexus Staging Suite tool. The service is mainly used to handle deployment and verification operations, and also provides synchronization operations to deliver content to the central repository over the network.

GPG - GNU Privacy Guard (also known as GPG or GnuPG), a GNU project, is a cryptographic software that follows the OpenPGP (RFC4880) standard and is a free alternative to PGP. With GPG you can encrypt (decrypt) files containing sensitive data, such as electronic health information that is protected by the privacy and security of the Health Insurance Portability and Accountability Act (HIPAA). For more information on GPG, visit the GNU Privacy Guard website.

Prepare your Android development library

I will use my Trestle development library as an example. In your project, you need to modify some places to prepare it for publishing to Maven Central as a development library.

  • Separate the core code of the library from the sample code. In my project, I separate them into two modules: library and sample. Please read the tips about creating a library module carefully. You may also need to rename your module.
  • In the build.gradle file of the sample module, make sure to include the following:
  1. apply plugin: 'com.android.application'  
  2.  
  3. dependencies {
  4.  
  5. compile project( ':library' )
  6. }
  • In your library module's build.gradle file, make sure you include the following:
  1. apply plugin: 'com.android.library'  
  2.  
  3. apply from : 'maven-push.gradle'  
  • In the library module, add a gradle.properties file and make sure it contains the following content:
  1. POM_NAME=ProjectName
  2.  
  3. POM_ARTIFACT_ID=projectname
  4.  
  5. POM_PACKAGING=aar
  • In the library module, add the maven-push.gradle file and make sure it contains the following content:
  1. /*
  2.  
  3. * Copyright 2013 Chris Banes
  4.  
  5. *
  6.  
  7. * Licensed under the Apache License, Version 2.0 (the "License" );
  8.  
  9. * you may not use this file except   in compliance with the License.
  10.  
  11. * You may obtain a copy of the License at  
  12.  
  13. *
  14.  
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16.  
  17. *
  18.  
  19. * Unless required by applicable law or agreed to   in writing, software
  20.  
  21. * distributed under the License is distributed on an "AS IS" BASIS,
  22.  
  23. * WITHOUT WARRANTIES OR CONDITIONS OF   ANY KIND, either express or implied.
  24.  
  25. * See the License for the specific language governing permissions and  
  26.  
  27. * limitations under the License.
  28.  
  29. */
  30.  
  31.   
  32.  
  33. apply plugin: 'maven'  
  34.  
  35. apply plugin: 'signing'  
  36.  
  37.   
  38.  
  39. def isReleaseBuild() {
  40.  
  41. return VERSION_NAME. contains ( "SNAPSHOT" ) == false  
  42.  
  43. }
  44.  
  45.   
  46.  
  47. def getReleaseRepositoryUrl() {
  48.  
  49. return hasProperty( 'RELEASE_REPOSITORY_URL' ) ? RELEASE_REPOSITORY_URL
  50.  
  51. : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"  
  52.  
  53. }
  54.  
  55.   
  56.  
  57. def getSnapshotRepositoryUrl() {
  58.  
  59. return hasProperty( 'SNAPSHOT_REPOSITORY_URL' ) ? SNAPSHOT_REPOSITORY_URL
  60.  
  61. : "https://oss.sonatype.org/content/repositories/snapshots/"  
  62.  
  63. }
  64.  
  65.   
  66.  
  67. def getRepositoryUsername() {
  68.  
  69. return hasProperty( 'NEXUS_USERNAME' ) ? NEXUS_USERNAME : ""  
  70.  
  71. }
  72.  
  73.   
  74.  
  75. def getRepositoryPassword() {
  76.  
  77. return hasProperty( 'NEXUS_PASSWORD' ) ? NEXUS_PASSWORD : ""  
  78.  
  79. }
  80.  
  81.   
  82.  
  83. afterEvaluate { project ->
  84.  
  85. uploadArchives {
  86.  
  87. repositories {
  88.  
  89. mavenDeployer {
  90.  
  91. beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
  92.  
  93.   
  94.  
  95. pom.groupId = GROUP  
  96.  
  97. pom.artifactId = POM_ARTIFACT_ID
  98.  
  99. pom.version = VERSION_NAME
  100.  
  101.   
  102.  
  103. repository(url: getReleaseRepositoryUrl()) {
  104.  
  105. authentication(userName: getRepositoryUsername(), password : getRepositoryPassword())
  106.  
  107. }
  108.  
  109. snapshotRepository(url: getSnapshotRepositoryUrl()) {
  110.  
  111. authentication(userName: getRepositoryUsername(), password : getRepositoryPassword())
  112.  
  113. }
  114.  
  115.   
  116.  
  117. pom.project {
  118.  
  119. name POM_NAME
  120.  
  121. packaging POM_PACKAGING
  122.  
  123. description POM_DESCRIPTION
  124.  
  125. urlPOM_URL
  126.  
  127.   
  128.  
  129. scm {
  130.  
  131. url POM_SCM_URL
  132.  
  133. connection POM_SCM_CONNECTION
  134.  
  135. developerConnection POM_SCM_DEV_CONNECTION
  136.  
  137. }
  138.  
  139.   
  140.  
  141. licenses {
  142.  
  143. license {
  144.  
  145. name POM_LICENCE_NAME
  146.  
  147. url POM_LICENCE_URL
  148.  
  149. distribution POM_LICENCE_DIST
  150.  
  151. }
  152.  
  153. }
  154.  
  155.   
  156.  
  157. developers {
  158.  
  159. developer {
  160.  
  161. id POM_DEVELOPER_ID
  162.  
  163. name POM_DEVELOPER_NAME
  164.  
  165. }
  166.  
  167. }
  168.  
  169. }
  170.  
  171. }
  172.  
  173. }
  174.  
  175. }
  176.  
  177.   
  178.  
  179. signing
  180.  
  181. required { isReleaseBuild() && gradle.taskGraph.hasTask( "uploadArchives" ) }
  182.  
  183. sign configurations.archives
  184.  
  185. }
  186.  
  187.   
  188.  
  189. //task androidJavadocs(type: Javadoc) {
  190.  
  191. //source = android.sourceSets.main.allJava
  192.  
  193. //}
  194.  
  195.   
  196.  
  197. //task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
  198.  
  199. //classifier = 'javadoc'  
  200.  
  201. // from androidJavadocs.destinationDir
  202.  
  203. //}
  204.  
  205.   
  206.  
  207. task androidSourcesJar(type: Jar) {
  208.  
  209. classifier = 'sources'  
  210.  
  211. from android.sourceSets.main.java.sourceFiles
  212.  
  213. }
  214.  
  215.   
  216.  
  217. artifacts
  218.  
  219. archives androidSourcesJar
  220.  
  221. }
  222.  
  223. }
  • Modify the .gitignore file in the project root directory
  1. # [Android] ========================
  2.  
  3. # Built application files
  4.  
  5. *.apk
  6.  
  7. *.ap_
  8.  
  9.   
  10.  
  11. # Files for the Dalvik VM
  12.  
  13. *.dex
  14.  
  15.   
  16.  
  17. # Java class files
  18.  
  19. *.class
  20.  
  21.   
  22.  
  23. # Generated files
  24.  
  25. bin/
  26.  
  27. gen/
  28.  
  29.   
  30.  
  31. # Gradle files
  32.  
  33. .gradle/
  34.  
  35. build/
  36.  
  37.   
  38.  
  39. # Local configuration file (sdk path, etc)
  40.  
  41. local .properties
  42.  
  43.   
  44.  
  45. # Proguard folder generated by Eclipse
  46.  
  47. proguard/
  48.  
  49.   
  50.  
  51. # Log Files
  52.  
  53. *.log
  54.  
  55.   
  56.  
  57. ## Directory-based project format:
  58.  
  59. .idea/
  60.  
  61.   
  62.  
  63. ## File-based project format:
  64.  
  65. *.ipr
  66.  
  67. *.iws
  68.  
  69.   
  70.  
  71. ## Plugin-specific files:
  72.  
  73.   
  74.  
  75. # IntelliJ
  76.  
  77. out /
  78.  
  79.   
  80.  
  81. # mpeltonen/sbt-idea plugin
  82.  
  83. .idea_modules/
  84.  
  85.   
  86.  
  87. # JIRA plugin
  88.  
  89. atlassian-ide-plugin.xml
  90.  
  91.   
  92.  
  93. # Crashlytics plugin ( for Android Studio and IntelliJ)
  94.  
  95. com_crashlytics_export_strings.xml
  96.  
  97.   
  98.  
  99. # [Maven] ========================
  100.  
  101. target/
  102.  
  103. pom.xml.tag
  104.  
  105. pom.xml.releaseBackup
  106.  
  107. pom.xml.versionsBackup
  108.  
  109. pom.xml.next  
  110.  
  111. release.properties
  112.  
  113.   
  114.  
  115. # [Gradle-Android] ========================
  116.  
  117.   
  118.  
  119. # Ignore Gradle GUI config
  120.  
  121. gradle-app.setting
  122.  
  123.   
  124.  
  125. # Gradle Signing
  126.  
  127. signing.properties
  128.  
  129. trestle.keystore
  130.  
  131.   
  132.  
  133. # Mobile Tools for Java (J2ME)
  134.  
  135. .mtj.tmp/
  136.  
  137.   
  138.  
  139. # Package Files #
  140.  
  141. *.jar
  142.  
  143. *.war
  144.  
  145. *.ear
  146.  
  147.   
  148.  
  149. # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
  150.  
  151. hs_err_pid*
  152.  
  153.   
  154.  
  155. # Misc
  156.  
  157. /.idea/workspace.xml
  158.  
  159. .DS_Store
  160.  
  161. /captures
  162.  
  163. **/*.iml
  164.  
  165. *.class
  • Modify the settings.gradle file in the project root directory
  1. include ':sample' , ':library'  
  • Modify the gradle.properties file in the project root directory
  1. # Project-wide Gradle settings.
  2.  
  3.   
  4.  
  5. # IDE (eg Android Studio) users:
  6.  
  7. # Gradle settings configured through the IDE *will override*
  8.  
  9. # any settings specified in this file.
  10.  
  11.   
  12.  
  13. # For more details on how to configure your build environment visit
  14.  
  15. # http://www.gradle.org/docs/ current /userguide/build_environment.html
  16.  
  17.   
  18.  
  19. # Specifies the JVM arguments used for the daemon process.
  20.  
  21. # The setting is particularly useful for tweaking memory settings.
  22.  
  23. # Default value: -Xmx10248m -XX:MaxPermSize=256m
  24.  
  25. # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
  26.  
  27.   
  28.  
  29. # When configured, Gradle will run in incubating parallel mode.
  30.  
  31. # This option should only be used with decoupled projects. More details, visit
  32.  
  33. # http://www.gradle.org/docs/ current /userguide/multi_project_builds.html#sec:decoupled_projects
  34.  
  35. # org.gradle.parallel = true  
  36.  
  37.   
  38.  
  39. VERSION_NAME=0.0.1
  40.  
  41. VERSION_CODE=1
  42.  
  43. GROUP =com.github.github_username
  44.  
  45.   
  46.  
  47. POM_DESCRIPTION=A library that does X, Y, and Z
  48.  
  49. POM_URL=https://github.com/github_username/ProjectName
  50.  
  51. POM_SCM_URL=https://github.com/github_username/ProjectName
  52.  
  53. POM_SCM_CONNECTION=scm:[email protected]:github_username/ProjectName.git
  54.  
  55. POM_SCM_DEV_CONNECTION=scm:[email protected]:github_username/ProjectName.git
  56.  
  57. POM_LICENCE_NAME=The Apache Software License, Version 2.0
  58.  
  59. POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
  60.  
  61. POM_LICENCE_DIST=repo
  62.  
  63. POM_DEVELOPER_ID=github_username
  64.  
  65. POM_DEVELOPER_NAME=GitHub FullName
  • Add a README.md file to introduce your library to other developers and how to use it. If you want to add some screenshots to your README.md file, I highly recommend an app called Screenr.

Install GPG

If you don't have GPG installed on your machine, you will need to download and install it. If you are using MacOSX, the installation instructions are here.

If you have never used GPG - first, create a GPG key:

  1. $ gpg --gen-key  

If you're unsure how to answer the questions when you create your GPG key, this guide (Creating an encryption key) can help.

Next, find your key ID:

  1. $ gpg --list-keys  

The first line will be something like pub XXXXX/YYYYYYYY <date>. Remember, the 'YYYYYYYY' part is your key ID.

Now, publish your key:

  1. $ gpg --keyserver hkp://keyserver.ubuntu.com --send-keys YYYYYYYY  
  2.  
  3. $ gpg --keyserver hkp://pgp.mit.edu --send-keys YYYYYYYY  

You can of course use other key servers, and you can also confirm whether your key has been published by running the following command:

  1. $ gpg --keyserver hkp://pgp.mit.edu --search-keys [email protected] # Use your email  

To get your library listed on the Gradle, Please website (and to make it easier for others to reference your library), please upload your project to Maven Central. The easiest way to upload a project is to use Sonatype.

Sonatype

  1. Create a JIRA account at Sonatype.
  2. After logging in successfully, create a new issue.

I created a GitHub repository for my Trestle project. So the fields I filled in on the new issue looked like this:

Group Id : com.github.<github_username>

Project URL : https://github.com/<github_username>/<project_name>

SCM url : https://github.com/<github_username>/<project_name>.git

Username : <sonatype_username>

Already Synced to Central : No

Note: I added brackets as placeholders around the fields you need to fill in. You will need to replace them with the appropriate values.

When you are ready to submit an issue, the details of the issue should be similar to the screenshot above. After you submit it, Sonatype will take 2 working days to process your issue. Then, you will receive a confirmation email informing you that your configuration is ready and you can publish your open source library.

Don't deploy your open source repository until you receive an email indicating that your ticket is OK. A common mistake for new projects is to deploy too early. This will mistakenly make your artifacts available in a repository for everyone to access.

Finally, if your component is already in the central repository, please add the following information to your ticket and refer to this article on how to migrate to OSSRH.

Modify the ~/.gradle/gradle.properties file on your machine to include the following:

  1. NEXUS_USERNAME=sonatype_username
  2.  
  3. NEXUS_PASSWORD=sonatype_password
  4.  
  5. signing.keyId=gpg_key_id
  6.  
  7. signing.password =gpg_password
  8.  
  9. signing.secretKeyRingFile=/Users/username/.gnupg/secring.gpg
  10.  
  11. org.gradle.daemon = true  

When you publish the repository, the authentication information is provided in the gradle.properties file. Please make sure to provide the correct nexus username and password (that is, the Sonatype username and password), otherwise you will get an unauthorized 401 error.

NOTE: If you have published a repository before, you do not need to create a new issue in JIRA (Sonatype). There is one JIRA issue for each top-level groupId. You should already have all the permissions you need to deploy any new artifacts to your groupId or subordinate groups. Syncing with the central repository follows a top-down process, so any releases from subordinate groups will be automatically synced. When you publish new components, you do not need to tell Sonatype because there is nothing for Sonatype to configure or check when you sync the repository. Sonatype will only post a twitter message the first time it syncs.

release

Once you are ready to publish your development library, in Android Studio, open the Gradle view on the right, under Tasks > upload, click uploadArchives, which will upload your development library to the Sonatype Staging Repositories.

On the Sonatype Staging Repositories page, log in to your Sonatype account, find your 'staging' repository, it should be at the end of the list, select it and press the 'Close' button. Closing a repository actually means you are preparing to publish it. If everything went well – you should see an activated 'Publish' button. You may need to refresh the page. Press the Publish button. Please read the help documentation about managing repositories with Nexus. If this is the first repository you have published, go back to JIRA and post a comment in JIRA that you have improved your repository, if it is not the first, there is no need to tell Sonatype that you have improved your repository. Then, you should receive a reply message from Sonatype saying that your repository will be ready in 10 minutes and will be synchronized to the Maven Central Repository in the next few hours. After a few hours, it will be displayed on the Gradle, Please website.

Using your development libraries

For other developers to use your development library, they need to add a dependency in the build.gradle file of the Android project, as shown below:

  1. apply plugin: 'android'  
  2.  
  3. dependencies {
  4.  
  5. compile 'com.github.lawloretienne:trestle:0.0.3'  
  6.  
  7. }

Special Thanks

Many thanks to Chris Banes, Jonathan Le, Serge Zaitsev, and others who posted on the blog, whose articles helped me navigate this complex process.

My development library

QuickReturn — https://github.com/lawloretienne/QuickReturn

Trestle — https://github.com/lawloretienne/Trestle

ImageGallery — https://github.com/lawloretienne/ImageGallery

<<:  Agora.io launches AMG Voice, a real-time voice service for mobile games

>>:  Detailed explanation of Android Transition Framework --- super cool animation framework

Recommend

How to increase followers through Luckin Coffee’s coupon event!

Will Luckin Coffee become the next ofo? Luckin Co...

“The first bucket of milk tea in autumn”, will it save life or kill you?

Yesterday was the beginning of autumn, and “the f...

December Marketing Node Reminder [Dry Goods Collection]

The cold December is here, and there are still ma...

How to use IIS to build a website on a VPS server?

For SEO website optimizers, knowing how to build ...

Are you one of the people at high risk of cancer?

Author: Professor Guo Tuankui, Department of Onco...

Smart autumn harvest | Strawberries grown in the sky are sweet

Produced by: Science Popularization China Author:...