Mac App Store外で配布するmacOSアプリに、自動アップデートの機能を組み込むときは、Sparkleを使う。SparkleはmacOS向けのアップデート用フレームワークで、更新の確認、ダウンロード、署名の検証、インストールまでを担当する。
Swift Package Manager(SwiftPM)でSparkleを導入し、更新チェックを組み込む手順は、次の3つである。
- XcodeでSparkleのパッケージを追加する
- 更新チェックのコードを書く
- Info.plistに、更新情報の配信先(
SUFeedURL)を設定する
実行例はXcode 27.0、macOS 27.0.1、Sparkle 2.10.0のもの。アプリはSwiftUIで作成している。
- 前の記事: 【spctl】Gatekeeperの判定を配布前に確認する
- 親記事: GitHubを使い、macOSアプリを署名・公証・自動アップデート付きで公開する
- 次の記事: 【Sparkle】EdDSA署名鍵を生成して公開鍵をInfo.plistに設定する
Sparkleのパッケージを追加する
Xcodeのメニューから「File > Add Package Dependencies…」を開き、検索欄にSparkleのリポジトリのURLを入力する。
https://github.com/sparkle-project/Sparkle

「Dependency Rule」の既定は「Up to Next Major Version」で、現在の最新版(2.10.0)から次のメジャーバージョン(3.0.0)の手前までを指定する。「Add Package」を押すと、パッケージの取得が始まる。
取得が終わると、「Choose Package Products for Sparkle」が表示される。「Add to Target」の既定はNoneである。

Noneのままでは、アプリにSparkleがリンクされない。「Add to Target」を、アプリのターゲットに変更する。

「Add Package」を押すと、パッケージが追加される。Xcodeのナビゲーターに「Package Dependencies」のセクションが現れ、Sparkleのバージョンが表示される。

