It is recommended to migrate the collection from jCenter to Maven central

Posted by lazersam on Mon, 07 Mar 2022 20:14:50 +0100

There are many tutorials published to Maven Central, but most of them have problems. This article is my summary based on solving many problems, which is used to help students in need avoid repeating the same mistakes. What you need can be collected. What if you use it~

1,Farewell to Bintray jCenter

First of all, say goodbye to bintray jcenter Compared with Maven Central, bintray jcenter has much better performance and convenience. Unfortunately, jcenter is about to shut down. Jcenter has still provided me with a lot of convenience. It's a pity to close it:

2. Publish to Maven Central

Step 1: register and activate sonatype

Before publishing to Maven Central, first register an account with sonatype,

https://issues.sonatype.org/

After registering the account, you need to activate the account by creating an issue. The page is as follows:

Here are a few points to note:

  1. Select Community Support - Open Source Project Repository Hosting
  2. Select New Project as the problem type
  3. Summary: describe the project function, not important
  4. Group Id is more important. We will explain later
  5. The Project URL can be filled in with its own open source project address, which must be related to the Group Id
  6. SCM url is the pull address of the version warehouse. Fill in the GIT link address of your project, which is usually added after the project address git

For the group id here, it is the group id referenced after publishing. You can use your own domain name, but you need to prove that the domain name is your own. If you don't use your own domain name, a simple and common way is to use GitHub's address. For example, my GitHub address is https://github.com/Shouheng88 , you can write com github. Shouheng88. Within a few minutes after the issue is created, you will receive an email from the other party, which will prompt you to verify the activation by creating an item in GitHub:

After we created the project according to the email instructions, we modified the problem status and activated it successfully in a few minutes.

Step 2: apply for key

In order to ensure the quality level of the components available in the central repository, OSSRH has clear requirements for the submitted documents. In addition to jar packages and pom files, Javadoc and Sources are required (similar to bindray jcenter), and each file must have a corresponding asc file, GPG signature file, to verify the file. Therefore, in this step, we need to apply for a key.

You can use brew to install OSX,

$ brew update
$ brew install -v gpg

You can also download and install directly under Windows,

https://www.gpg4win.org/get-gpg4win.html

After installation, the key can be generated through the following instructions:

gpg --generate-key

In the process of creating the key, you will be required to enter the password. The password here is very important and will be used when we publish it.

After creation, all created keys can be displayed through gpg -k:

The string ab7fxxxxxxxxxxxxxxxxxxaba846D44F7B66 here is called the key fingerprint. The last 8 bits of D44F7B66 are called KEY ID, which will be used when we release it.

In addition, a file named secretKeyRingFile is required for file signature, which can be generated by the following command:

gpg --export-secret-keys [Key fingerprint] > secret.gpg

After submitting in the warehouse of sonatype, you need to download the matching public key from multiple public key servers, and then verify the signature of the uploaded file. Therefore, we need to upload the public key to the public key server through the following command:

gpg --keyserver keyserver.ubuntu.com --send-keys [Key fingerprint]

Step 3: preparing to publish script

First, we need to introduce two plug-ins,

apply plugin: 'maven-publish'
apply plugin: 'signing'

Then write the published grade script as follows

task androidSourcesJar(type: Jar) {
    archiveClassifier.set("sources")
    from android.sourceSets.main.java.source
    exclude "**/R.class"
    exclude "**/BuildConfig.class"
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            // group id, the dependent group id referenced after publishing
            groupId 'com.github.Shouheng88'
            // Dependent artifact id referenced after publishing
            artifactId 'sil'
            // Released version
            version '0.1.0'
            // Released arr files and source files
            artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
            artifact androidSourcesJar
            pom {
                // Component name, which can be customized
                name = 'uix-common'
                // Component description
                description = 'Android UIX'
                // Component home page
                url = 'https://github.com/Shouheng88/Android-uix'
                // License name and address
                licenses {
                    license {
                        name = 'The Apache License, Version 2.0'
                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }
                // Developer Information
                developers {
                    developer {
                        name = 'ShouHeng'
                        email = 'shouheng2015@gmail.com'
                    }
                }
                // Version control warehouse address
                scm {
                    url = 'https://github.com/Shouheng88/Android-uix'
                    connection = 'scm:git:github.com/Shouheng88/Android-uix.git'
                    developerConnection = 'scm:git:ssh://git@github.com/Shouheng88/Android-uix.git'
                }
            }
        }
    }
    repositories {
        maven {
            // The location of the release. The SNAPSHOT and the final version are distinguished according to the released version
            def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                // This is where I was at issues sonatype. Org registered account
                username ossrhUsername
                password ossrhPassword
            }
        }
    }
}

signing {
    sign publishing.publications
}

Note: the group id here must be consistent with the group id applied for when applying for the sonatype account. The address of the warehouse to be published here may be different for each user. The specific number depends on your own activation email (see the section "processing publishing results in sonatype" below).

In addition, we need to be in gradle Properties defines the information related to our account:

signing.keyId=secret key keyId
signing.password=secret key password
signing.secretKeyRingFile=Private key keyRingFile route

sonatypeUsername=sonatype account number
sonatypePassword=sonatype password

Step 4: publish

