1、前言
其实,本篇文章应该是上一年就打算写的,结果呢,最近才有时间整理。开发 macOS 软件也有一段时间,对于软件更新,之前是自己手动编写增加 API 接口来提示是否有新版本,但一直觉得不智能,界面也不友好,而且下载的是压缩包,需要解压后自动手动替换 App,甚是痛苦。所以,看了很多开源项目,看到了一个 macOS 专用的更新库 Sparkle
, 然而现有网上的教程,已经非常陈旧,花了点时间才悟,所以,写一个总结吧。另外,也有其它的更新库,大家需要可以自行了解,以主流库为主,维护更好,这也是项目选型考虑的条件之一,也许是强者更强,好像劣币驱逐良币现象
在开源界没有发生过吧~
2、Sparkle
Sparkle的原理是根据提前配置好的xml文件地址,每次启动后解析xml,看看有没有比当前版本新的数据,有的话提示更新。
xml文件可以存在任何可以访问xml元数据的服务器,包括 GitHub 仓库。
2.1 使用 Cocopods 在项目中集成:
1 | pod 'Sparkle' |
也可以通过下载源代码进行集成(https://github.com/sparkle-project/Sparkle)。
2.2 配置 storyboard 更新 action
- 打开 Main.storyboard(如果是很旧的项目则为 MainMenu.xib)
- 选择 View -> Libraries -> Show Library (快捷键为
shift + command + L
) - 在搜索栏中搜索 Object 并将 Object 拖入左侧跟
App Delegate
同级层 - 选中刚添加的 Object 对象
- 选择 View -> Inspectors -> Show Identity Inspector(快捷键为
option + command + 3
) - 修改 Custom Class 为
SUUpdater
- 如果需要,可以添加一个检查更新的菜单项,设置它的 target 为刚才的
SUUpdater
实例,action 为checkForUpdates:
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
命令工具,会自动打开终端应用,显示:
1 | ➜ ~ /Users/HTC/Downloads/Sparkle-1.21.3/bin/generate_keys ; exit; |
配置 SUPublicEDKey
注意,这个步骤只要运行一次,然后记录下运行的结果,在 Info.plist
增加一个key-value 键值对,SUPublicEDKey
对应的公钥(base64 编码的字符串)。
注:这个步骤做了两件事:
1、生成一个私钥, 并将其保存在登录钥匙串中。您不需要对其执行任何操作, 但不要失去对 Mac 钥匙串的访问权限。如果您丢失了它, 您可能无法发出任何新的更新!
2、打印您的公钥到终端应用程序上显示。
配置 SUFeedURL
在 Info.plist
添加 SUFeedURL
属性字段,其值设置为将应用更新的 URL, 例如https://xxx.com/appcast.xml
appcast.xml 内容:
1 |
|
releaseNotesLink
: 更新日志的说明网页,最好是htmlurl
: zip压缩包下载地扯length
: zip压缩文件大小(字节)edSignature
: ed签名
生成签名
可以使用generate_appcast
工具进行应用强制转换时, 将自动生成签名。也可以手动生成签名。
1 | Sparkle/bin/sign_update path_to_your_update.zip |
示例:
1 | ➜ ~ /Users/HTC/Downloads/Sparkle-1.21.3/bin/sign_update /Users/HTC/Downloads/Sparkle-1.21.3.zip |
生成的 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
属性字段,其值设置为将应用更新的 URL, 例如https://xxx.com/appcast.xml
,下文有xml文件内容说明,与上面 EdDSA 有一些区别。
更新版本签名
把新版本生成的程序打包成zip。因为这个是升级包,因此我们要对升级包进行数字签名。方法很简单:
1 | Sparkle/bin/old_dsa_scripts/sign_update path_to_your_update.zip ~/.ssh/dsa_priv.pem |
记录下返回的字符串,这就是升级包的签名。使用填下到 appcast.xml
中。
appcast.xml 内容:
1 |
|
releaseNotesLink
: 更新日志的说明网页,最好是htmlurl
: zip压缩包下载地扯length
: zip压缩文件大小(字节)dsaSignature
: 升级包的数据签名
一些问题&坑点
web服务器
上面说明的 http://xxx.comappcast.xml
更新信息文件,还是 http://xxx.com/release-note.html
更新说明页面,还是应用的zip文件下载链接,都是需要通过服务器进行访问。
这里比较简单的方法,就是上传到 GitHub
上,就以访问到文件或链接。
如果是本地调试,也可以利用 macOS 自带的 python
创建一个本地的文件服务器:
1 | python -m SimpleHTTPServer |
示例:
1 | ➜ ~ python -m SimpleHTTPServer |
然后就可以通过 http://0.0.0.0:8000
就能访问电脑的所有文档和文件目录。
HTTPS
macOS 10.11 起苹果默认开启 App Transport Security ,也就是应用只能访问 HTTPS 的链接,HTTP 的默认不能访问。
建议当然是使用https,如果没有能力部署,也可以在应用的 Info.plist
配置允许访问http:
1 | <key>NSAppTransportSecurity</key> |
版本号
注意,版本号是 shortVersionString
;不是 version
字段。但是这2个字段都配置了的话,2个都需要大于旧应用的对应版本号,否则,Sparkle
认为没有新版本。
AppStore版本
如果是上架 AppStore,则不能使用 Sparkle
,因为苹果审核禁止检查更新和自动更新,需要更新,要求用户使用 AppStore。
编译报错
1 | /Users/HTC/Desktop/SparkleDemo-macOS/Pods/Target Support Files/Pods-macOSDemo/Pods-macOSDemo-frameworks.sh: line 104: EXPANDED_CODE_SIGN_IDENTITY: unbound variable |
在Xcode菜单栏选择 File
-> Workspace Setting
就会弹出一个界面,看出 Xcode10 是默认选中的最新的 New Build System(Default)
,在这个编译系统的环境下,编译脚本一直会报错。把 build system 切换到 Legacy Build System
,使用旧的编译系统就正常运行。怀疑是新的编译系统,流程有变动,这个问题,后续在深研吧。
总结
其实,官方文档已经给出了很好的教程。这里为什么还写教程的原因:
其一是,官方的文档比较旧,针对 Xcode10,一些操作已经发生了比较大的变化,对于新入门的苹果开发者,可以比较懵。
其二,对于英文或者想快速的入门使用的同学,提供一个最简洁的教程,节省大家的时间,对大家都好的事件,应该做!
其三,对于刚刚入门 macOS 软件开发的同学,可能还不知道有这样优秀的第三方更新软件库,所以,心若所诚,力行心从!
参考
- sparkle-project/Sparkle: A software update framework for macOS
- macmade/GitHubUpdates: Cocoa framework to install application updates from GitHub releases.
- 为你的Cocoa应用程序加入更新支持:Sparkle 简介 - CocoaChina
- 用Sparkle为Cocoa程序增加自动升级 - Cocoa学习
- Documentation - Sparkle: open source software update framework for macOS
- Publishing an update - Sparkle: open source software update framework for macOS
- Upgrading from previous versions of Sparkle - Sparkle: open source software update framework for macOS
- 两款Mac软件自动升级开源开发框架 - CSDNxck的博客 - CSDN博客
- Sparkle 1: Setup | Elias’s Cave
- MartianZ! - 使用Sparkle为OS X App添加自动更新功能
- 使用 最新版本Sparkle 进行自更新 - weixin_34174322的博客 - CSDN博客
- App Translocation
- potionfactory/LetsMove: A sample that shows how to move a running Mac application to the /Applications directory
- 如有疑问,欢迎在评论区一起讨论!
- 如有不正确的地方,欢迎指导!
> 注:本文首发于 [iHTCboy's blog](https://iHTCboy.com),如若转载,请注来源