制作具有开发人员ID的macOS安装程序软件包

问题描述 投票:180回答:5

注意:这仅适用于OS X Installer软件包,提交给Mac App Store的软件包遵循不同的规则。

由于Mountain Lion的Gatekeeper,我最终不得不将我的PackageMaker构建脚本带到谷仓后面进行拍摄。 PackageMaker已从Xcode中删除,并移至“ Xcode辅助工具”中,因此希望很快会被忘记。

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

xcode packagemaker pkgbuild productbuild
5个回答
327
投票

我们的示例项目有两个构建目标:HelloWorld.app和Helper.app。我们为每一个制作一个component package并将它们组合成一个product archive

A component package包含要由OS X安装程序安装的有效负载。虽然是一个组成部分软件包可以单独安装,通常包含在产品归档中。

我们的工具:pkgbuildproductbuildpkgutil

成功完成“构建和存档”后,在终端中打开$ BUILT_PRODUCTS_DIR。

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

这为我们提供了component-plist,您可以在"Component Property List"部分中找到值说明。 pkgbuild -root生成component packages,如果不需要更改任何默认属性,则可以在以下命令中省略-component-plist参数。

productbuild --synthesize产生Distribution Definition

$ 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 

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

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

我建议查看iTunes Installers Distribution.xml,以了解可能的情况。您可以使用以下方法解压缩“ Install iTunes.pkg”:

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

让我们放在一起

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

添加名为“生成程序包”的运行脚本构建阶段,它设置为仅在安装时运行脚本] ::

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

签署OS X安装程序

程序包使用Developer ID Installer证书签名,可以从Developer Certificate Utility下载。

它们的签名是通过pkgbuild

productbuildproductsign--sign "Developer ID Installer: John Doe"参数完成的。

注意,如果要使用productbuild创建已签名的产品归档

,则没有理由对组件包进行签名。

“开发人员证书实用工具”

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

要将某些内容复制到Xcode存档中,我们不能使用Run Script Build Phase。为此,我们需要使用“方案动作”。

编辑方案并展开存档。然后单击后操作并添加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

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

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

脚本

有两种不同类型的脚本:JavaScript in Distribution Definition Files和Shell脚本。

我在WhiteBox - PackageMaker How-to中找到的有关Shell脚本的最佳文档,但是请谨慎阅读,因为它是指旧的软件包格式。

