26

Xcode によるコード署名とアーカイブは時間がかかり、退屈で、問題があるため、私は常に自分のスクリプトを介してコマンドライン ツール などをxcodebuild使用して、Developer ID で署名された macOS アプリをコード署名し、アーカイブし、出荷してきました。codesign公証は大きな苦痛になりそうです。私のスクリプトに公証を追加することは可能ですか?

4

3 に答える 3

36

はい。残念ながら、公式の回答では、クインの「エスキモー」からのこの重要な情報など、いくつかの未解決の問題が残っています。方法は次のとおりです。

ワンタイムセットアップ

アプリ固有のパスワードを取得する

公証アプリの「アプリ」の名前を決めます。SSYShipProduct.plこれは、このパスワードを使用する「アプリ」であるため、製品出荷スクリプトの名前を使用します。あなたが作成した名前をyour-notarizing-nameと呼びます。

https://appleid.apple.com/account/manageを参照し、 Security > App-Specific Passwordまでスクロールして、 your-notarizing-name という名前アプリのApp-Specificパスワードを生成します。それがあなたに与えるパスワードをコピーします。これをapp-specific-passwordと呼びます。

アプリ固有のパスワードを macOS キーチェーンに追加する

次のコマンドを実行して、作成したばかりのパスワードをキーチェーンに追加します。

security add-generic-password -a "your-apple-ID-email" -w "app-specific-password" -s "your-notarizing-name"

パラメータは、この-sアイテムがキーチェーンに持つ名前です。実際には別の名前を使用できると思いますが、your-notarizing-nameここでも使用するのが理にかなっていると思います。

Keychain Accessアプリケーションで検索することで、それが機能したことを確認できます。ただし、キーチェーン アクセスを終了して再起動するまで、新しい項目はキーチェーン アクセスに表示されないことに注意してください。

たぶん、関連するitc-providerを取得します

Apple ID が複数の Apple Developer Connection チームに関連付けられている場合 (契約業務を行っている場合など)、このアプリを公証する必要があるチームのitc_providerが必要になります。

チームのitc_providerを見つけるには、次のコマンドを実行します。

/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u "your-apple-ID-email" -p "app-specific-password"

このコマンドによって出力された出力の最後までスクロールし、プロバイダー リストテーブルを確認します。目的のチームの短縮名をコピーします。これを「developer-team-itc-provider」と呼びます。

出荷ごとに (スクリプト可能!)

コマンド ライン ツールを使用してアプリのコンポーネントに署名する場合/usr/bin/codesign、codesign の呼び出しごとに次の新しい引数 parameter が必要です。これにより、いわゆる強化されたランタイムで署名するように codesign に指示されます。

 `--options runtime`

逆に、アプリが Xcode でサインインしている場合は、すべての実行可能コンポーネント ターゲットで、Xcode 10 以降で使用可能なBuild Setting Hardened runtimeをYesに設定する必要があります。

それ以外は、公証前の日と同じように、スクリプトはリリース構成でアプリのビルドを作成し、コード署名する必要があります。

Apple Notary サービスへのアップロード

次に、スクリプトでアプリを .zip または .dmg にアーカイブする必要があります。これは Apple Notary サービスにのみアップロードされる中間ファイルであり、出荷されないことに注意してください。

次に、スクリプトでプライマリ バンドル ID 値を構成する必要があります。これは、アプリのバンドル ID となる.zipか、.dmg追加されます。例: your-pbid-value = com.mycompany.YourApp.zip.

以下では、スクリプトで を使用します。これは、 Application Loader Toolaltoolに対する Apple の名前です。

次に、スクリプトで次のコマンドを実行して、.zip または .dmg の公証を取得する必要があります。

/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"

(上記のコマンドでは、奇妙なことに、すべての引数名の前にダッシュが 2 つ付いていることに注意してください。ただし、 の前にはダッシュ-itc_providerが 1 つしかありません。また、使用しているスクリプト言語が@文字列内の文字を補間する場合は、 の補間を防ぐようにコーディングして@keychainください)。

