准备可用于开发人员ID的macOS安装程序包 [英] Making macOS Installer Packages which are Developer ID ready

查看:170
本文介绍了准备可用于开发人员ID的macOS安装程序包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这仅用于 OS X安装程序程序包,这些程序包将提交给 Mac App Store 遵循不同的规则.

Note: This is for OS X Installer packages only, packages for submission to the Mac App Store follow different rules.

由于山狮的 Gatekeeper 我终于不得不接受我的 PackageMaker 在谷仓后面构建脚本并射击它. PackageMaker已从Xcode中删除,并移至"Xcode辅助工具"中,因此希望很快将其遗忘.

Because of Mountain Lion's Gatekeeper I finally had to take my PackageMaker build script behind the barn and shoot it. PackageMaker was already removed from Xcode and moved into "Auxiliary Tools for Xcode", so hopefully it will be soon forgotten.

问题是如何使用pkgbuildproductbuildpkgutil替换它?

The question is how do I use pkgbuild, productbuild, and pkgutil to replace it?

推荐答案

我们的示例项目有两个构建目标:HelloWorld.app和Helper.app.我们为每个组件制作一个组件包,然后将它们组合成一个产品归档文件.

Our example project has two build targets: HelloWorld.app and Helper.app. We make a component package for each and combine them into a product archive.

组件包包含要由OS X安装程序安装的有效负载.虽然是一个组成部分 软件包可以单独安装,通常会合并到产品档案文件中.

A component package contains payload to be installed by the OS X Installer. Although a component package can be installed on its own, it is typically incorporated into a product archive.

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

After a successful "Build and Archive" open $BUILT_PRODUCTS_DIR in the Terminal.

$ cd ~/Library/Developer/Xcode/DerivedData/.../InstallationBuildProductsLocation
$ pkgbuild --analyze --root ./HelloWorld.app HelloWorldAppComponents.plist
$ pkgbuild --analyze --root ./Helper.app HelperAppComponents.plist

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

This give us the component-plist, you find the value description in the "Component Property List" section. pkgbuild -root generates the component packages, if you don't need to change any of the default properties you can omit the --component-plist parameter in the following command.

productbuild --synthesize 生成

In the Distribution.xml you can change things like title, background, welcome, readme, license, and so on. You turn your component packages and distribution definition with this command into a product archive:

$ productbuild --distribution ./Distribution.xml \
    --package-path . \
    ./Installer.pkg

我建议查看 iTunes Installers Distribution.xml,以了解可能的解决方案.您可以使用以下命令解压缩"Install iTunes.pkg":

I recommend to take a look at iTunes Installers Distribution.xml to see what is possible. You can extract "Install iTunes.pkg" with:

$ pkgutil --expand "Install iTunes.pkg" "Install iTunes"

让我们放在一起

我的项目中通常有一个名为Package的文件夹,其中包含Distribution.xml,component-plists,资源和脚本之类的东西.

Lets put it together

I usually have a folder named Package in my project which includes things like Distribution.xml, component-plists, resources and scripts.

添加一个名为生成程序包"的运行脚本构建阶段,该阶段仅在安装时设置为运行脚本

Add a Run Script Build Phase named "Generate Package", which is set to Run script only when installing:

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}"

如果使用 productbuild 生成软件包后不必更改软件包,则可以摆脱pkgutil --expandpkgutil --flatten步骤.您也可以在 productbuild 上使用-sign 参数,而不是运行 productsign .

If you don't have to change the package after it's generated with productbuild you could get rid of the pkgutil --expand and pkgutil --flatten steps. Also you could use the --sign paramenter on productbuild instead of running productsign.

程序包使用 Developer ID Installer 证书签名,您可以从

Packages are signed with the Developer ID Installer certificate which you can download from Developer Certificate Utility.

他们的签名是通过 pkgbuild productbuild productsign --sign "Developer ID Installer: John Doe"参数完成的.

They signing is done with the --sign "Developer ID Installer: John Doe" parameter of pkgbuild, productbuild or productsign.

请注意,如果要使用productbuild创建已签名的产品档案文件,则没有理由对组件包进行签名.

Note that if you are going to create a signed product archive using productbuild, there is no reason to sign the component packages.

要将某些内容复制到Xcode存档中,我们不能使用运行脚本构建阶段.为此,我们需要使用方案动作".

To copy something into the Xcode Archive we can't use the Run Script Build Phase. For this we need to use a Scheme Action.

编辑方案并展开存档.然后单击后操作并添加新运行脚本操作

Edit Scheme and expand Archive. Then click post-actions and add a 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

在Xcode 5中,请将此值用于PKG:

In Xcode 5, use this value for PKG instead:

PKG="${OBJROOT}/ArchiveIntermediates/${TARGET_NAME}/BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"

