macOS上pkg安装包的制作


=Start=

缘由:

前段时间我负责的一个终端应用推广在借助MDM进行分发的时候出了点问题(具体情况是在低于或等于10.15.7版本的macOS系统下发了但是没有正常安装),提供应用安装包的同学说手动安装没问题那肯定不是包的问题,负责MDM分发的同学说其它的安装包都可以正常下发肯定也不是MDM的问题,在这种情况下,为了能让应用推广正常进行下去,我只好自己去学习和尝试解决,这里简单记录一下macOS上pkg安装包的制作方法和注意事项(等后面有机会了我再深入了解一下MDM的相关知识),方便有需要的参考。

正文:

参考解答:
pkg安装包是什么?

pkg是macOS平台下一种常见的安装包格式(另一种常见的是dmg格式)。两者的简单介绍如下:

dmg文件(或磁盘镜像文件)用于安装软件,但其中可以包含任意类型的文件,而不仅仅是应用程序或安装文件。这种格式常见于从互联网下载的macOS软件安装包,比如微信Mac版,甚至是待会要介绍的Packages这个macOS上的软件安装包制作工具本身也是以dmg格式提供的下载。

pkg文件是macOS安装包,包含安装程序脚本和压缩的安装文件,用于在用户硬盘上安装Mac软件应用程序。

虽然在互联网上分发的macOS安装程序以dmg格式的居多,但是在企业内部推macOS应用的时候,一般是pkg格式的居多,因为DMG文件需要挂载为一个虚拟磁盘来推送应用,而PKG文件可以直接安装,并且通常具备一系列安装流程,引导用户完成安装过程。

如何制作pkg安装包?

因为我是新手,同时也只是为了快速制作一个pkg安装包用于测试和解决问题,所以会以手头上能找到的最简单方便的教程/工具为主。这里的教程是「【技术分享】Mac环境PKG安装包制作教程」,工具是「Packages」。

Packages是一款开源的安装包制作工具,能够指定文件的安装路径、定制安装流程、资源国际化、插件机制、执行安装脚本,基本能够满足绝大部分场景。

Packages的下载和安装就不赘述了,比较简单,下面只介绍一些基本的使用和特定的注意事项。

  1. 两种项目模版的选择:

Distribution: A Distribution project can include multiple packages and allows you to have a welcome message, custom background picture, etc.
Raw Package: A Raw Package project lets you install files at specific locations.

简而言之就是,如果安装包要实现的功能足够简单,可以选择Raw Package模式,可以支持你将安装文件放置到特定目录下。复杂的或者想实现多一点功能的就选Distribution模式(支持自定义背景图片/欢迎信息等功能)。

  1. 项目名称和位置

“Project Name”为项目名称可任意填写,需要注意的是最好将“Project Directory”选定为安装文件所在的目录,否则容易出现安装包运行失败的现象——实测发现主要和目录权限有关,这个问题其实不大。

  1. Project的几个设置

Settings #可以设置安装包名(也即编译出来的pkg文件名)、安装包输出位置、安装包格式等信息。
Presentation #设置安装过程中的呈现效果。标准的安装过程分为:Introduction, Read Me, License, Destination Select, Installation Type, Installation, Summary七个步骤。可以为每个步骤定制文本信息并选择国际化设置。
Requirements & Resources
Comments

  1. 具体package的设置
  • Settings #设定标识符/版本号/安装完成的动作(是否重启等)/安装选项(安装是否需要输入密码等)
  • Payload #指定安装的目标目录(默认是根目录,如果要修改,选中特定目录之后要点击Set按钮才行,对应目录图标上就会出现一个准星图标,表示文件将安装到这个位置
  • Scripts #pre/post安装前后的执行脚本(安装前的脚本一般用于关闭正在运行的app进程,删除原来的app;安装后的脚本主要做启动app的工作)

如上所有操作后打包选项设置完成。然后点击工具栏的Build或者Build and Run开始制作pkg安装包,两者的区别是前者只制作pkg包,而后者制作后立即运行。

  1. pkg包制作好之后的测试

第一次制作pkg安装包时,会有很多内容不清楚,这时最好的办法是每一步具体的操作参考原文先搞一个出来,然后对制作好的pkg包进行安装测试,多试几次你就会明白每一步操作都是起什么作用的,哪些步骤比较重要不能马虎,哪些步骤不重要可以不用关注。

实际操作一遍下来之后你就会发现这是个熟能生巧的活,没有太多的技术含量(但是第一个搞出这个的人还真的是挺有探索精神的)。

==

几个简单快速获取macOS硬件/环境信息的命令

date
hostname
system_profiler SPHardwareDataType | grep -E "Serial Number|Hardware UUID"
ifconfig| grep 'inet ' | grep -v '127.0.0.1'
curl --connect-timeout 1 ifconfig.me

Scripts中的 pre-installation 和 post-installation 脚本样例

==> preInstall.sh

#!/usr/bin/env bash
echo "[pre]start" >>/tmp/pkg_install.txt
date >>/tmp/pkg_install.txt
ps aux | grep -i "keyword" | grep -v "grep" >>/tmp/pkg_install.txt
if [[ $? -eq 0 ]]; then
	#statements
	echo "[pre]process already exist, do nothing!" >>/tmp/pkg_install.txt
