pkgbuild 踩坑表演

今天偶然发现开发的 业火输入法 竟然有一个天大的问题,不知道从哪个版本开始,如果用户是首次安装,那么必定会安装失败,记录一下解决问题的过程

缘起于发现开发的输入法在某台机器上总是越用越卡,终于腾出时间打算排查一下(关于这里具体的原因后面再说),然后就在尝试删除重新安装的过程中发现了这个问题。说一下我的操作步骤,首先删除了原目录 /Library/Input Methods 下的文件,然后下载了最新版的 installer.pkg 文件,运行安装程序,安装过程中也没有什么报错。但是在安装完成后,并没有自动启动此输入法,在系统设置 -> 键盘设置中也无法找到此输入法,就好像完全没安装上一样。

排查后发现安装后 /Library/Input Methods 目录下并没有输入法应用,这就很不合理了,因为我很确定,这个版本是可以正常安装升级的,我的另一台设备就是通过同一个安装文件以重新安装的方式升级到这个最新版本,所以不应该出现问题才对。

刚开始我以为是 installer.pkg 文件中的 postinstall 脚本有问题,这个脚本中会先通过 pkill 进程名的方式停掉旧版本的进程,但是并没有提前判断这个进程是否存在,新安装的设备中因为不存在这个进程所以这个命令必然会失败,所以我首先猜测的就是这个脚本有问题。然而很遗憾的是,经过验证,并不是这个问题的原因,事后在复盘这里时,觉得也确实不太可能是这里的问题,因为 postinstall 是应用安装后执行的脚本,脚本中也并没有删除文件夹中应用的逻辑,所以问题不大可能出现在这里。

上面的方式尝试后没有结果,于是尝试以更新的方式重新安装了一下,具体操作步骤是,先往 /Library/Input Methods 丢一个旧版本的 .app 应用文件,再重新运行 installer.pkg。神奇的是,从 .app 文件的创建时间来分析,竟然安装成功了,旧版本成功被替换成了新版本,神奇吧。

无奈之下,啃了一下 pkgbuild 的使用说明,发现最有可能的原因是在构建的命令中缺少了 --component-plist ${plist file} 这个选项导致的,于是我翻了翻 git 的提交历史,重新把 component.plist 这个文件给找了出来(是的,在最初的构建脚本中,是有这个文件的,后面迭代过程中删除了),然后修改 pkgbuild 构建的命令,你猜怎么着,竟然可以了,真是让人苦笑不得。

深入分析原因,猜测可能与 component.plist 中定义的更新策略类似,component.plist 文件中有定义两个更新策略,一个是 upgrade,即全新安装,完全替换掉旧的 .app 文件,另一个是 update,仅更新 .app 中有变化的文件,仅用于升级安装的场景,全新安装时,不会安装这些文件。所以据此猜测,可能是在没有指定 component.plist 文件时,采用的默认策略类似于 update ,所以在全新安装时不会安装。

这里让人吐血的是,刚开始的构建脚本是正常的,后面重新修改了构建脚本,但是却没有测过全新安装的场景,导致问题存在了好久,后续还是要小心注意这些修改。