使OS X安装程序包像Pro-Xcode Developer ID一样准备好pkg

cat*_*lan 177 xcode packagemaker productbuild pkgbuild

注意:这仅适用于OS X Installer程序包,提交到Mac App Store的程序包遵循不同的规则.

由于Mountain Lion的Gatekeeper,我终于不得不把我的PackageMaker构建脚本放在谷仓后面并拍摄它.PackageMaker已经从Xcode中删除并转移到"Xcode的辅助工具"中,所以希望它很快就会被遗忘.

现在的问题是我怎么用pkgbuild,productbuildpkgutil来代替它?

cat*_*lan 321

我们的示例项目有两个构建目标:HelloWorld.app和Helper.app.我们为每个组件创建一个组件包,并将它们组合到一个产品档案中.

组件包包含要由OS X安装程序安装的有效载荷.虽然组件包可以单独安装,但它通常包含在产品存档中.

我们的工具:pkgbuild,productbuildpkgutil

成功"构建和存档"后,在终端中打开$ BUILT_PRODUCTS_DIR.

$ cd ~/Library/Developer/Xcode/DerivedData/.../InstallationBuildProductsLocation
$ pkgbuild --analyze --root ./HelloWorld.app HelloWorldAppComponents.plist
$ pkgbuild --analyze --root ./Helper.app HelperAppComponents.plist
Run Code Online (Sandbox Code Playgroud)

这为我们提供了组件 - plist,您可以在"组件属性列表"部分找到值描述.pkgbuild -root生成组件包,如果您不需要更改任何默认属性,则可以省略以下命令中的--component-plist参数.

productbuild --synthesize导致分布定义.

$ pkgbuild --root ./HelloWorld.app \
    --component-plist HelloWorldAppComponents.plist \
    HelloWorld.pkg
$ pkgbuild --root ./Helper.app \
    --component-plist HelperAppComponents.plist \
    Helper.pkg
$ productbuild --synthesize \
    --package HelloWorld.pkg --package Helper.pkg \
    Distribution.xml 
Run Code Online (Sandbox Code Playgroud)

Distribution.xml中,您可以更改标题,背景,欢迎,自述文件,许可证等内容.您可以使用此命令将组件包和分发定义转换为产品归档:

$ productbuild --distribution ./Distribution.xml \
    --package-path . \
    ./Installer.pkg
Run Code Online (Sandbox Code Playgroud)

我建议您查看iTunes Installers Distribution.xml以了解可能的情况.您可以使用以下命令提取"安装iTunes.pkg":

$ pkgutil --expand "Install iTunes.pkg" "Install iTunes"
Run Code Online (Sandbox Code Playgroud)

让我们把它放在一起

我的项目中通常有一个名为Package的文件夹,其中包括Distribution.xml,component-plists,resources和scripts等内容.

添加名为"Generate Package" 的运行脚本构建阶段,该阶段设置为仅在安装时运行脚本:

VERSION=$(defaults read "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/Contents/Info" CFBundleVersion)

PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/g"`
TMP1_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp1.pkg"
TMP2_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp2"
TMP3_ARCHIVE="${BUILT_PRODUCTS_DIR}/$PACKAGE_NAME-tmp3.pkg"
ARCHIVE_FILENAME="${BUILT_PRODUCTS_DIR}/${PACKAGE_NAME}.pkg"

pkgbuild --root "${INSTALL_ROOT}" \
    --component-plist "./Package/HelloWorldAppComponents.plist" \
    --scripts "./Package/Scripts" \
    --identifier "com.test.pkg.HelloWorld" \
    --version "$VERSION" \
    --install-location "/" \
    "${BUILT_PRODUCTS_DIR}/HelloWorld.pkg"
pkgbuild --root "${BUILT_PRODUCTS_DIR}/Helper.app" \
    --component-plist "./Package/HelperAppComponents.plist" \
    --identifier "com.test.pkg.Helper" \
    --version "$VERSION" \
    --install-location "/" \
    "${BUILT_PRODUCTS_DIR}/Helper.pkg"