約1 分後xcrunに終了し、標準出力に XML を出力します。送信が承認された場合(注: まだ承認されていません)、次の例のようになります。

<?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>



そこから本当に必要なのはそのRequestUUID価値だけです。ただし、私は 4 つのアプリを頻繁に出荷しているため、出荷スクリプトが失敗して役立つエラー情報が提供されずに 1 日が台無しになるため、(以下を参照) 興味深い XML を返す別の呼び出しを行うことになるため、 XML とキー パスの 2 つのパラメータを受け取り、指定されたキー パスで XML の値を返すサブルーチンをスクリプトに追加します。上記の場合、このサブルーチンを呼び出して を取得しRequestUUID、もう一度 を取得しsuccess-messageます。

(私のスクリプトは Perl です。CPAN にはXML::Simpleという名前のモジュールがあり、この構文解析を 1 行または 2 行で実行できますが、メンテナーによって、新しい設計では使用しないとマークされています。実際のXML パーサーをインストールしてラングリングするには、代わりにPlistBuddy@khuttun のコメントで提案されているように使用することを選択しました 残念ながら、altool出力をファイルに書き込むオプションPlistBuddyがなく、文書化されていないため、これは少し苦痛でしたstdin を受け入れるため、私のサブルーチンは stdout をaltool一時ファイルに書き込み、その一時ファイルのパスを PlistBuddy に渡します.ちょっと嫌ですが、うまくいきます.)

ステープルされていない zip パッケージを削除する

この時点で、アップロードしたファイル.zipまたはファイルをスクリプトで削除することをお勧めします。理由: そのファイルは、公証.dmgチケットがまだ添付されていない製品からアーカイブされました。スクリプトの最後に、チケットを持つ新しいアプリまたは変更されたアプリから作成します。ファイルをすぐに削除すると、ステープルされていないアプリを誤って出荷するのを防ぐことができます。.zip.dmg

Apple の応答をループで待機する

スクリプトは、次のコマンドをスリープ状態でループで実行することにより、最終的な結果を得るために Apple のサーバーを悩ませ始めることができます。