else
	#statements
	[ ! -f name11.pkg ] && sudo installer -pkg ./name11.pkg -target / && echo "[pre]try to install!" >>/tmp/pkg_install.txt
	curl -I "https://ixyzero.com/preInstall"
fi
ls -lt "/Library/Application Support/DoPkgTest/" >>/tmp/pkg_install.txt 2>&1
date >>/tmp/pkg_install.txt
echo "[pre]end" >>/tmp/pkg_install.txt
exit 0

==> postInstall.sh

#!/usr/bin/env bash
echo "[post]start" >>/tmp/pkg_install.txt
date >>/tmp/pkg_install.txt
ps aux | grep -i "keyword" | grep -v "grep" >>/tmp/pkg_install.txt
if [[ $? -eq 0 ]]; then
	#statements
	echo "[post]process already exist, do nothing!" >>/tmp/pkg_install.txt
else
	#statements
	echo 'sudo installer -pkg "/Library/Application Support/DoPkgTest/name11.pkg" -target /' >>/tmp/pkg_install.txt
	sudo installer -pkg "/Library/Application Support/DoPkgTest/name11.pkg" -target /
	host=$(hostname)
	ip=$(ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')
	sn=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $NF}')
	curl -I "https://ixyzero.com/host=$host&ip=$ip&sn=$sn"
	echo "https://ixyzero.com/host=$host&ip=$ip&sn=$sn" >>/tmp/pkg_install.txt
fi
date >>/tmp/pkg_install.txt
echo "[post]end" >>/tmp/pkg_install.txt
参考链接:

【技术分享】Mac环境PKG安装包制作教程
https://mp.weixin.qq.com/s/rFfm1_oyZbd-4cVu6fvsaw

http://s.sudre.free.fr/Software/Packages/about.html

http://s.sudre.free.fr/Software/documentation/Packages/en_2017/index.html

Open PKG File
https://openpkgfile.com/

Difference between .pkg and .dmg file?
https://forums.macrumors.com/threads/difference-between-pkg-and-dmg-file.217052/

Apple Mac OS X: Difference between APP and DMG
https://www.askingbox.com/question/apple-mac-os-x-difference-between-app-and-dmg

How to convert DMG to PKG Mac App for distribution
https://www.hexnode.com/mobile-device-management/help/convert-dmg-to-pkg-mac/

Why are so many Mac downloads a .dmg just that contains a single .pkg?
https://apple.stackexchange.com/questions/30695/why-are-so-many-mac-downloads-a-dmg-just-that-contains-a-single-pkg

https://en.wikipedia.org/wiki/Apple_Disk_Image

https://en.wikipedia.org/wiki/Installer_(macOS)

=END=

, ,

《“macOS上pkg安装包的制作”》 有 4 条评论

  1. 一些经验整理/总结
    `
    因为安装的pkg包一般都比较大,所以需要提前传到CDN上,然后通过CDN的链接进行下载,以减少下载失败的可能;
    刚想到一点就是最好也校验一下从CDN下载的pkg包的哈希,避免因为缓存投毒的原因被安装上了非预期的软件;
    另外就是收集请求的域名一定要保证外网可达,否则可能会因为非必要原因导致数据分析存在困难和误差。

    1. preInstall
    * 检查目标进程/目录是否存在
    * 如果进程不存在,则下载安装包;如果进程存在但版本较低,则下载更新包;如果进程存在且版本正常,则仅打印日志其它什么也不做
    * 发送请求/打印日志,用来告诉服务端 preInstall 正常执行

    2. install
    * 检查目标进程/目录是否存在
    * 执行安装/更新命令
    * 发送请求/打印日志,用来告诉服务端 install 正常执行

    3. postInstall
    * 检查目标进程/目录是否存在(理论上应该是有的,因为前面一步刚执行了检查和安装)
    * 如果不存在,则执行安装;如果已存在,则什么也不用做
    * 清理前2步中的无用文件,然后采集相关必要信息用于数据分析
    * 发送请求/打印日志,用来告诉服务端 postInstall 正常执行
    `

    • 今天经过多次实测发现,Payload页面仅仅用于指定要将文件(一般是可执行文件)放置的位置,该文件本身是不涉及到自动执行的,如果你想这么做,需要在post-installation那里用脚本显示执行才OK。
      所以上面第2步的install功能要根据实际情况拆分到preInstall或postInstall阶段中。

  2. macOS上如何获取当前的登录用户名称
    macos get current logged in user
    https://stackoverflow.com/questions/1104972/how-do-i-get-the-name-of-the-active-user-via-the-command-line-in-os-x/1104976#1104976
    `
    stat -f “%Su” /dev/console
    `
    Getting the current user in macOS – Update
    https://scriptingosx.com/2020/02/getting-the-current-user-in-macos-update/
    `
    # method 1
    loggedInUser=$( echo “show State:/Users/ConsoleUser” | scutil | awk ‘/Name :/ && ! /loginwindow/ { print $3 }’ )

    # method 2
    loggedInUser=$(stat -f %Su /dev/console)
    `

发表评论

您的电子邮箱地址不会被公开。