天天看點

macOS 使用 Sparkle 檢查軟體自更新

1、前言

其實,本篇文章應該是上一年就打算寫的,結果呢,最近才有時間整理。開發 macOS 軟體也有一段時間,對于軟體更新,之前是自己手動編寫增加 API 接口來提示是否有新版本,但一直覺得不智能,界面也不友好,而且下載下傳的是壓縮包,需要解壓後自動手動替換 App,甚是痛苦。是以,看了很多開源項目,看到了一個 macOS 專用的更新庫

Sparkle

, 然而現有網上的教程,已經非常陳舊,花了點時間才悟,是以,寫一個總結吧。另外,也有其它的更新庫,大家需要可以自行了解,以主流庫為主,維護更好,這也是項目選型考慮的條件之一,也許是強者更強,好像

劣币驅逐良币現象

在開源界沒有發生過吧~

2、Sparkle

Sparkle的原理是根據提前配置好的xml檔案位址,每次啟動後解析xml,看看有沒有比目前版本新的資料,有的話提示更新。

xml檔案可以存在任何可以通路xml中繼資料的伺服器,包括 GitHub 倉庫。

macOS 使用 Sparkle 檢查軟體自更新

2.1 使用 Cocopods 在項目中內建:

pod 'Sparkle'           

也可以通過下載下傳源代碼進行內建(

https://github.com/sparkle-project/Sparkle

)。