After the configuration is completed, publishing is relatively simple. Just select the publishing task under the module specified in the gradle task bar on the right side of the AS, and then select publish Maven Java publishing to Maven Repository:

Step 5: go to Sonatype to process the publishing results

In fact, the partition that each user publishes may be different. An accurate way to view it is that after you activate your account, you will receive an email indicating the location where your files are published,

Like mine https://s01.oss.sonatype.org Domain name, while other users may https://oss.sonatype.org/ Under the domain name, if I log in to other domain names with my registered account, I will report permission related errors. This is also a pit.

After logging in to your warehouse, click Staging Repositories on the left to see the file we just released.

Check our files and click Close. snoatype will verify the files we released. The verification takes about a minute. After the verification, click Release to finally Release our files.

Step 6: reference our library

After publishing, you can reference. The reference depends on the same way as other warehouses. It should be noted that you need to add the address of Maven Central's warehouse first:

repositories {
    //Recommendation: after the release is successful, the aar will be directly pulled from Maven central
    mavenCentral()
    //perhaps
    maven {url "https://s01.oss.sonatype.org/content/groups/public"}
    //perhaps
    maven {url "https://s01.oss.sonatype.org/content/repositories/releases"}
}

Step 7: dealing with references

I found that most of the tutorials ended with the introduction above, but there is actually a very important step to solve.

It is not usually referenced by our api, compile, or other methods. When using Bintray Jcenter, it can automatically generate the dependencies in the pom file according to the dependencies of our project. But we need to solve this problem ourselves when publishing to Maven Central. If this problem is not solved, only the aar file published by ourselves will be referenced. This is obviously not possible.

By comparing various reference methods of Bintray JCenter, I wrote the following code to generate dependencies in pom:

withXml {
    def dependenciesNode = asNode().appendNode('dependencies')
    project.configurations.all { configuration ->
        def name = configuration.name
        if (name != "implementation" && name != "compile" && name != "api") {
            return
        }
        println(configuration)
        configuration.dependencies.each {
            println(it)
            if (it.name == "unspecified") {
                // Ignore unrecognized
                return
            }
            def dependencyNode = dependenciesNode.appendNode('dependency')
            dependencyNode.appendNode('groupId', it.group)
            dependencyNode.appendNode('artifactId', it.name)
            dependencyNode.appendNode('version', it.version)
            if (name == "api" || name == "compile") {
                dependencyNode.appendNode("scope", "compile")
            } else { // implementation
                dependencyNode.appendNode("scope", "runtime")
            }
        }
    }
}

Here, we will first judge the reference mode, then select the corresponding scope according to the reference mode, and handle some exceptions at the same time.

Final release script

task androidSourcesJar(type: Jar) {
    archiveClassifier.set("sources")
    from android.sourceSets.main.java.source
    exclude "**/R.class"
    exclude "**/BuildConfig.class"
}

publishing {
    // Define what to publish
    publications {
        mavenJava(MavenPublication) {
            // group id, the dependent group id referenced after publishing
            groupId 'com.github.Shouheng88'
            // Dependent artifact id referenced after publishing
            artifactId 'sil'
            // Released version
            version '0.1.0'
            // Released arr files and source files
            artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
            artifact androidSourcesJar
            pom {
                // Component name, which can be customized
                name = 'uix-common'
                // Component description
                description = 'Android UIX'
                // Component home page
                url = 'https://github.com/Shouheng88/Android-uix'
                // License name and address
                licenses {
                    license {
                        name = 'The Apache License, Version 2.0'
                        url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }
                // Developer Information
                developers {
                    developer {
                        name = 'ShouHeng'
                        email = 'shouheng2015@gmail.com'
                    }
                }
                // Version control warehouse address
                scm {
                    url = 'https://github.com/Shouheng88/Android-uix'
                    connection = 'scm:git:github.com/Shouheng88/Android-uix.git'
                    developerConnection = 'scm:git:ssh://git@github.com/Shouheng88/Android-uix.git'
                }
                // Resolve dependencies
                withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')
                    project.configurations.all { configuration ->
                        def name = configuration.name
                        if (name != "implementation" && name != "compile" && name != "api") {
                            return
                        }
                        println(configuration)
                        configuration.dependencies.each {
                            println(it)
                            if (it.name == "unspecified") {
                                // Ignore unrecognized
                                return
                            }
                            def dependencyNode = dependenciesNode.appendNode('dependency')
                            dependencyNode.appendNode('groupId', it.group)
                            dependencyNode.appendNode('artifactId', it.name)
                            dependencyNode.appendNode('version', it.version)
                            if (name == "api" || name == "compile") {
                                dependencyNode.appendNode("scope", "compile")
                            } else { // implementation
                                dependencyNode.appendNode("scope", "runtime")
                            }
                        }
                    }
                }
            }
        }
    }
    // Define where to publish
    repositories {
        maven {
            // The location of the release. The SNAPSHOT and the final version are distinguished according to the released version
            def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
            def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                // This is where I was at issues sonatype. Org registered account
                username ossrhUsername
                password ossrhPassword
            }
        }
    }
}

signing {
    sign publishing.publications
}

summary

The above is a simple solution. The above operations can help us solve many problems in the publishing process. Of course, there is still room for optimization, such as dealing with project dependencies and other situations.

I hope this article is helpful to you. If you have any questions, please leave a message below.

Topics: Maven