如果您的版本控件未存储Xcode方案信息,我建议将其作为外壳程序脚本添加到您的项目中,这样您就可以通过将脚本从工作区拖动到后操作中来简单地还原操作.

In case your version control doesn't store Xcode Scheme information I suggest to add this as shell script to your project so you can simple restore the action by dragging the script from the workspace into the post-action.

有两种不同类型的脚本:

There are two different kinds of scripting: JavaScript in Distribution Definition Files and Shell Scripts.

我在 WhiteBox-PackageMaker操作指南,但请谨慎阅读,因为它指的是旧的软件包格式.

The best documentation about Shell Scripts I found in WhiteBox - PackageMaker How-to, but read this with caution because it refers to the old package format.

  • Flat Package Format - The missing documentation
  • Installer Problems and Solutions
  • Stupid tricks with pkgbuild
  • persisting obsolescence

目标选择窗格

仅向用户提供目标选择选项-为此计算机的所有用户安装".该选项在外观上看起来是选中的,但是用户需要单击它才能继续安装,从而造成一些混乱.

The user is presented with the destination select option with only a single choice - "Install for all users of this computer". The option appears visually selected, but the user needs to click on it in order to proceed with the installation, causing some confusion.

Apples文档建议使用<domains enable_anywhere ... />,但这会触发新的更具错误性的目标选择窗格",而Apple在其任何包装中均未使用.

Apples Documentation recommends to use <domains enable_anywhere ... /> but this triggers the new more buggy Destination Select Pane which Apple doesn't use in any of their Packages.

使用弃用的<options rootVolumeOnly="true" />给您旧的目标选择"窗格.

Using the deprecate <options rootVolumeOnly="true" /> give you the old Destination Select Pane.

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

You want to install items into the current user’s home folder.

简短的回答:请勿尝试!

Short answer: DO NOT TRY IT!

长答案:真的吗?不要尝试!阅读安装程序问题和解决方案.读完这篇文章你知道我做了什么吗?我很笨,可以尝试一下.告诉自己,我确定他们已经解决了10.7或10.8中的问题.

Long answer: REALLY; DO NOT TRY IT! Read Installer Problems and Solutions. You know what I did even after reading this? I was stupid enough to try it. Telling myself I'm sure that they fixed the issues in 10.7 or 10.8.

首先,我不时看到上述目标选择窗格错误".那应该阻止了我,但是我忽略了它.如果您不想在发布软件后的一周内花时间回复支持电子邮件,则必须单击一次精美的蓝色选项后再单击.

First of all I saw from time to time the above mentioned Destination Select Pane Bug. That should have stopped me, but I ignored it. If you don't want to spend the week after you released your software answering support e-mails that they have to click once the nice blue selection DO NOT use this.

您现在正在考虑,您的用户足够聪明,可以理解面板,不是吗?好了,这是关于主文件夹安装的另一件事,它们不起作用!

You are now thinking that your users are smart enough to figure the panel out, aren't you? Well here is another thing about home folder installation, THEY DON'T WORK!

我在大约10台不​​同操作系统版本的机器上进行了两周的测试,但没有失败.所以我发货了.在发布的一个小时内,我向无法安装它的用户表示衷心的感谢.日志提示您将无法解决的权限问题.

I tested it for two weeks on around 10 different machines with different OS versions and what not, and it never failed. So I shipped it. Within an hour of the release I heart back from users who just couldn't install it. The logs hinted to permission issues you are not gonna be able to fix.

因此,让我们再重复一遍:我们不使用Installer进行主文件夹安装!

So let's repeat it one more time: We do not use the Installer for home folder installations!

productbuild不接受用于欢迎,自述,许可和结论的RTFD.

RTFD for Welcome, Read-me, License and Conclusion is not accepted by productbuild.

从开始的RTFD文件开始就支持安装程序,以使漂亮的欢迎屏幕带有图像,但是productbuild不接受它们.

Installer supported since the beginning RTFD files to make pretty Welcome screens with images, but productbuild doesn't accept them.

解决方法: productbuild完成后,请使用虚拟的rtf文件并将其替换到软件包中.

Workarounds: Use a dummy rtf file and replace it in the package by after productbuild is done.

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

Note: You can also have Retina images inside the RTFD file. Use multi-image tiff files for this: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif. More details.

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

Starting an application when the installation is done with a BundlePostInstallScriptPath script:

#!/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

以登录用户身份而不是安装程序用户身份运行该应用程序很重要.这是通过 launchctl asuser uid路径完成的.此外,我们仅在不是通过 installer 工具或 Apple Remote Desktop 完成的命令行安装时才运行它.

It is important to run the app as logged in user, not as the installer user. This is done with launchctl asuser uid path. Also we only run it when it is not a command line installation, done with installer tool or Apple Remote Desktop.

这篇关于准备可用于开发人员ID的macOS安装程序包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