Tworzenie pakietów instalatora OS X takich jak Pro-Xcode Developer id ready pkg

Uwaga: dotyczy to tylko pakietów instalatora OS X, pakiety do przesłania do Mac App Store obowiązują inne zasady.

Z powodu strażnika Mountain Lion ' s W końcu musiałem wziąć mój PackageMaker zbudować skrypt za stodołą i go zastrzelić. PackageMaker został już usunięty z Xcode i przeniesiony do "narzędzia pomocnicze dla Xcode", więc mam nadzieję, że wkrótce zostanie zapomniany.

Pytanie brzmi jak używać pkgbuild, productbuild, i pkgutil do wymienić?

Author: Shaun Wilson, 2012-07-15

5 answers

Nasz przykładowy projekt ma dwa cele: HelloWorld. aplikacja i Pomocnik.app. Tworzymy pakiet komponentów dla każdego i łączymy je w Archiwum produktów.

A component package zawiera ładunek do zainstalowania przez instalator OS X. Chociaż element pakiet może być zainstalowany samodzielnie, zazwyczaj jest wbudowany w Archiwum produktów .

Nasze narzędzia: pkgbuild, productbuild , oraz pkgutil

Po pomyślnym "Build and Archive" otwórz $BUILT_PRODUCTS_DIR w Terminalu.

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

To daje nam component-plist, opis wartości znajdziesz w "Component Property List" sekcja. pkgbuild-root generuje Pakiety komponentów, jeśli nie musisz zmieniać żadnej z domyślnych właściwości, możesz pominąć parametr --component-plist w następujący sposób dowództwo.

productbuild --synteza daje definicję dystrybucji .

$ 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 

W dystrybucji .xml możesz zmieniać takie rzeczy jak tytuł, tło, powitanie, readme, licencja i tak dalej. Zmieniasz swoje Pakiety komponentów i definicję dystrybucji za pomocą tego polecenia w Archiwum produktów :

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

Polecam przyjrzeć się instalatorom iTunes dystrybucji.xml, aby zobaczyć, co jest możliwe. Możesz wyodrębnić " zainstaluj iTunes.pkg " z:

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

Lets put it together

W moim projekcie zazwyczaj mam folder o nazwie pakiet, który zawiera takie rzeczy jak dystrybucja.xml, component-plisty, zasoby i skrypty.

Dodaj Run script Build Phase o nazwie "Generate Package", która jest ustawiona na Uruchom skrypt tylko podczas instalacji :

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

Jeśli nie musisz zmieniać pakietu po jego wygenerowaniu z productbuild możesz pozbądź się pkgutil --expand i pkgutil --flatten kroków. Możesz również użyć --sign paramenter na productbuild zamiast uruchamiać productsign.

Podpisz instalator OS X

Pakiety są podpisane certyfikatem Developer ID Installer , który można pobrać z Developer Certificate Utility.

Podpisywanie odbywa się za pomocą --sign "Developer ID Installer: John Doe" parametru pkgbuild, productbuild lub productsign .

Zauważ, że jeśli zamierzasz utworzyć podpisane Archiwum produktów przy użyciu productbuild, nie ma powodu, aby podpisywać Pakiety komponentów.

Developer Certificate Utility

Do końca: skopiuj pakiet do archiwum Xcode

Aby skopiować coś do archiwum Xcode nie możemy użyć Run Script Build Phase. W tym celu musimy użyć działania schematu.

Edycja schematu i rozszerzenie Archiwum. Następnie kliknij post-akcje i dodaj a Nowa Akcja Run Script :

W 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

W Xcode 5 Użyj tej wartości dla PKG zamiast:

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

W przypadku, gdy kontrola wersji nie przechowuje informacji o schemacie Xcode proponuję dodać to jako skrypt powłoki do projektu, dzięki czemu można łatwo przywrócić akcję, przeciągając skrypt z obszaru roboczego do post-akcji.

Skrypty

Istnieją dwa różne rodzaje skryptów: JavaScript w definicji dystrybucji Pliki i skrypty powłoki.

Najlepsza dokumentacja o skryptach powłoki, jaką znalazłem w WHITEBOX-Packagemaker How-to, ale przeczytaj to z ostrożnością, ponieważ odnosi się to do starego formatu pakietów.

Dodatkowe Czytanie

Znane problemy i obejścia

Cel Wybierz Panel

Uĺźytkownik ma opcjÄ ™ destination select z jednym wyborem - "zainstaluj dla wszystkich uĹźytkownikĂłw tego komputera". Opcja pojawia się wizualnie wybrana, ale użytkownik musi kliknąć na nią, aby kontynuować instalację, powodując pewne zamieszanie.

Przykład pokazujący błąd instalatora