パッケージの追加で、次のファイルが変更される。
project.pbxprojに、パッケージの参照、プロダクトの依存、リンクの設定が追加される[プロジェクト名].xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolvedが作成され、解決されたバージョン(2.10.0)が記録される
Package.resolvedをgitで管理すると、チーム全員が同じバージョンのSparkleを使える。
更新チェックのコードを書く
更新チェックには、SPUStandardUpdaterControllerを使う。SparkleのUIを含む標準のコントローラである。
SwiftUIのアプリでは、Appのプロパティとしてコントローラを持ち、メニューから更新確認を呼び出す。
import SwiftUI
import Sparkle
@main
struct [アプリ名]App: App {
private let updaterController = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)
var body: some Scene {
WindowGroup {
ContentView()
}
.commands {
CommandGroup(after: .appInfo) {
Button("Check for Updates…") {
updaterController.checkForUpdates(nil)
}
}
}
}
}
startingUpdater: trueを指定すると、アプリの起動時にSparkleの更新機能が開始する。updaterDelegateとuserDriverDelegateは、動作や画面をカスタマイズするときに使う。今回はnilにしている。
CommandGroup(after: .appInfo)で、アプリメニューの「About」の下に「Check for Updates…」を追加している。メニューから実行すると、checkForUpdates(nil)で更新の確認が始まる。
更新の確認中にメニューを無効にしたい場合は、SPUUpdaterのcanCheckForUpdatesを使う。このコードでは、省略している。
このコードは、Xcode 27.0でそのままビルドできる。
Info.plistに配信先を設定する
Sparkleは、Info.plistのSUFeedURLから、更新情報(appcast)の取得先を読み取る。あわせて、自動で更新を確認するかをSUEnableAutomaticChecksで指定する。
| キー | 値 |
|---|---|
SUFeedURL | appcastのURL |
SUEnableAutomaticChecks | trueにすると、自動で更新を確認する |
INFOPLIST_KEYでは設定できない
XcodeのプロジェクトがGENERATE_INFOPLIST_FILE = YES(Info.plistを自動生成する設定)のとき、ビルド設定のINFOPLIST_KEY_SUFeedURLを設定しても、Info.plistに出力されない。SUFeedURLのような独自のキーは、INFOPLIST_KEY_の接頭辞では埋め込めない。
$ plutil -p [アプリ名].app/Contents/Info.plist | grep SU
INFOPLIST_KEY_SUFeedURLとINFOPLIST_KEY_SUEnableAutomaticChecksを設定してビルドしても、この出力は空になる。
Info.plistのファイルを追加する
独自のキーを出力するには、Info.plistのファイルを用意し、ビルド設定のINFOPLIST_FILEに指定する。GENERATE_INFOPLIST_FILE = YESのままでも、自動生成される内容と、用意したファイルの内容がマージされる。
プロジェクトの直下に、Info.plistを作成する。
<?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>SUFeedURL</key>
<string>https://github.com/[ユーザー名]/[リポジトリ名]/releases/latest/download/appcast.xml</string>
<key>SUEnableAutomaticChecks</key>
<true/>
</dict>
</plist>
アプリのターゲットの「Build Settings」で、INFOPLIST_FILE(Info.plist File)にInfo.plistを指定する。project.pbxprojでは、次の設定になる。
INFOPLIST_FILE = Info.plist;
ビルドしたアプリのInfo.plistに、SUFeedURLとSUEnableAutomaticChecksが出力されていることを確認する。
$ plutil -p [アプリ名].app/Contents/Info.plist | grep -E 'SU|BundleVersion|ShortVersion'
"CFBundleShortVersionString" => "1.0"
"CFBundleVersion" => "1"
"SUEnableAutomaticChecks" => true
"SUFeedURL" => "https://github.com/[ユーザー名]/[リポジトリ名]/releases/latest/download/appcast.xml"
SUFeedURLのappcastをreleases/latest/download/のURLで配信する方法は、GitHub Releasesの記事で解説する。更新の署名を検証するためのSUPublicEDKeyは、鍵の生成の記事で追加する。
参考: 【GitHub Releases】appcast.xmlを固定URLで配信する
参考: 【Sparkle】EdDSA署名鍵を生成して公開鍵をInfo.plistに設定する
ビルドしたアプリにSparkleが含まれる
ビルドしたアプリのContents/Frameworksには、Sparkle.frameworkが含まれる。
$ ls [アプリ名].app/Contents/Frameworks
Sparkle.framework
Sparkleのフレームワークの内部には、更新のダウンロードやインストールを担当するXPCサービス(Downloader.xpc、Installer.xpc)と、Updater.app、Autoupdateが含まれる。署名の検証では、これらも対象になる。
更新の確認を実行する
ビルドしたアプリを起動し、アプリメニューの「Check for Updates…」を実行すると、更新の確認が始まる。
SUEnableAutomaticChecksをtrueにしても、起動の直後に自動で確認されるとは限らない。起動してから約50秒の間は、自動の確認は実行されなかった。動作の確認には、メニューから実行する。
Sparkleのコマンドラインツールの場所
Sparkleのパッケージには、次のコマンドラインツールが含まれる。
| ツール | 用途 |
|---|---|
generate_keys | 更新の署名に使う鍵(EdDSA)を生成する |
generate_appcast | 配布するアーカイブからappcastを生成する |
sign_update | アーカイブに署名する、または署名を検証する |
BinaryDelta | 差分更新のファイルを作成・適用する |
これらは、XcodeがSparkleのパッケージを取得したときに、DerivedDataに展開される。Xcodeから開いたプロジェクトでは、次のパスにある。
~/Library/Developer/Xcode/DerivedData/[プロジェクト名]-[ハッシュ]/SourcePackages/artifacts/sparkle/Sparkle/bin/
xcodebuildに-derivedDataPathを指定してビルドした場合は、指定したディレクトリのSourcePackages/artifacts/sparkle/Sparkle/bin/に展開される。
$ ls [DerivedDataのパス]/SourcePackages/artifacts/sparkle/Sparkle/bin
BinaryDelta
generate_appcast
generate_keys
old_dsa_scripts
sign_update
SourcePackages/checkouts/Sparkle/にも、同じ名前のgenerate_keysなどが存在するが、これはディレクトリである。実行できるファイルは、artifacts/の下のbin/にある。
DerivedDataに複数のプロジェクトがある場合は、findで探す。
$ find ~/Library/Developer/Xcode/DerivedData -path '*Sparkle/bin/generate_keys'
App Sandboxを使う場合の注意
ここで検証したアプリは、App Sandboxを無効にしている。App Sandboxを有効にするアプリでは、Sparkleの動作に追加の設定が必要になる。設定の内容は、Sparkleの公式ドキュメントで確認する。
