Welcome to follow the official wechat account: FSA Full stack action 👋

The message “jCenter will be discontinued soon “has a big impact on all Android developers. Many useful third-party libraries are uploaded to jCenter, and almost all Android projects rely on the jCenter repository. This means that Android developers have a strong dependency on it. As a third-party library user, once jCenter is stopped, there are only two options:

  1. Use third-party proxy repositories such as Ali (which may cache these third-party libraries that were hosted on jCenter)
  2. Pray for third-party library authors to synchronize libraries to Mavan Central soon

The following articles are recommended for other people’s opinions on the jCenter outage. If you are interested, you can read them:

Getting back to the subject, if you are a third-party library developer and have no previous experience uploading libraries to MavenCentral, this article can help you upload libraries to MavenCentral early

I. Sonatype account

1. Sign up for Sonatype

The relationship between MavenCentral and Sonatype is equivalent to jCenter and jForg:

Library platform Operator, Management background
jCenter jForg bintray.com
MavenCentral Sonatype oss.sonatype.org

Note: the latest management background link is: s01.oss.sonatype.org, see central.sonatype.org/publish/rel…

So, before uploading the library to MavenCentral, you need to sign up for Sonatype at issues.sonatype.org:

If you already have an account, log in directly, otherwise click Sign Up to enter the registration page:

Fill in your account, password, and email address to register with Sonatype. After registration, log in to Sonatype.

Note: Email address is very important. It is recommended that you use your email address in order to receive timely notification of reply information from Sonatype in the issue.

2. Apply for the upload permission

Now that you have a Sonatype account, the next step should be to upload the library to MavenCentral via the grdle script (s01.oss.sonatype.org). However, new Sonatype users do not have this permission by default. You can visit s01.oss.sonatype.org and click “Log In” In the upper right corner to try to Log In.

Note: there are two possibilities for this popup, one is the account password is wrong, the other is no permission.

Therefore, now we need to ask Sonatype to grant us this permission. Go back to the page issues.sonatype.org, click the new button at the top, and fill in the project information:

Note: the figure is my personal project information, just for example, do not copy!!

The only thing to notice in this step is the Group Id. There are two cases:

  • None Domain name: You can use the github subdomain nameio.github.usernameFor example, my Github account name is GitLqrio.github.gitlqr.
  • Have website domain name: can fill in personal or company domain name, such as:com.gitlqrIn addition, you also need to configure a TXT record in DNS configuration to verify domain name ownership, see:Central.sonatype.org/pages/produ…

Note: now can’t use com. Making a domain, the specific reason please see: central.sonatype.org/changelog/#… ; When using your own website domain name, it is recommended to write a top-level domain name instead of a subdomain specific to a project. In this way, you only need to apply for the Group Id once, and then all your other libraries will use the same Group Id.

After filling in the information, click “New” button to open an issue, and wait for Sonatype staff to review and reply:

Since Sonatype operates abroad, there will be time difference in working time. We need to wait patiently for Sonatype staff to deal with this issue, such as me:

Note: If you want to upload the library as soon as possible, as mentioned earlier, please use your usual email address and you will be notified by email as soon as a Sonatype worker makes a comment.

Gradle configuration

It may take a while to apply for upload permission from Sonatype for the first time, so we can sync gradle configurations.

Maven commits scripts

Create a new maven-publish.gradle file in the project root directory with the following contents:

Note: The following is a general configuration, just copy it.

if (project.hasProperty("android")) { // Android libraries
    task sourcesJar(type: Jar) {
        classifier = 'sources'
        from android.sourceSets.main.java.srcDirs
    }

    task javadoc(type: Javadoc) {
        // https://github.com/novoda/bintray-release/issues/71
        excludes = ['**/*.kt'] // < ---- Exclude all kotlin files from javadoc file.
        source = android.sourceSets.main.java.srcDirs
        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
        options.encoding = "utf-8"
        options.charSet = "utf-8"}}else { // Java libraries
    task sourcesJar(type: Jar, dependsOn: classes) {
        classifier = 'sources'
        from sourceSets.main.allSource
    }
}

// Enforce utF-8 encoding for Java/JavaDoc etc
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