Apples Documentation zaleca użycie <domains enable_anywhere ... /> ale to wyzwala nowe więcej wadliwe okienko wyboru miejsca docelowego, którego Apple nie używa w żadnym z pakietów.

Użycie przestarzałego <options rootVolumeOnly="true" /> daje stary panel wyboru miejsca docelowego. Przykład pokazujący Stary panel wyboru miejsca docelowego


Chcesz zainstalować elementy w folderze domowym bieżącego użytkownika.

Krótka odpowiedź: nie próbuj!

[17]} długa odpowiedź: naprawdę; nie próbuj! Przeczytaj problemy i rozwiązania Instalatora . Wiesz, co zrobiłem nawet po przeczytaniu tego? Byłem na tyle głupi, żeby spróbować. Wmawiając sobie, że jestem pewien że naprawili problemy w 10.7 lub 10.8.

Przede wszystkim od czasu do czasu widziałem wyżej wspomniany błąd Destination Select Pane. To powinno mnie powstrzymać, ale zignorowałem to. Jeśli nie chcesz spędzić tydzień po wydaniu oprogramowania odpowiadając na e-maile wsparcia, które muszą kliknąć raz ładny niebieski wybór nie używaj tego.

Myślisz teraz, że Twoi użytkownicy są wystarczająco inteligentni, aby rozgryźć panel, prawda? Cóż, tu jest inna rzecz o domu instalacja folderów, nie działają!

Testowałem go przez dwa tygodnie na około 10 różnych maszynach z różnymi wersjami systemu operacyjnego i co nie, i nigdy nie zawiodło. Więc wysłałem go. W ciągu godziny od wydania odzyskałem serce od użytkowników, którzy po prostu nie mogli go zainstalować. Dzienniki wskazywały na problemy z uprawnieniami, których nie będziesz w stanie naprawić.

Powtórzmy to jeszcze raz: nie używamy Instalatora do instalacji folderów domowych!


RTFD na powitanie, Read-me, Licencja i wnioski nie są akceptowane przez productbuild.

Instalator od początku obsługiwał pliki RTFD, aby tworzyć ładne ekrany powitalne z obrazami, ale productbuild ich nie akceptuje.

Obejścia: Użyj atrapy pliku rtf i zastąp go w pakiecie przez po zakończeniu productbuild.

Uwaga: Możesz również mieć obrazy siatkówki wewnątrz pliku RTFD. Użyj do tego wielowarstwowych plików tiff: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif. Więcej szczegóły .


Uruchamianie aplikacji, gdy instalacja odbywa się za pomocą skryptu 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

Ważne jest, aby uruchomić aplikację jako zalogowany użytkownik, a nie jako użytkownik instalatora. Odbywa się to za pomocą ścieżki UID launchctl asuser. Ponadto uruchamiamy go tylko wtedy, gdy nie jest to instalacja wiersza poleceń, wykonywana za pomocą installer tool lub Apple Remote Desktop .


 298
Author: catlan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-25 19:48:26

Istnieje jedna bardzo ciekawa aplikacja Stéphane Sudre, która robi to wszystko za Ciebie, jest skryptowalna / wspiera budowanie z linii poleceń, ma super ładny GUI i jest darmowy. Smutne jest to, że nazywa się to "pakietami", co uniemożliwia znalezienie w google.

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

Żałuję, że nie wiedziałem o tym, zanim zacząłem tworzyć własne skrypty.

Zrzut ekranu aplikacji Packages

 174
Author: Bram de Jong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-06 15:45:34

Oto skrypt kompilacji , który tworzy podpisany pakiet instalatora z katalogu głównego kompilacji.

#!/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
 2
Author: Doug Richardson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-06 20:42:49

A +1 do zaakceptowanej odpowiedzi:

Wybór miejsca docelowego w Instalatorze

Jeśli pomiędzy domeną użytkownika a domeną systemową jest wymagana selekcja domeny (a.k.a destination), to zamiast próbować <domains enable_anywhere="true"> użyj następującego wzoru:

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

enable_currentUserHome instaluje aplikację pod ~/Applications/ i enable_localSystem pozwala zainstalować aplikację Pod /Application

[6]}próbowałem tego w El Capitan 10.11.6 (15g1217) i wydaje się, że działa idealnie w 1 dev maszynie i 2 próbowałem różnych maszyn wirtualnych.
 1
Author: PnotNP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-21 18:32:27

FYI dla tych, którzy próbują utworzyć Instalator pakietu dla pakietu lub wtyczki, to proste:

pkgbuild --component "Color Lists.colorPicker" --install-location ~/Library/ColorPickers ColorLists.pkg
 0
Author: gngrwzrd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-10 21:40:52