Наш пример проекта имеет две цели сборки: HelloWorld.app и Helper.app. Мы создаем пакет компонентов для каждого и объединяем их в архив продукта .
Компонент пакета содержит полезную нагрузку для установки на OS X Installer. Хотя пакет компонентов может быть установлен сам по себе, он обычно включается в архив продукта .
После успешной «сборки и архивирования» откройте $ 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, нет причин подписывать пакеты компонентов .
Полностью: скопируйте пакет в архив 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 , но прочитайте это с осторожностью, потому что это относится к старому формату пакета.
Дополнительное Чтение
Известные проблемы и обходные пути
Панель выбора места назначения
Пользователю предоставляется опция выбора места назначения с единственным выбором - «Установить для всех пользователей этого компьютера». Опция отображается визуально, но пользователю необходимо нажать на нее, чтобы продолжить установку, что вызывает некоторую путаницу.
Документация Apple рекомендует использовать <domains enable_anywhere ... />
но при этом запускается новая, более глючная панель выбора места назначения, которую Apple не использует ни в одном из своих пакетов.
Использование устаревшего <options rootVolumeOnly="true" />
даст вам старую панель выбора места назначения.
Вы хотите установить элементы в домашнюю папку текущего пользователя.
Краткий ответ: НЕ ПЫТАЙТЕСЬ!
Длинный ответ: ДЕЙСТВИТЕЛЬНО; НЕ ПЫТАЙТЕСЬ! Читайте установщик проблемы и решения . Вы знаете, что я сделал даже после прочтения этого? Я был достаточно глуп, чтобы попробовать это. Говоря себе, я уверен, что они исправили проблемы в 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 Remote Desktop .