productbuild --distribution "./Package/Distribution.xml"  \
    --package-path "${BUILT_PRODUCTS_DIR}" \
    --resources "./Package/Resources" \
    "${TMP1_ARCHIVE}"

pkgutil --expand "${TMP1_ARCHIVE}" "${TMP2_ARCHIVE}"

# Patches and Workarounds

pkgutil --flatten "${TMP2_ARCHIVE}" "${TMP3_ARCHIVE}"

productsign --sign "Developer ID Installer: John Doe" \
    "${TMP3_ARCHIVE}" "${ARCHIVE_FILENAME}"
Run Code Online (Sandbox Code Playgroud)

如果你没有它与产生之后,更改包productbuild你可以摆脱pkgutil --expandpkgutil --flatten步骤.您也可以在productbuild上使用--sign paramenter而不是运行productsign.

签署OS X安装程序

软件包使用Developer ID Installer证书进行签名,您可以从Developer Certificate Utility下载该证书.

他们使用pkgbuild,productbuildproductsign--sign "Developer ID Installer: John Doe"参数完成签名.

请注意,如果要使用productbuild 创建签名的产品归档,则没有理由签署组件包.

开发者证书工具

一路:将包复制到Xcode存档中

要将某些内容复制到Xcode存档中,我们无法使用" 运行脚本构建阶段".为此,我们需要使用Scheme Action.

编辑方案并展开存档.然后单击post-actions并添加New Run Script Action:

在Xcode 6中:

#!/bin/bash

PACKAGES="${ARCHIVE_PATH}/Packages"

PACKAGE_NAME=`echo "$PRODUCT_NAME" | sed "s/ /_/g"`
ARCHIVE_FILENAME="$PACKAGE_NAME.pkg"
PKG="${OBJROOT}/../BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"

if [ -f "${PKG}" ]; then
    mkdir "${PACKAGES}"
    cp -r "${PKG}" "${PACKAGES}"
fi
Run Code Online (Sandbox Code Playgroud)

在Xcode 5中,使用此值PKG代替:

PKG="${OBJROOT}/ArchiveIntermediates/${TARGET_NAME}/BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"
Run Code Online (Sandbox Code Playgroud)

如果你的版本控件没有存储Xcode Scheme信息,我建议将它作为shell脚本添加到你的项目中,这样你就可以通过将脚本从工作区拖到后期操作中来简单地恢复操作.

脚本

有两种不同的脚本:分发定义文件中的JavaScript和Shell脚本.

关于Shell Scripts的最佳文档我在WhiteBox - PackageMaker How-to中找到,但请仔细阅读,因为它引用了旧的包格式.

补充阅读

已知问题和解决方法

目的地选择窗格

向用户显示目标选择选项,只有一个选项 - "为此计算机的所有用户安装".该选项在视觉上被选中,但是用户需要单击该选项才能继续安装,从而引起一些混淆.

显示安装程序错误的示例

苹果文档建议使用,<domains enable_anywhere ... />但这会触发新的更多错误的目的地选择窗格,Apple不会在其任何包中使用.

使用deprecate可以获得<options rootVolumeOnly="true" />旧的目标选择窗格. 显示旧目标选择窗格的示例


您想要将项目安装到当前用户的主文件夹中.

简短的回答:不要尝试!

答案很长:真的; 不要试试!阅读安装程序问题和解决方案.你知道我读完之后做了什么吗?我愚蠢到可以试试.告诉自己我确信他们已经解决了10.7或10.8中的问题.

首先,我不时看到上面提到的Destination Select Pane Bug.这本应该阻止我,但我忽略了它.如果您不想在发布软件后花一周的时间来回答支持电子邮件,那么一旦选择了漂亮的蓝色选项,就不要再使用它了.

您现在认为您的用户足够聪明,可以将面板弄清楚,不是吗?那么这是关于主文件夹安装的另一件事,他们不工作!

