Apple Notary API client for Kotlin
APACHE-2.0 License
Apple Notary API client for Kotlin.
Notarize your macOS application from Kotlin code without dependency on Xcode nor macOS.
This library is available on Space Packages, you will need to add this Maven repository to your Gradle configuration:
import java.net.URI
repositories {
maven {
url = URI("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
}
}
Then add the dependency
implementation("org.jetbrains:apple-notary-api-kotlin-client:$version")
You will also need to provide a Ktor engine implementation, for example if you want to use the CIO engine:
implementation("io.ktor:ktor-client-cio:$ktorVersion")
You will first need to create an API Key for App Store Connect API, see Apple's Documentation . While doing this process make sure to save:
57246542-96fe-1a63-e053-0824d011072a
)2X9R4HXF34
).p8
file you can download from the API Keys page in App Store ConnectOnce you have these information, you can setup a credential object:
import com.jetbrains.notary.NotaryClientV2
import com.jetbrains.notary.auth.AppStoreConnectAPIKey
val credentials = AppStoreConnectAPIKey(
issuerId = "your-issuer-id",
keyId = "your-private-key-id",
privateKey = "your-private-key-file-content",
)
val client = NotaryClientV2(credentials)
// ... now you can use your client!
// For example retrieving your previous submissions:
val submissions = client.getPreviousSubmissions()
println(submissions)
apple-notary-api-kotlin-client
provides some extension functions that cover basic use cases of
Apple Notary API.
notarize
or notarizeBlocking
notarize
(or its blocking equivalent notarizeBlocking
) will cover the basic use case of "I want to notarize a file,
wait for the notarization to complete, get status and logs of the submission result when completed".
Under the hood, it will do the following:
ignoreServerError
and ignoreTimeoutExceptions
set to true
(set by default), polling will be hardened not to fail on usual false negative situationsimport com.jetbrains.notary.NotaryClientV2
import com.jetbrains.notary.auth.AppStoreConnectAPIKey
import kotlin.time.Duration.Companion.minutes
val credentials = AppStoreConnectAPIKey(
issuerId = "your-issuer-id",
keyId = "your-private-key-id",
privateKey = "your-private-key-file-content",
)
val notaryApiClient = NotaryClientV2(credentials)
val notarizationResult = notaryApiClient.notarizeBlocking(file, StatusPollingConfiguration(
timeout = 30.minutes,
pollingPeriod = 1.minutes,
ignoreServerError = true,
ignoreTimeoutExceptions = true,
))
val json = Json { prettyPrint = true }
println("Notarization logs:\n${json.encodeToString(notarizationResult.logs)}")
when (notarizationResult.status) {
SubmissionResponse.Status.ACCEPTED -> println("Notarization of $file successful")
SubmissionResponse.Status.IN_PROGRESS, null -> error("Timed out polling status of $file notarization submission")
SubmissionResponse.Status.INVALID, SubmissionResponse.Status.REJECTED -> error("Notarization of $file failed, see logs above")
}
ktor
client implementationYou are free to use your own ktor
client implementation and thus configuration.
We provide NotaryClientV2.defaultHttpClient
to allow your client configuration to extend the default one.
import com.jetbrains.notary.NotaryClientV2
import com.jetbrains.notary.auth.AppStoreConnectAPIKey
import kotlin.time.Duration.Companion.minutes
val credentials = AppStoreConnectAPIKey(
issuerId = "your-issuer-id",
keyId = "your-private-key-id",
privateKey = "your-private-key-file-content",
)
val myOwnClient = NotaryClientV2.defaultHttpClient.config { // keep all the default configuration
install(HttpRequestRetry) {
retryOnExceptionOrServerErrors(maxRetries = 10) // but increase the number of retry of the default configuration
constantDelay(millis = 1.minutes.inWholeMilliseconds) // but change the default exponential retry by a constant one
}
}
val notaryApiClient = NotaryClientV2(credentials, httpClient = myOwnClient)
This project is distributed under the Apache 2.0 license.
Special thanks to the people that built Rust library apple-codesign that inspired this work.