Создание пакетов установщика OS X, таких как идентификатор разработчика Pro-Xcode, готовый pkg

Примечание. Это только для OS X Installer, пакеты для отправки в Mac App Store следуют различным правилам.

Из-за Mountain Lion Gatekeeper Мне, наконец, пришлось взять PackageMaker построить script за сарай и снять его. PackageMaker уже был удален из Xcode и перешел в "Вспомогательные инструменты для Xcode", поэтому, надеюсь, он скоро будет забыт.

Вопрос в том, как использовать pkgbuild, productbuild и pkgutil для его замены?

Ответ 1

Наш пример проекта имеет две цели сборки: HelloWorld.app и Helper.app. Мы создаем пакет компонентов для каждого и объединяем их в архив продукта.

Компонентный пакет содержит полезную нагрузку, которая будет установлена Установщиком OS X. Хотя пакет компонента может быть установлен сам по себе, он обычно включается в архив продукта.

Наши инструменты: pkgbuild, productbuild и pkgutil

После успешной "сборки и архивирования" откройте $ 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, вы найдете описание значения в разделе "Список свойств компонента". 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 

В Distribution.xml вы можете изменить такие вещи, как заголовок, фон, приветствие, readme, лицензия и т.д. С помощью этой команды вы превращаете пакеты компонентов и определение дистрибутива в архив продукта:

$ 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 --expand и pkgutil --flatten. Также вы можете использовать параметр --sign в productbuild вместо того, чтобы запускать productsign.

Подпишите установщика OS X

Пакеты подписаны сертификатом установщика идентификатора разработчика, который можно загрузить из утилиты сертификатов разработчика.

Их подписание выполняется с помощью параметра --sign "Developer ID Installer: John Doe" в pkgbuild, productbuild или productsign.

Обратите внимание, что если вы собираетесь создать подписанный архив продуктов с помощью productbuild, нет причин подписывать пакеты компонентов.

Developer Certificate Utility

Полностью: скопируйте пакет в архив Xcode

Чтобы скопировать что-либо в архив Xcode, мы не можем использовать этап сборки сценария запуска. Для этого нам нужно использовать действие схемы.

Отредактируйте схему и разверните Архив. Затем щелкните пост-действия и добавьте новое действие "Выполнить сценарий":

В 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, я предлагаю добавить это как сценарий оболочки в ваш проект, чтобы вы могли просто восстановить действие, перетащив сценарий из рабочей области в последующее действие.

Scripting

Существует два вида сценариев: JavaScript в файлах определения распространения и сценарии оболочки.

Лучшая документация по сценариям оболочки, которую я нашел в WhiteBox, - PackageMaker How-to, но прочитайте это с осторожностью, потому что это относится к старому формату пакета.

Дополнительное Чтение

Известные проблемы и обходные пути

Панель выбора места назначения

Пользователю предоставляется опция выбора места назначения с единственным выбором - "Установить для всех пользователей этого компьютера". Опция отображается визуально, но пользователю необходимо нажать на нее, чтобы продолжить установку, что вызывает некоторую путаницу.

Example showing the installer bug

Документация Apple рекомендует использовать <domains enable_anywhere.../> но это вызывает новую, более <domains enable_anywhere.../> выбора места назначения, которую Apple не использует ни в одном из своих пакетов.

Использование deprecate <options rootVolumeOnly="true"/> даст вам старую <options rootVolumeOnly="true"/> назначения. Example showing old Destination Select Pane


Вы хотите установить элементы в домашнюю папку текущих пользователей.

Краткий ответ: НЕ ПЫТАЙТЕСЬ!

Длинный ответ: ДЕЙСТВИТЕЛЬНО; НЕ ПЫТАЙТЕСЬ! Читайте установщик проблемы и решения. Вы знаете, что я сделал даже после прочтения этого? Я был достаточно глуп, чтобы попробовать это. Говоря себе, я уверен, что они исправили проблемы в 10.7 или 10.8.

Прежде всего, я видел время от времени вышеупомянутую ошибку выбора пункта назначения. Это должно было остановить меня, но я проигнорировал это. Если вы не хотите тратить неделю после того, как выпустили свое программное обеспечение, отвечая на электронные письма поддержки, на которые они должны щелкнуть, как только появится приятный синий значок, НЕ используйте это.

Вы сейчас думаете, что ваши пользователи достаточно умны, чтобы понять панель, не так ли? Ну вот еще одна вещь об установке домашней папки, они не работают!

Я тестировал его в течение двух недель примерно на 10 разных машинах с разными версиями ОС, а что нет, и никогда не подводил. Поэтому я отправил это. В течение часа после релиза я возвращаюсь к пользователям, которые просто не смогли его установить. Журналы намекают на проблемы с разрешениями, которые вы не сможете исправить.

Итак, позвольте повторить это еще раз: мы не используем установщик для установки домашней папки!


RTFD для Welcome, Read-me, License и Заключения не принимается productbuild.

Установщик поддерживал с самого начала файлы RTFD для создания симпатичных экранов приветствия с изображениями, но productbuild их не принимает.

Обходные пути: используйте фиктивный rtf файл и замените его в пакете после завершения productbuild.

Примечание: вы также можете иметь изображения Retina внутри файла RTFD. Для этого используйте 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

Важно запускать приложение как зарегистрированный пользователь, а не как пользователь установщика. Это делается с помощью пути запуска launchctl asuser. Также мы запускаем его только тогда, когда это не установка из командной строки, выполняемая с помощью инструмента установки или удаленного рабочего стола Apple.


Ответ 2

Существует одно очень интересное приложение Stéphane Sudre, которое делает все это для вас, является сценарием/поддерживает создание из командной строки, имеет великолепный графический интерфейс и БЕСПЛАТНО. Грустная вещь: она называется "Пакеты", что делает невозможным найти в google.

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

Мне жаль, что я не знал об этом, прежде чем начал писать собственные сценарии.

Packages application screenshot

Ответ 3

Вот сборка 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

Ответ 4

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 разных виртуальных машинах, которые я пробовал.

Ответ 5

FYI для тех, кто пытается создать установщик пакетов для пакета или плагина, легко:

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