我在大约10台具有不同操作系统版本的机器上进行了为期两周的测试,但是它没有失败.所以我发货了.在发布后的一个小时内,我就回到那些无法安装它的用户那里.日志暗示许可问题,你无法解决.

所以让我们再重复一次:我们不使用安装程序进行主文件夹安装!


不接受RTFD for Welcome,Read-me,License和Results productbuild.

自开始使用RTFD文件以来,安装程序支持使用图像制作漂亮的欢迎屏幕,但是productbuild不接受它们.

解决方法:使用虚拟rtf文件并在productbuild完成后将其替换为包.

注意:您还可以在RTFD文件中包含Retina图像.为此使用多图像tiff文件:tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif.更多细节.


使用BundlePostInstallScriptPath脚本完成安装时启动应用程序:

#!/bin/bash

LOGGED_IN_USER_ID=`id -u "${USER}"`

if [ "${COMMAND_LINE_INSTALL}" = "" ]
then
    /bin/launchctl asuser "${LOGGED_IN_USER_ID}" /usr/bin/open -g PATH_OR_BUNDLE_ID
fi

exit 0
Run Code Online (Sandbox Code Playgroud)

以登录用户身份运行应用程序非常重要,而不是安装程序用户.这是通过launchctl asuser uid path完成的.此外,我们只在不是命令行安装时运行它,使用安装程序工具或Apple Remote Desktop完成.


  • 这是一个很好的教程,但假设存在预制的捆绑包.例如,如果我要将一个文件安装到`/ tmp`中以便稍后在postflight脚本中处理,我该如何构建组件列表?所有可用的文档似乎都假设开发人员使用`--analyze`生成它,至少在最初阶段. (9认同)
  • $ pkgbuild --root ./HelloWorld.app是错误的(假设.app是一个实际的应用程序包).pkgbuild在目标根目录上运行:即:包含由xcode工具链生成的包的文件夹.所以pkgbuild的参数是我们想要打包的包的包含文件夹的路径.如果无法获得此权限,则会导致包含仅包含应用内容文件夹的包.它不会作为实际的应用包安装.赠品是在组件plist中.如果它不包含指定应用程序包的RootRelativeBundlePath条目,那么您已经搞砸了. (5认同)
  • @BramdeJong"毫无意义".我不同意.Apple维护命令行工具.软件包是第三方应用程序,不受社区支持,如果Apple改变了一些重大内容,将来可能会破解.对我来说,我宁愿知道命令行技术,这样,如果Apple改变了一些激烈的东西,那么我就可以继续运行了. (3认同)
  • 请注意,通过命令行创建包完全没有意义,试图逃避打包应用程序中的所有错误.请参阅下面的评论,使用StéphaneSudre的"软件包"应用程序,它可以为您解决所有问题! (2认同)

Bra*_*ong 182

StéphaneSudre有一个非常有趣的应用程序,可以为您完成所有这些,可编写脚本/支持从命令行构建,具有超级漂亮的GUI并且是免费的.可悲的是:它被称为"包",这使得它无法在谷歌中找到.

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

在我开始手工制作自己的脚本之前,我希望我知道它.

包应用截图

  • 我无法相信这篇文章没有更多的意义.该软件非常棒,它支持从命令行构建. (11认同)
  • 我希望这是一个付费的应用程序,开发人员不断更新和修补.Packages.app很棒,特别是如果你想快速部署你的应用程序.我花了3分钟来安装阅读概述,设置我的项目并创建可安装的软件包.对Stéphane的大赞誉. (4认同)
  • @user283182:很晚了,您肯定已经想通了,但也许这会对其他人有所帮助 - 我认为您面临的问题在 [Mac App Store 审查指南](https://developer.apple. com/app-store/review/guidelines/mac/#terms-conditions),规则 2.14:“应用程序必须使用 Xcode 中包含的 Apple 打包技术打包和提交 - 不允许第三方安装程序。” (2认同)