已开源 app 实现检查更新的简单方式

如果您开发的 app 没有上架 app store,那么您肯定会考虑如何保证用户及时收到 app 更新的问题,如果您的项目是开源在某个托管平台的,那么本文就提供一种简单的方式助您实现 app 检查更新的功能。

实现平台

  • macOS 10.14.3
  • swift 4.2.1
  • xcode 10.1

思路

本文提供的方法,不需要架设服务器,只要在开源平台上托管就可以。所以,这里假设您的 app 都是在托管平台发布,并且代码也是及时推送到托管平台的。

每个 xcode 工程中都有一个 info.plist 文件,使用其中的 CFBundleShortVersionString 键的值作为版本判断依据,app 运行起来本身能获取自己的版本号,通过网络从托管平台获取最新版本源文件中的 info.plist 文件,然后得到最新版本号,与自身的版本号对比,如果不一样就说明有了最新版本(更严格的判断应该是远端文件中获取的版本号新于 app 自身的版本号),然后通过提示框提醒用户有新版本发现,提示框中给出一个按钮,帮助用户跳转到开源工程最新版本的 release 页面即可。

:本文描述的具体方法不适用于 Xcode 11 及以上版本,因为 info.plist 的内容有变化,不过可以继续使用此文描述的思路,不同的是需要解析的文件不是 info.plist 而是 xxxxx.xcodeproj/project.pbxproj ,版本就是其中的 MARKETING_VERSION

这里以工程托管在 github 为例,说明几点注意的地方:

  • 请求的 info.plist 文件链接必须是直接指向原文件的,而不是浏览代码页面对应的链接,网页 github 平台上浏览工程代码,找到 info.plist 文件,然后点击如图位置的 raw 按钮即可得到源文件的直链:

  • 跳转最新 release 的页面是根据 tag 名进行跳转的,所以 tag 名称最好与版本号命名规则一致,当然不一致也可以,只要最终能对应上就可以,比如十里的一个开源项目 textGO,对应 tag 的 release 页面链接可以轻易获得:https://github.com/smslit/textGO/releases/tag/v0.3 ,规则就是 https://github.com/smslit/textGO/releases/tag/v + 版本号

  • 第一步网络请求 info.plist 文件使用 GET 请求即可完成,网络请求相关内容可以通过另一篇文章了解:macOS 开发之实现 HTTP 的 GET 和 POST 请求

示例

下面以十里的开源项目 textGO 为例说明一下实现。

更新器类

因为十里将项目托管到的是 github 平台,所以封装的更新器类仅适用于 github,如果适配其它平台只需修改两处 url 的处理即可。更新器类为 TextGoUpdater ,在文件 TextGoUpdater.swift 中定义,您可以打开这个文件查看具体实现代码。

属性

TextGoUpdater 类中定义了两个属性,分别是 userurl

  • user 指的是 github 的账户名
  • url 指的是 info.plist 文件的直链

方法

  • init(user:) 初始化方法,初始化过程中根据提供的 github 账户名和工程名推断出 info.plist 文件的直链并赋给 url 属性
  • check(callback:) 触发检查更新的过程,是公共方法。callback 是个逃逸闭包,完成网络请求后在进行数据处理前执行,主要方便调整控件的状态。
  • checkUpdateRequestSuccess(data:response:error:callback:) 封装了网络请求完成后的处理过程,是私有方法。另外使用的两个 tipInfo 方法在 TextGoPublic.swift 文件中定义,用来显示提示框告知用户检测更新的结果。检测到更新以后,会根据类的 user 属性和工程名称以及最新版本号推断出 release 页面链接。

使用方法

使用方法很简单,主要分两种:有回调和没有回调。

无回调使用

可以在文件 AppDelegate.swift 中看到使用方法

  • 定义属性 updater
let updater = TextGoUpdater(user: "smslit") {}
  • checkUpdate() 方法中直接调用 updater 实例的 check 方法:
@objc func checkUpdate() {
    updater.check() {}
}

有回调使用

  • 定义属性 updater
let updater = TextGoUpdater(user: "smslit") {}
  • checkUpdate() 方法中直接调用 updater 实例的 check 方法:
@objc func checkUpdate() {
    updater.check() {
        // 实现对界面控件的调整
    }
}

执行效果

textGO 是一个菜单栏小工具,通过点击检查更新菜单项触发更新的检查,为了更好的展示效果,以视频展示,同时修改版本号来查看有更新和没更新两种情况的效果。

总结

本文更新器的实现思路比较简单,只是提供了检查更新的功能,不过一般情况下这就足够了,其实这种方法也能适用于托管平台的私有项目,可以在平台中共享出某个可以提供版本号的文件,得到它的直链就可以,思路一样,想办法更改两处链接就能实现。最后,祝您成功!