`/usr/bin/xcrun altool --notarization-info --username "your-apple-id-email" --password "@keychain:your-notarizing-name" --output-format "xml"

スクリプトがこのコマンドをすぐに実行すると、次の例のような xml が stdout に返されます。

<!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>


そこにある重要なキー パスは ですnotarization-info:Status。この値in progressは、Apple がまだ提出物に取り組んでいることを意味します。通常、数分後 (Apple は「1 時間未満である必要があります」と言っていますが、2019 年 7 月 4 日の米国の休日の午後に最大 3 時間半の時間を経験しました)、altool別の xml がスクリプトに返されます。標準出力では、次のようになります。

<?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>


Statusリバース エンジニアリングを行った後、各ループ反復で、 の値が以外の場合in progress、または必要に応じてLogFileURLが定義されている場合は 常に、スクリプトが XML を解析し、ループから抜け出す必要があることがわかります。または、電子メール トリガーを使用する場合は、スクリプトで Apple からの件名の電子メールを検索できます。これで、Mac ソフトウェアを配布できます。.

更新 2019-11-02

過去数回の出荷でこの手順に問題がありましたが、今日もまた、Apple の Notary Service にバグがあることを確認しました。バグはaltool --notarization-info、次の標準出力の例のように、コマンドが 1 ~ 5 時間失敗し、ゼロ以外の終了コードが返され、標準出力にエラー コード 1519「RequestUUID が見つかりませんでした」が表示されることです。

<?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>


これはバグです。もちろん、私のスクリプトApple Notary Service から受け取ったばかりの Request UUID を送信したため、Appleはそれを見つけることができるはずです。さらに、コマンドを手動で送信し続けると、約 2 時間後に突然、コマンドが返され、その後のコマンドで返さSuccessれ続け、Apple から成功Successの電子メールを受け取りました。この遅延は、今日、7 つの異なる適切なリクエスト UUID で発生し、最長で 5 時間でした。おそらく現時点では、Apple Notary Service がリクエスト UUID を作成して送信してから、Apple Notary Service がリクエストに応答するために使用するデータベースに表示されるまでに 1 ~ 5 時間の遅延があるため、この誤ったエラーが発生します。とても悲しい。notarization-info

Apple がバグ修正担当者をいつ割り当てるかを制御できないため、スクリプトのこの段階を変更して、Apple からの応答を解析し、コマンドがゼロ以外の終了ステータスcode最初の (index=0)product-errors配列エントリの を返した場合にのみ終了するようにしました。は 1519 ではありません。私のように PlistBuddy を使用して XML を解析している場合、そのコードのキー パスはproduct-errors:0:code. 私のスクリプトのループは、エラー 1519 が受信されるたびに表示されるので、何が起こっているかを確認できます。もちろん、whileエラー コードが 1519 の場合は終了しないように条件を変更しました。

スクリプトを修正した後、出荷するアプリがいくつかありました。Apple Notary Service は最初のものを適切に処理しました。エラー 1519 はなく、約 2 分後に成功しました。ただし、次のスクリプトでは、スクリプトのこの新しい機能が必要でした。時刻 09:54 (HH:mm) に、スクリプトは Apple からリクエスト UUID を受け取りました。20 秒後、最初のaltool --notarization-infoクエリが送信されました。応答は偽のエラー 1519 でした。その後のクエリでも、12:44 までのほぼ 3 時間にわたって偽のエラー 1519 が返されました。すると、12時45分に突然in progress応答が返ってきました。さらに 5 回のin progress応答の後、12:47 に、最終的にSuccess .

このトピックを離れる前にもう 1 つ: そのリクエストがエラー 1519 なしで成功した 1 時間後、1 時間前からの以前のリクエストが突然返さin progressれ始め、数分後にSuccessが返されました。結論: エラー 1519 の泥沼に迂回されたリクエスト UUID は、後でエラー 1519 の迂回を回避する可能性のある後のリクエスト UUID でキューに入れられません。そのため、エラー 1519 の応答をもう 1 回受け取った後に Request UUID を破棄し、アプリを Apple Notary Service に再アップロードして、より適切に機能することを期待する別の Request UUID を取得することによって、最初からやり直すことをお勧めします。もちろん、破棄したすべてのリクエスト UUID が最終的に成功するため、次の数時間の間に多くの電子メールが届きます。

いずれにせよ、スクリプトの次のステップに進みましょう…</p>

Appleのログファイルを確認してください

LogFileURL公証が成功したとしても、Apple によって作成されたログ ファイルには警告が含まれている可能性があるため、スクリプトは の値を解析してログをチェックできるようにする必要があります。もちろん、スクリプトでログ ファイルを取得するには、

curl <LogFileURL-Value>

ログファイルは明らかに JSON です。警告またはエラーは、 key の値である配列として表示されますissues。そのため、スクリプトはそのcurl出力を JSON パーサーで解析する必要があり、キーの値がissuesJSON の null または空の配列である場合は、出荷を続行します。

チケットをアプリにホッチキス留めする

このステップはとても簡単です…</p>

xcrun stapler staple /path/to/YourApp.app

このコマンドを実行すると、アプリのパッケージに新しいファイルが追加されます: YourApp.app/Contents/CodeResources. これは明らかにあなたの公証チケットです。このファイルは、YourApp.app/Contents/_CodeSignature/CodeResources公証前の時代と同じように、まだそこにあり、コード署名を含むファイルに追加されることに注意してください。

チケットのステープルを確認する

ただし、アプリに有効なチケットがあることを確認するためのより良い方法があります。スクリプトは Gatekeeper チェックを実行 (または再実行) する必要があります。

spctl -a -v /path/to/YourApp.app

stderr の結果は、次のようになります。

/path/to/YourApp.app: accepted
source=Notarized Developer ID

これは、 Notarizedの挿入を除いて、事前公証と同じ結果です。上記の単語が検出されない場合、賢明なスクリプトは stderr を解析し、出荷を中止します。

ジップアンドシップ

チケットが追加されたので、スクリプトで .app を再度圧縮または dmg できますが、今度はそれを出荷します。

于 2019-07-04T15:13:36.000 に答える