Sparkleの更新が正しく動くかは、古いバージョンのアプリを起動して、実際に新しいバージョンへ更新して確認する。手順は次のとおりである。
- 古いバージョン(v1.0.0)のアプリをインストールして起動する
- 新しいバージョン(v1.0.1)をリリースする
- 古いバージョンのアプリで、更新を確認する
- 更新をインストールして、新しいバージョンで再起動することを確認する
実行例はSparkle 2.10.0、macOS 27.0.1のもの。画面はSparkleの英語のUIで、アプリのメニューは日本語である。リリースは、GitHub Actionsの自動化したワークフローから作成している。
古いバージョンのアプリを用意する
GitHub Releasesから、古いバージョンのzipをダウンロードして展開する。
$ gh release download v1.0.0 --repo [ユーザー名]/[リポジトリ名] --dir v1
$ ditto -x -k v1/[アプリ名]-1.0.0.zip v1/x
$ plutil -p v1/x/[アプリ名].app/Contents/Info.plist | grep -E 'ShortVersion|BundleVersion'
"CFBundleShortVersionString" => "1.0.0"
"CFBundleVersion" => "1"
アプリは、更新の際に書き換えられる。更新を確認する前に、書き込みできる場所へコピーしておく。
$ ditto v1/x/[アプリ名].app install/[アプリ名].app
$ open install/[アプリ名].app
更新を検出する
アプリが起動したら、アプリメニューの「Check for Updates…」を実行する。新しいバージョンがあれば、「Software Update」のウィンドウが表示される。

A new version of [アプリ名] is available!
[アプリ名] 1.0.1 is now available—you have 1.0.0. Would you like to download it now?
[Skip This Version] [Remind Me Later] [Install Update]
ウィンドウには、「Automatically download and install updates in the future」のチェックボックスも表示される。
メッセージの「1.0.1」と「1.0.0」は、sparkle:shortVersionStringの表示用のバージョンである。更新の判定には、ビルド番号のsparkle:versionが使われる。
参考: 【Sparkle】ビルド番号とバージョン番号を使い分ける
自動の更新確認はすぐには実行されない
Info.plistのSUEnableAutomaticChecksをtrueにしていても、アプリを起動した直後に、自動で更新が確認されるとは限らない。起動してから約50秒の間は、自動の確認は実行されず、SULastCheckTimeも記録されなかった。動作の確認には、メニューの「Check for Updates…」から手動で実行する。
更新をインストールする
「Install Update」を押すと、更新のダウンロードと署名の検証が始まる。完了すると、「Ready to Install」になる。

「Install and Relaunch」を押すと、アプリが新しいバージョンに置き換わり、再起動する。
更新後のアプリを確認する
再起動したアプリは、新しいバージョンになっている。
$ plutil -p install/[アプリ名].app/Contents/Info.plist | grep -E 'ShortVersion|BundleVersion'
"CFBundleShortVersionString" => "1.0.1"
"CFBundleVersion" => "2"
署名、staple、Gatekeeperの判定も、更新後のアプリで確認できる。
$ codesign --verify --deep --strict install/[アプリ名].app
$ xcrun stapler validate install/[アプリ名].app
The validate action worked!
$ spctl --assess --type execute -vv install/[アプリ名].app
install/[アプリ名].app: accepted
source=Notarized Developer ID
更新の確認の記録は、アプリの設定ファイルに保存される。SULastCheckTimeが、最後に更新を確認した日時である。
$ plutil -p ~/Library/Preferences/[Bundle ID].plist
{
"SUHasLaunchedBefore" => true
"SULastCheckTime" => [最後に確認した日時(UTC)]
}
更新の直後は、defaults read [Bundle ID]が、この値を返さない場合があった。設定ファイルの内容は、plutil -pで直接確認する。
更新が検出されないとき、失敗するときの切り分け
更新が検出されない、または失敗する場合は、次の順に確認する。
- feedとzipが取得できるか(URL、404、リダイレクト、反映の遅延)
- ビルド番号(
sparkle:version)が、インストール済みのアプリよりも大きいか sparkle:minimumSystemVersionが、使っているmacOSよりも高くないか- 署名が正しいか(
SUPublicEDKeyと、署名に使った秘密鍵の組み合わせ)
切り分けの環境を用意する
appcast.xmlの内容を変えて、Sparkleの反応を確認できる。ローカルでHTTPサーバーを起動し、アプリのSUFeedURLを、そのサーバーに向ける。
feedのURLは、Info.plistのSUFeedURLで決まる。defaults write [Bundle ID] SUFeedURL ...でアプリの設定を書き換えても、feedのURLは変わらない。検証用のアプリのコピーでは、Info.plistを書き換え、署名し直す。
$ plutil -replace SUFeedURL -string "http://localhost:8765/appcast.xml" [アプリ名].app/Contents/Info.plist
$ codesign -f -s [SHA-1ハッシュ] --options runtime --timestamp=none [アプリ名].app
$ python3 -m http.server 8765 --directory www --bind 127.0.0.1
アプリを起動して、「Check for Updates…」を実行したとき、HTTPサーバーのログに、GET /appcast.xmlが記録されていれば、アプリはサーバーに接続している。リクエストが記録されていない場合は、feedのURLが書き換わっていない。
Sparkleの表示と原因
appcast.xmlの内容を変えたときの、Sparkleの表示は次のとおりである。
| appcast.xmlの状態 | Sparkleの表示 |
|---|---|
| 新しいバージョンがある | A new version of [アプリ名] is available! |
sparkle:versionがインストール済みと同じ | You’re up to date! / [アプリ名] 1.0.0 is currently the newest version available. |
sparkle:minimumSystemVersionが高い | Your macOS version is too old / [アプリ名] 1.0.1 is available but your macOS version is too old to install it. At least macOS 99.0 is required. |
| feedが404 | Update Error! / An error occurred in retrieving update information. Please try again later. |
sparkle:edSignatureが一致しない、または属性がない | ダウンロード後に、Update Error! / The update is improperly signed and could not be validated. Please try again later or contact the app developer. |
sparkle:versionの比較は、表示用のバージョンではなく、ビルド番号で行われる。sparkle:shortVersionStringが新しくても、sparkle:versionが同じであれば、You’re up to date!になる。
署名のエラーは、feedの取得ではなく、zipをダウンロードした後に表示される。署名が一致しない場合と、署名の属性がない場合は、同じメッセージである。
署名の確認には、sign_update --verifyが使える。
参考: 【Sparkle】EdDSA署名鍵を生成して公開鍵をInfo.plistに設定する
$ sign_update --account [アカウント名] --verify [アプリ名]-1.0.1.zip "[sparkle:edSignatureの値]"
--accountを省略すると、既定のed25519の鍵が使われる。別のアカウント名で生成した鍵の署名は、検証に失敗する。署名の検証に失敗したときは、署名した鍵と、検証に使う鍵が一致しているかを確認する。
enclosureのlengthが実際のサイズと違っていても、署名が正しければ、検証は通り、「Ready to Install」まで進んだ。
メニューの操作を自動化する
動作確認を繰り返すときは、AppleScriptで、メニューやボタンの操作を自動化できる。
$ osascript -e 'tell application "System Events" to tell process "[アプリ名]" to click menu item "Check for Updates…" of menu 1 of menu bar item 2 of menu bar 1'
$ osascript -e 'tell application "System Events" to tell process "[アプリ名]" to click button "Install Update" of window "Software Update"'
ターミナルのアプリに、アクセシビリティの権限が必要になる場合がある。
