A Gradle Plugin for working with Apple's Notarytool Web API. Allows software files to be notarized as part of the gradle build script. Use of this plugin, doesn't depend on the operating system and so can be used on older versions of macOS, Windows and Linux.
Apple requires that all software applications for macOS need to be notarized, in order to give "even more
confidence in your macOS software", see
Notarizing macOS software before distribution.
Originally, applications were notarized using a command line tool called altool
. Apple has now switched to using a
new command line tool called notarytool
(
see TN3147: Migrating to the latest notarization tool),
and as of November 1, 2023 Apple's notary service no longer accepts uploads using altool
. The notarytool
utility
requires Xcode 13 and macOS 11.3 or later. This makes notarizing software applications on older versions of macOS a
challenge. In addition, the notarytool
utility is only available on macOS, so it can't be used on other Operating
Systems. To help with this, Apple supplies
the Notary API Web Service,
which allows cross-platform notarization using a REST API.
This plugin uses the Notary API Web API to notarize software applications and so it can be used with older versions of macOS, as well as other Operating Systems such as Windows and Linux. The plugin also allows seamless integration with an existing gradle build, so applications can be built and notarized in one process.
This project is in development and its usage and API may be unstable. It has been tested and can be considered as being beta.
This project adheres to Semantic Versioning 2.0.0.
This project is not currently accepting any pull requests. If you find a problem, or have a suggestion please log an issue.
The plugin in available from the Gradle Plugin Portal.
To use this plugin, add the following to your build script:
plugins {
id("ca.ewert-technologies.notarytoolgradle") version "0.2.0"
}
To be able to notarize an application for macOS, you need to have an Apple Developer account, with access to App Store Connect. In order to make calls to the Notary API, you first need to create an API Key, see: Creating API Keys for App Store Connect API for instructions. After creating an API key, you should have the following information:
Item | Description |
---|---|
Issuer ID | Your issuer ID from the API Keys page in App Store Connect |
Private Key ID | Your Private key ID from App Store Connect |
Private Key | The .p8 file downloaded when creating the API Key |
These items are used to generate a JSON Web Token (JWT), which is used for authentication when making calls to the Notary API (see Generating Tokens for API Requests for more information). Note: the JWT is generated for you automatically by this library.
In order to use the plugin, it must be configured with the Authentication information obtained as above. To configure the Authentication information, add the following configuration block to your gradle build script:
configure<NotaryToolGradlePluginExtension> {
val path: Path = Paths.get("path", "to", "privateKeyFile.p8")
privateKeyId.set("<Private Key ID>")
issuerId.set("<Issuer ID here>")
privateKeyFile.set(path)
}
NOTE: The privateKeyId and issuerId should not be stored directly in the build script as this could potentially expose private information. Use something like the gradle-credentials-plugin to secure this information.
If the configuration block has not been added the following error is displayed when applying the plugin:
Could not create task ':submissionHistory'.
Could not create task of type 'SubmissionHistoryTask'.
Cannot query the value of extension 'notarytool-gradle-extension' property 'issuerId' because it has no value available.
The plugin adds the following tasks to the build, grouped under notarytool
:
This task retrieves a list, from oldest to newest, of previous notarization submissions along with their status. The last 100 submissions are returned. For each item the submission id, status, uploaded date, and uploaded file are displayed.
To get help on the task use:
./gradlew -q help --task submissionHistory
which provides the following:
Detailed task information for submissionHistory
Path
:submissionHistory
Type
SubmissionHistoryTask (ca.ewert.notarytool.gradle.tasks.SubmissionHistoryTask)
Options
--rerun Causes the task to be re-run even if up-to-date.
Description
Retrieves a list of previous notarization submissions.
Group
notarytool
This task does not require any command-line options
Example, running
./gradlew submissionHistory
would produce the following sample output:
Submission ID Status Upload Date Uploaded File Name
a014d72f-1234-45ac-abcd-8f39b9241c58 Accepted Jun. 12, 2023, 12:27:13 p.m. PDT pwm_3.3.3.0_aarch64.dmg
b685647e-1234-4343-abcd-1c5786499827 Accepted Jun. 13, 2023, 2:32:58 p.m. PDT PWMinder.zip
c6da5f3b-1234-4197-abcd-c83bac3d2953 Accepted Jul. 13, 2023, 10:35:58 a.m. PDT pwm_3.3.3.0_aarch64.dmg
d653220d-1234-4682-abcd-9a4fe87ebbff Invalid Aug. 22, 2023, 10:43:45 a.m. PDT pwm_invalid_aarch64.dmg
aaf8606e-1234-4a44-abcd-4c11cb94249e Invalid Oct. 31, 2023, 3:26:38 p.m. PDT pwm_invalid_aarch64.dmg
bdd929bf-1234-4a8e-abcd-4d67d33e6d7f Invalid Oct. 31, 2023, 3:51:47 p.m. PDT pwm_invalid_aarch64.dmg
cc0e5bc0-1234-4d03-abcd-55959c31bad7 Invalid Oct. 31, 2023, 4:12:21 p.m. PDT pwm_invalid_aarch64.dmg
d8c05db7-1234-495c-abcd-f9647d16ffcd Invalid Nov. 1, 2023, 2:33:08 p.m. PDT pwm_invalid_aarch64.dmg
ecb300ed-1234-4ebc-abcd-84f07d054663 Accepted Nov. 1, 2023, 2:38:35 p.m. PDT pwm_good_aarch64.dmg
This task retrieves the status of a notarization submission. If the status is Accepted
or Invalid
it also provides
a link to download the associated submission log.
To get help on the task use:
./gradlew -q help --task submissionStatus
which provides the following:
Detailed task information for submissionStatus
Path
:submissionStatus
Type
SubmissionStatusTask (ca.ewert.notarytool.gradle.tasks.SubmissionStatusTask)
Options
--submissionId The identifier that you received after submitting the software.
--rerun Causes the task to be re-run even if up-to-date.
Description
Retrieves the status of a notarization submission.
Group
notarytool
The only mandatory option is --submissionId
, where the argument is the identifier for a previous submission.
Example, running:
./gradlew submissionStatus --submissionId b014d72f-17b6-45ac-abcd-8f39b9241c58
would produce the following sample output:
Starting task: submissionStatus
Status for submission id b014d72f-17b6-45ac-abcd-8f39b9241c58: Accepted
Submission Log: https://notary-artifacts-prod.s3.amazonaws.com/...
This task submits software to be notarized, and then repeatedly polls to check the status of the submission
until it is either Accepted
, Rejected
, or Invalid
. This polling can be disabled using no-poll
(see below).
To get help on the task use:
./gradlew -q help --task submitSoftware
which provides the following:
Detailed task information for submitSoftware
Path
:submitSoftware
Type
SubmitSoftwareTask (ca.ewert.notarytool.gradle.tasks.SubmitSoftwareTask)
Options
--fileLocation Location (path) of the file to be notarized.
--no-poll Disables option --poll
--poll Repeatedly poll for submission status until Accepted, Rejected or Invalid.
--rerun Causes the task to be re-run even if up-to-date.
Description
Submits software to be notarized.
Group
notarytool
The only required option is fileLocation
. This can be passed in from the command line, but can also be
set within the build script, which is likely the more common way to set it.
Running using --poll
will cause the tasks to poll for the status of submission after submitting the software. This
is the default behaviour (i.e. polling is enabled if --poll
is omitted).
The polling can be disabled by using --no-poll
(i.e. ./gradlew submitSoftware --no-poll
),
or by setting poll = false
within the build script.
Examples:
tasks.submitSoftware {
fileLocation = "/Path/to/uploadFile.dmg"
poll = true // Polling is enabled, the default value is true
}
tasks.submitSoftware {
fileLocation = "/Path/to/uploadFile.dmg"
poll = false // Polling is disabled
}
Note that the fileLocation
parameter is a String
. It would typically be set based on a value from a task that
produces the file to be notarized (typically a .dmg
or .zip
file), for example the jpackage
task.
As described above, after submitting the software to Apple to be notarized, it (optionally)
continues to check on the status of the submission.
It polls for the status every 15 seconds, until the status is either Accepted
, Rejected
or Invalid
. This typically takes less than 5 minutes, but can take longer. After 50 attempts, if the status is
still In Progress
, the task will end. You can then manually check the status of the submission
using the submissionStatus
task, passing in the submissionId
.
The following is a list of references that may be helpful when creating and releasing a software application for macOS.
- badass-jlink-plugin - Gradle plugin that using jlink and jpackage to produce a dmg file, for modular applications.
- badass-runtime-plugin - Gradle plugin that using jlink and jpackage to produce a dmg file, for non-modular applications.
- Infinitekind appbundler - Create a macOS app bundle (
.app
file), with an optional bundles jre - DMG Canvas - Application used to create disk images (i.e.
.dmg
files) - gradle-credentials-plugin - Allows you to encrypt and store credentials and other private information used within the build script.
While plugin was designed primarily with notarizing application developed using Java in mind, it can be used for notarizing any file, for example those developed with Electron, Unity, etc.
For any issues or suggestions please use github issues.
This project is licensed under the MIT License.