附加阅读

  • Installer Problems and Solutions
  • Stupid tricks with pkgbuild
  • persisting obsolescence
  • 已知问题和解决方法

    目的地选择窗格

    仅向用户提供目标选择选项-“为此计算机的所有用户安装”。该选项在视觉上显示为选中状态,但用户需要单击该选项才能继续安装,从而造成一些混乱。

    << img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9iVU15YS5wbmcifQ==” alt =“显示安装程序错误的示例”>“>

    [Apples文档建议使用<domains enable_anywhere ... />,但这会触发新的更具错误性的Destination Select窗格,Apple不在其任何包装中使用。

    使用不推荐使用的<options rootVolumeOnly="true" />,您可以得到旧的“目标选择窗格”。“显示旧目的地的示例选择窗格”


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

    简短回答:请勿尝试!

    长答案:真的;不要尝试!读取Installer Problems and Solutions。读完这篇文章你知道我做了什么吗?我很笨,可以尝试一下。告诉自己,我确定他们已经解决了10.7或10.8中的问题。

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

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

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

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


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

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

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

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


    使用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
    

    重要的是,以登录用户身份而不是安装程序用户身份运行该应用程序。这是通过launchctl asuser uid路径

    完成的。另外,我们仅在不是通过installer
    工具或Apple Remote Desktop完成的命令行安装时才运行它。

    StéphaneSudre有一个非常有趣的应用程序,它可以为您完成所有这些工作,可编写脚本/支持从命令行进行构建,具有非常漂亮的GUI,并且免费。可悲的是:它被称为“包裹”,因此无法在Google中找到。

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

    我希望我在开始手工制作自己的脚本之前就已经知道这一点。

    “打包应用程序屏幕截图”

    仅供参考,对于那些试图为捆绑软件或插件创建软件包安装程序的人,这很容易:

    pkgbuild --component "Color Lists.colorPicker" --install-location ~/Library/ColorPickers ColorLists.pkg
    

    A +1接受的答案:

    安装程序中的目的地选择

    如果希望在用户域和系统域之间选择域(也称为目标域),则不要尝试<domains enable_anywhere="true">,请使用以下命令:

    <domains enable_currentUserHome="true" enable_localSystem="true"/>

    [enable_currentUserHome~/Applications/下安装应用程序应用程序,enable_localSystem允许在/Application下安装应用程序>

    [我已经在El Capitan 10.11.6(15G1217)中进行了尝试,在1台开发机和2台我尝试过的不同VM上似乎运行良好。

    Here is a build script从构建根目录创建签名的安装程序包。

    #!/bin/bash
    # TRIMCheck build script
    # Copyright Doug Richardson 2015
    # Usage: build.sh
    #
    # The result is a disk image that contains the TRIMCheck installer.
    #
    
    DSTROOT=/tmp/trimcheck.dst
    SRCROOT=/tmp/trimcheck.src
    
    INSTALLER_PATH=/tmp/trimcheck
    INSTALLER_PKG="TRIMCheck.pkg"
    INSTALLER="$INSTALLER_PATH/$INSTALLER_PKG"
    
    #
    # Clean out anything that doesn't belong.
    #
    echo Going to clean out build directories
    rm -rf build $DSTROOT $SRCROOT $INSTALLER_PATH
    echo Build directories cleaned out
    
    
    #
    # Build
    #
    echo ------------------
    echo Installing Sources
    echo ------------------
    xcodebuild -project TRIMCheck.xcodeproj installsrc SRCROOT=$SRCROOT || exit 1
    
    echo ----------------
    echo Building Project
    echo ----------------
    pushd $SRCROOT
    xcodebuild -project TRIMCheck.xcodeproj -target trimcheck -configuration Release install || exit 1
    popd
    
    echo ------------------
    echo Building Installer
    echo ------------------
    mkdir -p "$INSTALLER_PATH" || exit 1
    
    echo "Runing pkgbuild. Note you must be connected to Internet for this to work as it"
    echo "has to contact a time server in order to generate a trusted timestamp. See"
    echo "man pkgbuild for more info under SIGNED PACKAGES."
    pkgbuild --identifier "com.delicioussafari.TRIMCheck" \
        --sign "Developer ID Installer: Douglas Richardson (4L84QT8KA9)" \
        --root "$DSTROOT" \
        "$INSTALLER" || exit 1
    
    
    echo Successfully built TRIMCheck
    open "$INSTALLER_PATH"
    
    exit 0
    

    182
    投票

    StéphaneSudre有一个非常有趣的应用程序,它可以为您完成所有这些工作,可编写脚本/支持从命令行进行构建,具有非常漂亮的GUI,并且免费。可悲的是:它被称为“包裹”,因此无法在Google中找到。


    3
    投票

    仅供参考,对于那些试图为捆绑软件或插件创建软件包安装程序的人,这很容易:


    3
    投票

    A +1接受的答案:


    2
    投票

    Here is a build script从构建根目录创建签名的安装程序包。

    #!/bin/bash
    # TRIMCheck build script
    # Copyright Doug Richardson 2015
    # Usage: build.sh
    #
    # The result is a disk image that contains the TRIMCheck installer.
    #
    
    DSTROOT=/tmp/trimcheck.dst
    SRCROOT=/tmp/trimcheck.src
    
    INSTALLER_PATH=/tmp/trimcheck
    INSTALLER_PKG="TRIMCheck.pkg"
    INSTALLER="$INSTALLER_PATH/$INSTALLER_PKG"
    
    #
    # Clean out anything that doesn't belong.
    #
    echo Going to clean out build directories
    rm -rf build $DSTROOT $SRCROOT $INSTALLER_PATH
    echo Build directories cleaned out
    
    
    #
    # Build
    #
    echo ------------------
    echo Installing Sources
    echo ------------------
    xcodebuild -project TRIMCheck.xcodeproj installsrc SRCROOT=$SRCROOT || exit 1
    
    echo ----------------
    echo Building Project
    echo ----------------
    pushd $SRCROOT
    xcodebuild -project TRIMCheck.xcodeproj -target trimcheck -configuration Release install || exit 1
    popd
    
    echo ------------------
    echo Building Installer
    echo ------------------
    mkdir -p "$INSTALLER_PATH" || exit 1
    
    echo "Runing pkgbuild. Note you must be connected to Internet for this to work as it"
    echo "has to contact a time server in order to generate a trusted timestamp. See"
    echo "man pkgbuild for more info under SIGNED PACKAGES."
    pkgbuild --identifier "com.delicioussafari.TRIMCheck" \
        --sign "Developer ID Installer: Douglas Richardson (4L84QT8KA9)" \
        --root "$DSTROOT" \
        "$INSTALLER" || exit 1
    
    
    echo Successfully built TRIMCheck
    open "$INSTALLER_PATH"
    
    exit 0
    
    © www.soinside.com 2019 - 2024. All rights reserved.