2.2 配置 storyboard 更新 action

  1. 打開 Main.storyboard(如果是很舊的項目則為 MainMenu.xib)
  2. 選擇 View -> Libraries -> Show Library (快捷鍵為

    shift + command + L

  3. 在搜尋欄中搜尋 Object 并将 Object 拖入左側跟

    App Delegate

    同級層
  4. 選中剛添加的 Object 對象
  5. 選擇 View -> Inspectors -> Show Identity Inspector(快捷鍵為

    option + command + 3

  6. 修改 Custom Class 為

    SUUpdater

  7. 如果需要,可以添加一個檢查更新的菜單項,設定它的 target 為剛才的

    SUUpdater

    執行個體,action 為

    checkForUpdates:

macOS 使用 Sparkle 檢查軟體自更新
macOS 使用 Sparkle 檢查軟體自更新
macOS 使用 Sparkle 檢查軟體自更新

2.3 數字簽名

Sparkle

能夠下載下傳軟體并進行替換,是以為了保證安全,確定全程是軟體作者行為,給出了3點建議:

由于 Sparkle 正在将可執行代碼下載下傳到使用者的系統, 是以您必須非常小心安全性。為了讓 Sparkle 知道下載下傳的更新沒有損壞(修改), 并且來自您 (而不是惡意攻擊者), 我們建議:

1、通過 HTTPS 提供更新。

除非你遵守 Apple 的應用傳輸安全要求, 否則你的應用不會在 macos 10.11 或更高版本上 HTTP 請求将被系統拒絕。

2、通過 Apple 的開發人員 ID 程式對應用程式進行簽名。

3、使用 Sparkle 的 EdDSA (ed25519) 簽名對已釋出的更新存檔進行簽名。

是以,建議使用

Sparkle

的簽名認證機制,保證更新的合法性。 需要注意的是,

Sparkle

v1.21 之後使用全新的 EdDSA (ed25519) 簽名,而之前的舊版本使用 使用DAS SHA-1 數字簽名,則是另一種配置方式。

Sparkle

v1.21 以上配置:

首先,輕按兩下運作

Sparkle/bin/generate_keys

指令工具,會自動打開終端應用,顯示:

~ /Users/HTC/Downloads/Sparkle-1.21.3/bin/generate_keys ; exit;
This tool uses macOS Keychain to store the Sparkle private key.
If the Keychain prompts you for permission, please allow it.
OK! Read the existing key saved in the Keychain.

In your app's Info.plist set SUPublicEDKey to:
c6KSLEMfs7YqD5M0FZ8McEUi1x9gGdbXSem2T+lCgjA=           

配置 SUPublicEDKey

注意,這個步驟隻要運作一次,然後記錄下運作的結果,在

Info.plist

增加一個key-value 鍵值對,

SUPublicEDKey

對應的公鑰(base64 編碼的字元串)。

注:這個步驟做了兩件事:

1、生成一個私鑰, 并将其儲存在登入鑰匙串中。您不需要對其執行任何操作, 但不要失去對 Mac 鑰匙串的通路權限。如果您丢失了它, 您可能無法發出任何新的更新!

2、列印您的公鑰到終端應用程式上顯示。

配置 SUFeedURL

Info.plist

添加

SUFeedURL

屬性字段,其值設定為将應用更新的 URL, 例如

https://xxx.com/appcast.xml

appcast.xml 内容:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>應用名稱</title>
        <description>Most recent changes with links to updates.</description>
        <language>en</language>
        <item>
            <title>Version 1.4.14</title>
            <sparkle:releaseNotesLink>
                http://xxx.com/release-note.html
            </sparkle:releaseNotesLink>
            <pubDate>Wed, 10 Apr 2019 19:58:11 +0000</pubDate>
            <enclosure
                url="https://xxx.com/app.zip"
                sparkle:shortVersionString="1.4.14"
                sparkle:version="2019.05.04"
                length="6605799"
                type="application/octet-stream"
                sparkle:edSignature="MEYCIQCQaUqxcrhhEABlWxk+1At5QSwty+Li8d6Sr3q6jJF1JgIhAOWGpIkYLwXC
                RFfaA8uz34Dy7CXCczpmSyCOQ5+rfOFL"
            />
            <sparkle:minimumSystemVersion>10.11</sparkle:minimumSystemVersion>
        </item>
    </channel>
</rss>           

releaseNotesLink

: 更新日志的說明網頁,最好是html

url

: zip壓縮包下載下傳地扯

length

: zip壓縮檔案大小(位元組)

edSignature

: ed簽名

生成簽名

可以使用

generate_appcast

工具進行應用強制轉換時, 将自動生成簽名。也可以手動生成簽名。

Sparkle/bin/sign_update path_to_your_update.zip           

示例:

~ /Users/HTC/Downloads/Sparkle-1.21.3/bin/sign_update /Users/HTC/Downloads/Sparkle-1.21.3.zip
sparkle:edSignature="j4Mq6yLPlTb1/lGxGiW6BRsYoWBvPkIKc+ACstG87FJJBtjm5StuC07eT2EU4mRVAB0c9Y7ib36lQI8Zft3rCQ==" length="17748993"           

生成的

edSignature

length

填寫到上面的

appcast.xml

這樣就可以啦,其中

appcast.xml

是需要能通過網絡通路,不然無法更新。當然,如果是企業内部使用,部署到内網的伺服器就可以。

還有很多配置,隻下載下傳不更新、多語言本地化、增量更新等,這裡就不說了,大家如果有特殊需要,可以自己看文檔配置啊

Publishing an update - Sparkle: open source software update framework for macOS

Sparkle

v1.21 之前舊版本的配置:

如果是 1.21 之前的

DSA

簽名的SDK,現在更新的SDK,已經放到了bin目錄的的下目錄

old_dsa_scripts

生成數字簽名

使用

generate_dsa_keys_macos_10.12_only

指令生成 dsa_priv.pem(私鑰)和dsa_pub.pem(公鑰)兩個檔案。其中私鑰千萬不能丢,否則将無法簽署更新包。

然後,把dsa_pub.pam添加到項目中。

配置公鑰

Info.plist

SUPublicDSAKeyFile

屬性字段,其值設定為

dsa_pub.pem

公鑰的檔案名。

配置更新資訊

Info.plist

SUFeedURL

https://xxx.com/appcast.xml

,下文有xml檔案内容說明,與上面 EdDSA 有一些差別。

更新版本簽名

把新版本生成的程式打包成zip。因為這個是更新包,是以我們要對更新包進行數字簽名。方法很簡單:

Sparkle/bin/old_dsa_scripts/sign_update path_to_your_update.zip ~/.ssh/dsa_priv.pem           

記錄下傳回的字元串,這就是更新包的簽名。使用填下到

appcast.xml

中。

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>應用名稱</title>
        <description>Most recent changes with links to updates.</description>
        <language>en</language>
        <item>
            <title>Version 1.4.14</title>
            <sparkle:releaseNotesLink>
                http://xxx.com/release-note.html
            </sparkle:releaseNotesLink>
            <pubDate>Wed, 10 Apr 2019 19:58:11 +0000</pubDate>
            <enclosure
                url="https://xxx.com/app.zip"
                sparkle:shortVersionString="1.4.14"
                sparkle:version="2019.05.04"
                length="6605799"
                type="application/octet-stream"
                sparkle:dsaSignature="MEYCIQCQaUqxcrhhEABlWxk+1At5QSwty+Li8d6Sr3q6jJF1JgIhAOWGpIkYLwXC
                RFfaA8uz34Dy7CXCczpmSyCOQ5+rfOFL"
            />
            <sparkle:minimumSystemVersion>10.11</sparkle:minimumSystemVersion>
        </item>
    </channel>
</rss>           

releaseNotesLink

url

length

dsaSignature

: 更新包的資料簽名

一些問題&坑點

  • web伺服器

    上面說明的

    http://xxx.comappcast.xml

    更新資訊檔案,還是

    http://xxx.com/release-note.html

    更新說明頁面,還是應用的zip檔案下載下傳連結,都是需要通過伺服器進行通路。

這裡比較簡單的方法,就是上傳到

GitHub

上,就以通路到檔案或連結。

如果是本地調試,也可以利用 macOS 自帶的

python

建立一個本地的檔案伺服器:

python -m SimpleHTTPServer
  或者 
  python -m http.server            
~ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...           

然後就可以通過

http://0.0.0.0:8000

就能通路電腦的所有文檔和檔案目錄。

  • HTTPS

macOS 10.11 起蘋果預設開啟 App Transport Security ,也就是應用隻能通路 HTTPS 的連結,HTTP 的預設不能通路。

建議當然是使用https,如果沒有能力部署,也可以在應用的

Info.plist

配置允許通路http:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>           
  • 版本号

    注意,版本号是

    shortVersionString

    ;不是

    version

    字段。但是這2個字段都配置了的話,2個都需要大于舊應用的對應版本号,否則,

    Sparkle

    認為沒有新版本。
  • AppStore版本

    如果是上架 AppStore,則不能使用

    Sparkle

    ,因為蘋果稽核禁止檢查更新和自動更新,需要更新,要求使用者使用 AppStore。
  • 編譯報錯
/Users/HTC/Desktop/SparkleDemo-macOS/Pods/Target Support Files/Pods-macOSDemo/Pods-macOSDemo-frameworks.sh: line 104: EXPANDED_CODE_SIGN_IDENTITY: unbound variable
Command PhaseScriptExecution failed with a nonzero exit code           

在Xcode菜單欄選擇

File

->

Workspace Setting

就會彈出一個界面,看出 Xcode10 是預設選中的最新的

New Build System(Default)

,在這個編譯系統的環境下,編譯腳本一直會報錯。把 build system 切換到

Legacy Build System

,使用舊的編譯系統就正常運作。懷疑是新的編譯系統,流程有變動,如果有問題,後續在深研。

總結

其實,官方文檔已經給出了很好的教程。這裡寫的原因:

其一是,官方的文檔比較舊,針對 Xcode10,一些操作已經發生了比較大的變化,對于新入門的蘋果開發者,可以比較懵。

其二,對于英文或者想最快的方式入門使用的同學,提供一個最簡潔的教程,節省大家的時間,對大家都好的事件,應該做!

其三,對于剛剛入門 macOS 軟體開發的同學,可能還不知道有這樣優秀的第三方更新軟體庫,是以,心若所誠,力行心從!

參考

  • 如有疑問,歡迎在評論區一起讨論!
  • 如有不正确的地方,歡迎指導!
注:本文首發于 iHTCboy's blog ,如若轉載,請注來源