There are requirements in order to be published on Maven Central. If your project is not open source, for example, you cannot be on Maven Central.
When you publish Android library files, you do it under a group id. You decide what this group id should be. You could pick your reverse domain name if you own a domain name: com.levibostian
. This method requires you verify you own the domain name. You can also just use a github domain name where all you have to do is verify your github repo and your groupId is something like io.github.yourusername
.
You must use Sonatype's Jira system in order to reserve your groupId. Here is a full example of the issue template you can use and the communication back and forth through the entire process. (Official docs on using Jira)
All artifacts uploaded to Maven Central must be signed with GPG to verify the files are actually from you. There are many steps to this. Let's get into it.
- Create a new master GPG key pair if you do not have one already.
$> gpg2 --full-gen-key
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Levi Bostian
Email address: [email protected]
Comment:
You selected this USER-ID:
"Customer.io Android <[email protected]>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
The command will ask you to enter a passphrase for the key. This is a password to protect your master secret key for extra protection. Use a passphrase!
I like to generate my password with the command openssl rand 60 | openssl base64 -A
. Save this passphrase in a safe place.
- It's recommended that you use subkeys for signing the artifacts. Subkeys are easier to manage in case there is an issue and your master key leaks.
First, we need to get the ID for our master private key. gpg --list-secret-keys --keyid-format long
and you will see:
sec rsa4096/XXXXXXXXXXXXXXXX 2021-05-03 [SC]
woefjweofjwoiwjoiwjfoiwejiowejfowiefjwoifjweoif
uid [ultimate] Your Name <[email protected]>
ssb rsa4096/YYYYYYYYYYYYYYYY 2021-05-03 [E]
The XXXXXXXXXXXXXXXX
is the ID we are looking for.
Now, we are going to edit the master private key. This will put us into the gpg program where we will use the command addkey
which is the command to add a subkey.
$ gpg --edit-key XXXXXXXXXXXXXXXX
gpg (GnuPG/MacGPG2) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
...
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(14) Existing key from card
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
...
gpg> save
Now, when you run gpg --list-secret-keys --keyid-format long
again, you should see a new subkey entry:
ssb rsa4096/EEEEEEEEEEEE 2021-06-14 [S]
[S]
is what we are looking for. That means it's a subkey used for signing which is what we need.
- Next, we need to send our keys to some keyservers so that others can verify something is signed by us.
$> gpg --keyserver pgp.mit.edu --send-key XXXXXXXXXXXXXXXX
$> gpg --keyserver keyserver.ubuntu.com --send-key XXXXXXXXXXXXXXXX
$> gpg --keyserver keys.openpgp.org --send-key XXXXXXXXXXXXXXXX
There are many keyservers out there. We are sending the key to a few popular ones above.
- Now, we need to create a revoke certificate. This certificate is used if your master key gets compromised or you forget your GPG passphrase and you need to notify the public to no longer trust a public key and you can then generate a new master key combo.
gpg --output revoke.asc --gen-revoke XXXXXXXXXXXXXXXX
Save this certificate file in a safe place not to the public.
- All done with the keys. Now it's time to do Maven specific work for signing. We will use the Maven
signing
plugin to sign. The files in this project already include what you need to do signing.
Let's look at this code in publish.gradle
file:
// ORG_GRADLE_PROJECT_signingKeyId
// ORG_GRADLE_PROJECT_signingKey
// ORG_GRADLE_PROJECT_signingPassword
useInMemoryPgpKeys(findProperty("signingKeyId"), findProperty("signingKey"), findProperty("signingPassword"))
This is telling the signing
plugin what key to use for signing. This is also a CI safe way to sign because we are using environment variables. That means we need to set environment variables on our system. Let's do that:
ORG_GRADLE_PROJECT_signingKeyId
- Thesigning
plugin says "The public key ID (The last 8 symbols of the keyId. You can use gpg -K to get it)." The important part there is the last 8 characters of the keyid. Use commandgpg --list-secret-keys --keyid-format long
and the last 8 characters of the [S] subkey's keyId is the value of this environment variable. So if the key iswoijeyrinvnno22o2n
, you will setnno22o2n
as the value on your CI server.ORG_GRADLE_PROJECT_signingKey
- This is the secret subkey in armor format. On your machine, rungpg --export-secret-subkeys --armor -o /tmp/subkeys.key XXXXXXXXXXXXXXXX
. You will enter the passphrase for your master key and then your subkeys will be generated to the output file. Now, you can runcat /tmp/subkeys.key
to get the contents of this environment variable. Note: If you don't want to sign with subkeys but instead master key, you would use--export-secret-keys
instead of--export-secret-subkeys
for the above command but everything else stays the same with the command.ORG_GRADLE_PROJECT_signingPassword
- this is your master key passphrase.
Great. Now you're ready to deploy your library to the Sonatype nexus servers. The publish.gradle
file is setup with a release repository and a snapshot repository. Snapshots are only used when the version of your library ends with SNAPSHOT
in the name (example 0.1.0-SNAPSHOT
or main-SNAPSHOT
).
You will need to set the environment variables GRADLE_PUBLISH_USERNAME
and GRADLE_PUBLISH_PASSWORD
which are the Jira username and password that you created in the steps above.
Directions here are from the official doc. You build and upload your library by using the command MODULE_VERSION=0.1.1-alpha ./gradlew :wendy:uploadArchives
where wendy
is the name of your module you want to deploy and MODULE_VERSION
is the version name of the release. Run this command now to make your first deployment.
After success, you will now login to the nexus repository with your sonatype jira username/password. Now, go to the Staging Repositories
tab on the left side. You should see your artifact there!
The rest of this section, I'll guide you with the official docs. Read the remaining sections of the release documentation to get your artifact tested and then uploaded.
Once you have "Released" your artifact, it's time to enable Maven Central sync. You do this by commenting on your Jira ticket that you made about your artifact. Sync should be enabled after that. When the Jira ticket says that sync is enabled for your artifact, you can find your artifact here (Maven central search engines have a few hour delays so this is the best place to see if sync is enabled).