macos客户端打包主要有两种格式dmg和pkg,dmg很多时候类似于一个压缩包,在安装的时候需要用户拖拽即可,也不需要管理员权限(被覆盖程序需要用户手动退出),在各种开发过程中只需要简单配置一下dmg就可以打包出来。pkg则支持自定义的脚本执行,执行的时候需要root权限,获取到权限之后,通过自定义脚本可以完成各种复杂逻辑,尤其是在各种特殊场景或者需要兼容历史包袱的时候需要选择pkg,这里主要讲一下pkg自定义脚本过程中几个容易出问题的地方。   macos的pkg在早期存在Bundle Package的方式,里面支持多个脚本行为,在10.15之后已经不推荐和支持使用这种了,目前基本都是使用Flat Package的方式,里面主要有两个脚本。

Script NameRun If(何时运行)Run When(运行时机)
preinstall每次安装都会运行在 payload 安装前
postinstall每次安装都会运行在 payload 安装后
  1. 脚本格式和语法 preinstall和postinstall里面支持普通的bash脚本语法(支持引入其他脚本文件等),注意文件名不需要带后缀.sh,另外就是在上传代码执行打包前,需要在本地对两个文件增加可执行文件权限chmod +x,否则即使脚本语法没有问题,最后也会执行失败。

  2. 内置变量 在安装过程中,脚本有一些内置变量可以使用

变量来源说明
$1pkgbuildpkg 文件路径
$2pkgbuild安装目标路径(通常是 /)命令行安装可以自定义目录
$3pkgbuildpackage identifier
$INSTALLER_TEMPinstallerInstaller 临时目录(pkg运行的tmp目录)
  1. 环境变量 虽然支持bash语法,但是在软件安装过程中,脚本运行所在的env并不是单独zsh等运行的env,因为运行在沙盒,下面是我找的一个env(每台电脑不一样),比如tmp等与terminal执行所在env不一样。这里主要的影响在于脚本中如果启动了某些程序或者某些动作,会继承当前程序的env。我们之前遇到一个问题,在脚本中通过open -a启动了某个程序,运行是正常的,但是通过这个程序在启动另外一个程序一点就会崩溃。最初的现象是docker的软件图标闪几秒后退出了。这样就出现运行代码、命令行直接执行这个场景都没有问题,打包后就出现问题。随后我们查询被启动程序的log,发现程序存在崩溃。另外就是这种崩溃出现在安装启动后,如果退出,手动启动或者启动项拉起没有这个问题。继续对比对方程序的log发现崩溃场景下tmp路径不对,无法找到所需程序,随后我们发现安装脚本env变量的差异性,以及这种传染带给子程序的各种问题。
INSTALLER_TEMP=/private/tmp/PKInstallSandbox.ihgwFN/tmp
DSTVOLUME=/
TMPDIR=/private/tmp/PKInstallSandbox.ihgwFN/tmp
DSTROOT=/
USER=root
SCRIPT_NAME=preinstall
SHARED_INSTALLER_TEMP=/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/C/PKInstallSandboxManager-shared-tmp
INSTALLER_SECURE_TEMP=/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/C/PKInstallSandboxManager/52D185A5-181E-41F8-832A-7C5E31B4A3E4.activeSandbox/136FEC37-93BE-4C71-A891-6A5E63455E02
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec
PWD=/private/tmp/PKInstallSandbox.ihgwFN/Scripts/my.fake.pkg.CiIISN
INSTALL_PKG_SESSION_ID=my.fake.pkg
PACKAGE_PATH=/Users/mb312/dev_trees/docosx/pkg_examples/my_package.pkg
SHLVL=1
COMMAND_LINE_INSTALL=1
_=/usr/bin/env
Positional arguments /Users/mb312/dev_trees/docosx/pkg_examples/my_package.pkg / / /
  1. 脚本运行测试和查看工具 pkg包程序的结构是可以直接查看的,可以下载安装这个SuspiciousPackage可以查看程序脚本的目录结构,也可以查看这个程序的脚本到底做了那些动作。另外就是一些gui的打包程序PackagesIceberg,可以放自己的脚本打包一个空的程序快速验证。

另外最后就是mac pkg安装过程中可以实时查看日志的,除了在preinstall和postinstall中本地写log,一些stdout的输出可以在安装的时候快捷键 Command (⌘) + L就可以实时看到整个安装的log了。