Создание пакетов установщика macOS с идентификатором разработчика

189

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

Из-за привратника Mountain Lion мне наконец-то пришлось взять сценарий сборки PackageMaker за сараем и снять его. PackageMaker уже удален из XCode и перемещен в «Вспомогательные инструменты для XCode», так что, надеюсь, он скоро будет забыт.

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

catlan
источник
поэтому я предполагаю, что проблема с packagemaker заключается в невозможности правильно подписать pkg-файлы для использования с привратником в Mountain Lion?
JasonZ
1
Это возможно, но PackageMaker всегда был с ошибками, и был признан устаревшим с Mac OS X 10.6 Snow Leopard. В конечном итоге это сэкономит ваше время, чтобы просто ознакомиться с новыми инструментами.
Catlan
@catlan: У вас есть официальная ссылка, которая гласит, что на 10.6 устарел производитель пакетов?
Карл
2
@carleeto: Он никогда не объявлялся устаревшим, просто удалялся из Xcode и в конечном итоге «исчезал», как бирманский протестующий.
ошибка
5
Замечания к выпуску Xcode 4.6: Устаревшее создание
catlan

Ответы:

344

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

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

Наши инструменты: 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, нет причин подписывать пакеты компонентов .

Утилита Сертификата Разработчика

Полностью: скопируйте пакет в архив 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 .


катлан
источник
9
Это отличный учебник, но предполагает наличие сборных комплектов. Если бы я, например, должен был установить один файл /tmpдля последующей обработки в сценарии после полета, как мне структурировать список компонентов? Вся доступная документация предполагает, что разработчик сгенерировал ее --analyze, по крайней мере, на начальном этапе.
ошибка
1
Если вам не нужно ничего менять, Component Property Listвам не нужно запускаться --analyze. Для файлов постобработки я предлагаю поместить их все в файл pkg и установить в качестве места установки pkg /tmp. Но, возможно, я неправильно понял ваш вопрос. Если это так, опубликуйте его в более подробной версии на SO.
catlan
2
Обратите внимание, что нет никакого смысла создавать пакеты через командную строку, пытаясь избежать всех ошибок в приложении упаковки. Скорее смотрите мой комментарий ниже об использовании приложения «Пакеты» от Стефана Судре, которое решает все проблемы для вас!
Брам де Йонг
5
@BramdeJong "не имеет смысла". Я не согласен. Apple поддерживает инструменты командной строки. Пакеты - это стороннее приложение, которое не поддерживается сообществом и может сломаться в будущем, если Apple что-то изменит. Для меня, я бы предпочел знать технику командной строки, чтобы, если Apple что-то изменило, я мог продолжать работать.
Volomike
5
$ pkgbuild --root ./HelloWorld.app не так (при условии, что .app является фактическим пакетом приложения). pkgbuild работает с целевым корнем: папкой, которая содержит пакет, сгенерированный цепочкой инструментов xcode. Таким образом, аргумент pkgbuild - это путь к папке, содержащей пакет, который мы хотим упаковать. Неправильное получение этого права приводит к пакету, который содержит только папку содержимого приложения. Он не будет установлен как фактический пакет приложений. Дешевая распродажа находится в списке компонентов. Если в нем нет записи RootRelativeBundlePath, указывающей комплект приложений, значит, вы облажались.
Джонатан Митчелл
185

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

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

Я хотел знать об этом до того, как начал создавать свои собственные сценарии.

Скриншот приложения пакетов

Брам де Йонг
источник
11
Я не могу поверить, что этот пост не имеет больше смысла. Это программное обеспечение удивительно и поддерживает сборку из командной строки.
Сезар Мендоса
1
Кто-нибудь пытался подписать пакет этим инструментом? Мне не удается активировать пункт меню «Установить сертификат» ....
GTAE86
2
@ user283182: Очень поздно, конечно, вы уже поняли это, но, возможно, это поможет другим - я думаю, что проблема, с которой вы столкнулись, подробно описана в [Руководстве по обзору Mac App Store] ( developer.apple.com/app- store / review / Guidelines / Mac /… ), правило 2.14: «Приложения должны быть упакованы и представлены с использованием технологий упаковки Apple, включенных в XCode - сторонние установщики не допускаются».
старший старший
4
Я хотел бы, чтобы это было платное приложение, и разработчик постоянно обновляет и исправляет. Packages.app - это здорово, особенно если вы хотите быстро развернуть свое приложение. Мне потребовалось всего 3 минуты, чтобы установить, прочитать обзор, настроить мой проект и создать устанавливаемый пакет. Слава Стефану.
Николай Христов
1
Это приложение потрясающе!
Спенсер Мюллер Диниз
3

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

pkgbuild --component "Color Lists.colorPicker" --install-location ~/Library/ColorPickers ColorLists.pkg
gngrwzrd
источник
2
Кстати, есть разница между созданием .pkg и созданием настоящего установщика с экраном приветствия, лицензией и так далее.
катлан
да, я знаю, я поместил это здесь, потому что я не мог найти ссылку на создание установщика pkg для плагина.
gngrwzrd
Это заставило меня прокатиться. Просто минимум, чтобы дать заземление.
Учуугака
3

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

PnotNP
источник
Это работает хорошо, но с GOT'CHA: если вы сначала устанавливаете для каждого пользователя, а затем для каждой машины, установка будет в пользовательском каталоге, а не в машинном, но с правами sudo. Дело не в обратном: вы можете установить для каждого компьютера, а затем для каждого пользователя и иметь его в обоих местах.
Терье Дал
@TerjeDahl да, это потому, что после установки пакет перемещается в то же местоположение, что и идентификатор пакета, который был установлен ранее установщиком (и установщик это знает). Это может быть предотвращено некоторыми настройками в файле манифеста, которые я сейчас не помню.
PnotNP
@ PnotNP Ах. Если бы вы были так любезны, чтобы вернуться с этими настройками, если бы вы могли вспомнить, то это было бы здорово!
Терье Даля
2

Вот скрипт сборки, который создает подписанный установочный пакет из корня сборки.

#!/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
Даг Ричардсон
источник
1
Да, pkgbuild создает установщик .pkg.
Даг Ричардсон