Parce que la signature de codes et l'archivage par Xcode prennent du temps, sont ennuyeux et problématiques, j'ai toujours signé, archivé et expédié mon application macOS signée Developer ID en utilisant les outils de ligne de commande xcodebuild
, codesign
, etc. via mon propre script. La notarisation semble être une douleur majeure. Est-il possible d'ajouter la notarisation à mon script?
Oui. Malheureusement, le réponse officielle laisse quelques extrémités lâches, par exemple ceci friandise importante de Quinn "l'Eskimo" . Voici comment faire:
Décidez d'un nom pour votre "application" de notarisation des applications. J'utilise le nom de mon script d'expédition de produit, _SSYShipProduct.pl
_ car c'est "l'application" qui utilisera ce mot de passe. Nous désignerons le nom que vous composez comme votre-nom-notarié .
Accédez à https://appleid.Apple.com/account/manage , faites défiler jusqu'à Sécurité > Mot de passe spécifique à l'application et générez un mot de passe spécifique à l'application pour une application nommée votre-nom-notarié . Copiez le mot de passe qu'il vous donne. Nous appellerons cela mot de passe spécifique à l'application .
Exécutez cette commande pour ajouter le mot de passe que vous venez de créer à votre trousseau:
_security add-generic-password -a "your-Apple-ID-email" -w "app-specific-password" -s "your-notarizing-name"
_
Le paramètre _-s
_ est le nom que cet élément aura dans votre trousseau. Je pense que vous pourriez en fait utiliser un nom différent, mais dans mon esprit, il est logique d'utiliser _your-notarizing-name
_ ici aussi.
Vous pouvez vérifier que cela a fonctionné en recherchant dans l'application Keychain Access . Cependant, sachez que les nouveaux éléments ne sont pas répertoriés dans Keychain Access tant que vous ne l'avez pas quitté et relancé.
Si votre Apple ID est associé à plus d'une Apple équipe Developer Connection (comme si vous travaillez sous contrat), vous aurez besoin du itc_provider de l'équipe pour laquelle cette application doit être notariée.
Pour trouver le itc_provider de votre équipe, exécutez cette commande:
_/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u "your-Apple-ID-email" -p "app-specific-password"
_
Faites défiler jusqu'à la fin de la sortie imprimée par cette commande et regardez la table Liste des fournisseurs . Copiez le nom court de l'équipe souhaitée. Nous appellerons cela "développeur-équipe-fournisseur-itc".
Si vous signez des composants de votre application à l'aide de l'outil de ligne de commande _/usr/bin/codesign
_, chaque appel de codesign doit avoir le nouveau paramètre d'argument suivant, qui indique à codesign de signer avec le soi-disant runtime renforcé :
_ `--options runtime`
_
Inversement, si votre application est signée dans Xcode, vous devez définir le paramètre de build Runtime renforcé , disponible dans Xcode 10 ou version ultérieure, sur Oui dans tous les exécutables cibles des composants.
En dehors de cela, votre script devrait créer une version de votre application dans la configuration de la version et la signer, comme lors des jours de pré-notarisation.
Votre script doit ensuite archiver votre application dans un .Zip ou .dmg. Notez qu'il s'agit d'un fichier intermédiaire qui ne sera téléchargé que vers le service notaire Apple, non expédié.
Ensuite, votre script doit composer une valeur d'ID de bundle principal , qui sera l'identifiant de bundle de votre application avec _.Zip
_ ou _.dmg
_ ajouté. Exemple: votre-valeur-pbid = _com.mycompany.YourApp.Zip
_.
Dans ce qui suit, votre script utilisera altool
, qui est le nom d'Apple pour Application Loader Tool .
Votre script doit ensuite exécuter cette commande pour obtenir votre .Zip ou .dmg notarié:
_/usr/bin/xcrun altool --notarize-app --primary-bundle-id "your-pbid-value" --username "your-Apple-id-email" --password "@keychain:your-notarizing-name" -itc_provider "developer-team-itc-provider" --file /path/to/YourApp.Zip/or/YourApp.dmg --output-format "xml"
_
(Notez que, dans la commande ci-dessus, bizarrement, tous les noms d'argument sont précédés de deux tirets, sauf que _-itc_provider
_ est précédé d'un seul tiret. De plus, si le langage de script que vous utilisez interpole _@
_ caractères dans les chaînes , codez-le pour empêcher l'interpolation de _@keychain
_).
Au bout d'une minute environ, xcrun
se fermera et s'imprimera pour sortir du XML qui, si votre soumission a été acceptée (note: non approuvé pour l'instant), ressemblera à cet exemple:
_<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>notarization-upload</key>
<dict>
<key>RequestUUID</key>
<string>2ab59b26-19ec-4a30-84cf-6d2cb8d3c97e</string>
</dict>
<key>os-version</key>
<string>10.15.0</string>
<key>success-message</key>
<string>No errors uploading 'path/to/YourApp.Zip'.</string>
<key>tool-path</key>
<string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
<key>tool-version</key>
<string>1.1.1138</string>
</dict>
</plist>
_
Tout ce dont vous avez vraiment besoin, c'est de cette valeur RequestUUID
. Cependant, comme j'expédie souvent quatre applications, et parce que cela gâche ma journée lorsque mon script d'expédition échoue sans fournir d'informations d'erreur utiles, et parce que (voir ci-dessous) vous allez faire un autre appel qui renvoie également du XML intéressant, j'ai investi un certain temps ajouter à mon script un sous-programme qui prend deux paramètres, XML et un chemin de clé, et renvoie la valeur du XML à un chemin de clé donné. Dans le cas ci-dessus, j'appelle ce sous-programme pour obtenir le RequestUUID
, puis à nouveau pour obtenir le _success-message
_.
(Mon script est en Perl. Bien qu'il existe dans CPAN un module nommé XML :: Simple qui peut effectuer cette analyse en une ou deux lignes, il est marqué par le responsable comme n'étant pas pour donc pour éviter d'avoir à installer et à utiliser un analyseur XML réel , j'ai plutôt choisi d'utiliser PlistBuddy
comme suggéré dans le commentaire de @khuttun. Cela a été un peu douloureux aussi parce que, malheureusement, altool
n'a pas d'option pour écrire sa sortie dans un fichier, et PlistBuddy
n'est pas documenté pour accepter stdin. Donc mon sous-programme écrit la stdout à partir de altool
dans un fichier temporaire, puis passe le chemin de ce fichier temporaire à PlistBuddy. C'est dégoûtant, mais ça marche.)
À ce stade, je recommande que votre script supprime le fichier _.Zip
_ ou _.dmg
_ qu'il a téléchargé. Raison: ce fichier a été archivé à partir d'un produit qui n'a pas encore votre ticket de notarisation agrafé . À la fin de votre script, vous allez créer un nouveau _.Zip
_ ou _.dmg
_ à partir d'une application modifiée qui a le ticket. La suppression du fichier vous empêche immédiatement d'expédier par erreur une application non agrafée.
Votre script peut alors commencer à harceler le serveur d'Apple pour vos résultats finaux, en exécutant cette commande en boucle avec un peu de sommeil:
`/ usr/bin/xcrun altool --notarization-info --username" your-Apple-id-email "--password" @keychain: your-notarizing-name "--output-format" xml "
Si votre script exécute cette commande immédiatement, il sera renvoyé dans stdout du xml qui ressemblera à cet exemple:
_<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>notarization-info</key>
<dict>
<key>Date</key>
<date>2019-08-07T01:17:37Z</date>
<key>RequestUUID</key>
<string>4ba71353-9d99-4b52-b579-37f384717130</string>
<key>Status</key>
<string>in progress</string>
</dict>
<key>os-version</key>
<string>10.15.0</string>
<key>success-message</key>
<string>No errors getting notarization info.</string>
<key>tool-path</key>
<string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
<key>tool-version</key>
<string>1.1.1138</string>
</dict>
</plist>
_
Le chemin d'accès clé principal est _notarization-info:Status
_, dont la valeur _in progress
_ signifie que Apple travaille toujours sur votre soumission. Après quelques minutes en général (Apple dit que "devrait être moins d'une heure", mais j'ai connu des heures allant jusqu'à trois heures et demie les après-midi de vacances aux États-Unis de 2019-juil-04), altool
va revenir à votre script un xml différent dans stdout, quelque chose comme ceci:
_<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>notarization-info</key>
<dict>
<key>Date</key>
<date>2019-08-06T23:28:25Z</date>
<key>LogFileURL</key>
<string>https://osxapps-ssl.iTunes.Apple.com/iTunes-assets/Enigma113/v4/f6/09/be/f609bee3-b031-323a-0987-d1f620a78758/developer_log.json?accessKey=1565410613_1722173034418364591_TvycjBAzd6FRTYGKZEFU6EwDfsws8Wa1MV%2FYnTiJ1zyOZamc%2FoeO5RMeIzZN669ZQJgO2Q4W48ipKNFO%2BQGuq%2FITXN8MQAetbNe90w9ogzqXbrzTHg%2FgYK89yvEFmiiRxhaVlZqLI93NBpY0hwBqXv2bvvlg%2FRCc%2BVaCNRJ%2BrnE%3D</string>
<key>RequestUUID</key>
<string>07fc3745-b0ff-4d1a-9b15-37f384717130</string>
<key>Status</key>
<string>success</string>
<key>Status Code</key>
<integer>0</integer>
<key>Status Message</key>
<string>Package Approved</string>
</dict>
<key>os-version</key>
<string>10.15.0</string>
<key>success-message</key>
<string>No errors getting notarization info.</string>
<key>tool-path</key>
<string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
<key>tool-version</key>
<string>1.1.1138</string>
</dict>
</plist>
_
Après une rétro-ingénierie, vous voyez que, dans chaque itération de boucle, votre script doit analyser le XML et sortir de la boucle chaque fois que la valeur de Status
est autre que _in progress
_, ou si vous préférez, lorsque LogFileURL
est défini. Ou si vous préférez les déclencheurs d'e-mails, votre script peut rechercher un e-mail de Apple avec une ligne d'objet Vous pouvez maintenant distribuer votre logiciel Mac. .
MISE À JOUR 2019-11-02
Après avoir eu des problèmes avec cette étape dans mes deux dernières expéditions, et encore aujourd'hui, j'ai maintenant confirmé un bug dans le service notarial d'Apple. Le bogue est que la commande _altool --notarization-info
_ échouera pendant 1 à 5 heures, renvoyant des codes de sortie différents de zéro et dans stdout un code d'erreur 1519 "Impossible de trouver le RequestUUID", comme dans l'exemple suivant stdout:
_<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.Apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>os-version</key>
<string>10.15.1</string>
<key>product-errors</key>
<array>
<dict>
<key>code</key>
<integer>1519</integer>
<key>message</key>
<string>Could not find the RequestUUID.</string>
<key>userInfo</key>
<dict>
<key>NSLocalizedDescription</key>
<string>Could not find the RequestUUID.</string>
<key>NSLocalizedFailureReason</key>
<string>Apple Services operation failed.</string>
<key>NSLocalizedRecoverySuggestion</key>
<string>Could not find the RequestUUID.</string>
</dict>
</dict>
</array>
<key>tool-path</key>
<string>/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework</string>
<key>tool-version</key>
<string>4.00.1181</string>
</dict>
</plist>
_
Il s'agit d'un bogue car, bien sûr, mon script a soumis l'UUID de demande qu'il vient de recevoir de Apple Service notarial, Apple devrait être en mesure de le trouver et, en outre, lorsque j'ai continué à envoyer la commande manuellement, après environ 2 heures, soudainement, la commande a renvoyé Success
et a continué de revenir Success
avec les commandes suivantes, et j'ai reçu l'e-mail Success d'Apple. Ce retard s'est produit aujourd'hui avec 7 bonnes UUID de demande différentes, la plus longue étant de 5 heures. Il se peut, à ce moment, qu'il y ait un délai de 1 à 5 heures entre Apple le service notaire créant et vous envoyant un UUID de demande, et qu'il apparaisse dans la base de données que Apple le service notaire utilise pour répondre à _notarization-info
_ requêtes, vous obtenez donc cette fausse erreur. Très triste.
Comme je n'ai aucun contrôle sur le moment où [Apple affecte des personnes pour corriger les bogues, j'ai modifié cette étape de mon script pour analyser la réponse de Apple et mourir uniquement si la commande renvoie un état de sortie différent de zéro et le code
de la première (index = 0) _product-errors
_ tableau n'est pas 1519. Si vous utilisez PlistBuddy pour analyser XML tel que je suis, le le chemin d'accès clé pour ce code doit être _product-errors:0:code
_. La boucle de mon script s'imprime chaque fois que l'erreur 1519 est reçue, donc je peux voir ce qui se passe, et bien sûr, j'ai modifié sa condition while
pour ne pas quitter si le code d'erreur est 1519.
Après avoir corrigé mon script, j'avais plusieurs applications à expédier. Apple Le service notarial a bien traité la première: aucune erreur 1519 et succès après environ deux minutes. Le suivant, cependant, avait besoin de cette nouvelle fonctionnalité de mon script. À l'heure 09:54 (HH: mm), mon script a reçu l'UUID de demande d'Apple. 20 secondes plus tard, il a envoyé la première requête _altool --notarization-info
_. La réponse a été une fausse erreur 1519. Les requêtes suivantes ont également renvoyé de fausses erreurs 1519, pendant près de 3 heures, jusqu'à 12 h 44. Puis, à 12 h 45, tout à coup, il a reçu une réponse _in progress
_. Après 5 autres réponses _in progress
_, à 12 h 47, enfin, Succès .
Une dernière chose avant de quitter cette rubrique: une heure après que cette demande a réussi sans erreur 1519, une demande antérieure d'il y a une heure a soudainement commencé à renvoyer _in progress
_ puis quelques minutes plus tard, Succès . Conclusion: les UUID de demande qui sont déviés dans le bourbier de l'erreur 1519 ne sont pas mis en file d'attente FIFO avec des UUID de demande ultérieurs qui pourraient, par hasard, éviter le détour de l'erreur 1519. Ainsi, une meilleure solution de contournement pourrait être d'abandonner un UUID de demande après avoir reçu une réponse supplémentaire à l'Erreur 1519 et de recommencer en téléchargeant l'application sur Apple Notary Service et en obtenant un autre UUID de demande qui, vous l'espérez, fonctionnera mieux. Bien sûr, vous recevrez de nombreux e-mails au cours des prochaines heures, car tous les UUID de demande que vous avez abandonnés réussissent finalement.
En tout cas, maintenant, passons à l'étape suivante du script…
Votre script doit analyser la valeur de LogFileURL
pour pouvoir consulter le journal, car même si la notarisation réussit, le fichier journal créé par Apple peut contenir des avertissements. Pour obtenir le fichier journal, votre script doit, bien sûr,
_curl <LogFileURL-Value>
_
Le fichier journal est apparemment JSON. Les avertissements ou les erreurs sont présentés sous forme de tableau, qui correspond à la valeur de la clé issues
. Votre script doit donc analyser cette sortie curl
avec un analyseur JSON et si la valeur de la clé issues
est un null JSON ou un tableau vide, continuez la livraison.
Cette étape est assez simple…
_xcrun stapler staple /path/to/YourApp.app
_
L'exécution de cette commande ajoutera au package de votre application un nouveau fichier: _YourApp.app/Contents/CodeResources
_. Il s'agit apparemment de votre ticket de notarisation . Notez que ce fichier est en plus du fichier _YourApp.app/Contents/_CodeSignature/CodeResources
_ qui est toujours là et contient la signature de code, la même que dans les jours de pré-notarisation.
Mais il existe un meilleur moyen de vérifier que votre application dispose désormais d'un bon ticket. Votre script doit maintenant exécuter (ou réexécuter) une vérification Gatekeeper:
_spctl -a -v /path/to/YourApp.app
_
Le résultat, dans stderr, devrait être,
_/path/to/YourApp.app: accepted
source=Notarized Developer ID
_
qui est le même résultat que la pré-notarisation, à l'exception de l'insertion de notarié . Des scripts astucieux analyseront ce stderr et abandonneront l'expédition si les mots ci-dessus ne sont pas détectés.
Maintenant que le ticket a été ajouté, votre script peut à nouveau compresser ou dmg votre .app, mais cette fois, expédiez-le.
Voici un script de notarisation et d'agrafage réutilisable et sous licence libre pour les versions automatisées:
https://github.com/rednoah/notarize-app/blob/master/notarize-app
Il fonctionnera et attendra et ne sortira qu'une fois que tout sera fait:
altool --notarize-app
altool --notarization-info
périodiquement jusqu'à la fin de la notarisationstapler staple
Voici un exemple de notariseur automatique que j'ai écrit pour RawTherapee. Tout d'abord, nous notarions l'application:
Ensuite, nous notarions le dmg:
Les informations d'identification du notaire sont transmises via la directive de commande cmake
-DNOTARY="--username [email protected] --password abcd-efgh-ijkl-mnop"