tasks.withType(Javadoc) {
    options.encoding = "UTF-8"
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

// add javadoc/source jar tasks as artifacts
artifacts {
    archives javadocJar
    archives sourcesJar
}

apply plugin: 'maven'
apply plugin: 'signing'


//Properties properties = new Properties()
//properties.load(project.rootProject.file('local.properties').newDataInputStream())
//
//def ossrhUsername = properties.getProperty("ossrhUsername")
//def ossrhPassword = properties.getProperty("ossrhPassword")

def PUBLISH_GROUP_ID = publishedGroupId // The groupId can not be applied directly as long as the beginning of the groupId is ok

def PUBLISH_ARTIFACT_ID = artifact

def PUBLISH_VERSION = libraryVersion / / android. DefaultConfig. VersionName / / this is configured in the direct access to library gradle version number, need not change the version number, only need to maintain a can.

/ / signature
signing {
    required { gradle.taskGraph.hasTask("uploadArchives") }
    sign configurations.archives
}

uploadArchives {
    repositories {
        mavenDeployer {

            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

            repository(url: "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
                authentication(userName: ossrhUsername, password: ossrhPassword)
            }

            snapshotRepository(url: "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
                authentication(userName: ossrhUsername, password: ossrhPassword)
            }

            pom.groupId = PUBLISH_GROUP_ID
            pom.artifactId = PUBLISH_ARTIFACT_ID
            pom.version = PUBLISH_VERSION

            pom.project {
                packaging 'aar' // I publish the android package here, all written aar

                name libraryName // 'Simple name for publishing library'
                // optionally artifactId can be defined here
                description libraryDescription // 'Package description'
                url siteUrl // 'You can write the company website address or github personal page address'

                scm {
                    connection gitUrl // 'SCM: replace with project git address'
                    developerConnection gitUrl // 'SCM: replace the project address starting with git'
                    url siteUrl // 'Project home page, can be the github project home page'
                }

                licenses {
                    license {
                        name licenseName // 'The Apache License, Version 2.0'
                        url licenseUrl / / 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }

                developers {
                    developer {
                        id developerId // 'Fill in your full name when you apply for the account'
                        name developerName // 'Just fill it in here'
                        email developerEmail// 'Please use the email address to apply for the account'
                    }
                }
            }
        }
    }
}
Copy the code

2. Configure Maven library information

Library information shares two configurations:

  • General information: fill in the project root directorygradle.prpertiesFile.
  • Module information: in the specific Module directorybuild.gradleFile.

General informationgradle.prpertiesconfiguration

PublishedGroupId = GroupId siteUrl= project url gitUrl=git link developerId= account ID developerName= account ID developerEmail= mailbox licenseName=The Apache Software License, Version2.0
licenseUrl=http:/ / www.apache.org/licenses/LICENSE-2.0.txt
allLicenses=["Apache - 2.0"]
Copy the code

Please refer to github.com/GitLqr/Lite…

The Module informationbuild.gradleconfiguration

ext {
    artifact = 'Library unique identifier'
    libraryName = 'Simple name for publishing library'
    libraryDescription = 'Release package description'
    libraryVersion = 'Release library version number'
}
Copy the code

Please refer to github.com/GitLqr/Lite…

3. Import the Maven script

Add the following code at the bottom of the build.gradle file in the corresponding Module directory of the library:

apply from: '.. /maven-publish.gradle'
Copy the code

Upload /uploadArchives = upload/uploadArchives = upload/uploadArchives = upload/uploadArchives = upload/uploadArchives = upload/uploadArchives

Iii. GPG signature

After passing the above two steps, you still need the last step. At this time, you cannot commit normally when running uploadArchives task. MavenCentral also needs to configure the GPG signature file.

1. Use Gpg4win to generate GPG key

Note: the following generated GPG key operation process is using a Windows environment, if you are using a Mac, please refer to: www.jianshu.com/p/1c715203c…

Go to www.gpg4win.org/get-gpg4win… Download and install Gpg4win:

To start Gpg4win, click “File” – “New Key Pair…” :

Create a personal OpenPGP key pair:

Fill in the account, email, and select Protect the generated key with a passphrase:

Note: In advanced Settings, you can set more details, such as expiration time, but the expiration time should not be too long, or error.

Click “New” and set password (confirm password) :

After the key is generated, the following popup window appears, click “Finish” :

Double-click the newly created key in the main interface, and the following popup window will appear. You need to copy the 8 characters at the bottom, which will be used in the later [Configuring key] link:

On the home screen, right-click the newly created key and click “Publish to server…” And then determine along the way:

On the home screen, right-click the newly created key and click “Export…” Change the file name to “GPG” or “PGP” and click save:

Note that Gpg4win is exported in two ways:

  • "Export..."Export the public key
  • "Backup Secret Keys"Export:The private key!!!!!

Tips: The following steps need to use the private key, so you need to click “Backup Secret Keys” to export the GPG file of the private key; When exporting, the default file suffix is “asC”. Be sure to change the suffix to “GPG” to generate the correct binary GPG key file. It is useless to save as ASC text file and then change to GPG!!

2. Configure the key

This step is critical and needs in a computer user directory of gradle/gradle properties configured in the following content:

For example: C: \ Users \ CharyLin \. Gradle \ gradle properties

# MavenCentral
signing.keyId=The last eight bits of the key we just obtained
signing.password=The password we set when we executed the command earlier
signing.secretKeyRingFile=Path to the GPG file just generated
ossrhUsername=Sonatype user name
ossrhPassword=Sonatype password
Copy the code

Four, publish,

uploadArchives

At this point, double-click the uploadArchives task in the Gradle panel. If the uploadArchives task succeeds, the following log will appear:

11:12:00: Executing task 'uploadArchives'... . > Task :litearouter-api:sourcesJar UP-TO-DATE > Task :litearouter-api:signArchives UP-TO-DATE > Task :litearouter-api:uploadArchives ... BUILD SUCCESSFUL in 16s 23 actionable tasks: 1 executed, 22 up-to-date 11:12:16: Task execution finished 'uploadArchives'.Copy the code

Unable to read secret key from file: It may not be a PGP secret key ring Unable to read secret key from file: It may not be a PGP secret key ring Unable to read secret key from file: It may not be a PGP secret key ring

  • The GPG account or password is incorrect
  • The GPG public key file is used
  • GPG key files are used, but are saved as ASC files and then modified to GPG files
FAILURE: Build failed with an exception.

* What went wrong:
Could not evaluate onlyIf predicate for task ':litearouter-annotation:signArchives'.
> Unable to read secret key from file: D:\CharyLinDatas\GitLqr\secret.gpg (it may not be a PGP secret key ring)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 11s
Copy the code

2. Release archives

Now you can go to the admin background under login s01.oss.sonatype.org/ and click on the left side of “Staging Repositories”:

Select the package you just uploaded, and under the Content TAB at the bottom, you can see what files are in the package:

When you are sure, click “Close”, fill in the description, and then click “Confirm”:

Normally, “Repository closed” with a checkmark in the Activity TAB is closed after a few minutes:

Then click the “Release” button again to publish to MavenCentral. Wait a few hours and you can check the results at search.maven.org/.

Because the “Automatically Drop” option was selected during Release, the package will be Automatically removed from the Staging Repository when it is successfully published.

Note that if your library has several components (like my project contains litearouter-Annotation, litearouter-API, and litearouter-compiler), remember to use them one by one. For example:

  • litearouter-annotation: upload –> close –> release
  • litearouter-api: upload –> close –> release
  • litearouter-compiler: upload –> close –> release

Do not upload all of them at one time, then close them at one time, and finally release them at one time. This approach is not sure what consequences it will bring, so it is recommended not to do so.

Five, the complement

1.Group IdWhat is the

In gradle can use implementation to rely on a certain third-party libraries, structure is: the implementation GroupId: ArtifactId: Version:

Such as: implementation ‘com. Android. Support: appcompat – v7:27.1.1’

Part of the explain
GroupId Is the unique identifier of the project organization. In practical development, it generally corresponds to the structure of the JAVA package, which is the JAVA directory structure in the main directory, such as’ com.android.support ‘.
ArtifactId Is the unique identifier of the project. In actual development, it generally corresponds to the name of the project, which is the name of the root directory of the project, for example, AppCompat-v7.
Version Is the project version number, for example, 1.0-snapshot. Where 1.0 is the version number and SNAPSHOT represents an unstable version that is still under development. A derived Release represents a stable Release

Note: GroupId generally corresponds to package structure, that is, GroupId and package name can be different. Just as in Android projects, the applicationId and package name are two different concepts.

The resources

  • Android library to Maven Central overview
  • Android release library to MavenCentral instructions as well as stomp fix

If this article is helpful to you, please click on my wechat official number: FSA Full Stack Action, which will be the biggest incentive for me. The public account not only has Android technology, but also iOS, Python and other articles, which may have some skills you want to know about oh ~