Nasz przykładowy projekt ma dwa cele kompilacji: HelloWorld.app i Helper.app. Dla każdego tworzymy pakiet komponentów i łączymy je w archiwum produktów .
Pakiet komponent zawiera ładowność być zainstalowany przez OS X Installer. Chociaż pakiet składników można zainstalować samodzielnie, zazwyczaj jest on dołączany do archiwum produktów .
Po udanym „budowaniu i archiwizowaniu” 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 listę komponentów, opis wartości znajdziesz w sekcji „Lista właściwości komponentów” . pkgbuild -root generuje pakiety składników , jeśli nie musisz zmieniać żadnych domyślnych właściwości, możesz pominąć parametr --component-plist w następującym poleceniu.
budowanie produktu - synteza wyników w definicji rozkładu .
$ 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 pliku Distribution.xml możesz zmieniać takie elementy, jak tytuł, tło, powitanie, plik readme, licencja i tak dalej. Za pomocą tego polecenia zamieniasz pakiety komponentów i definicję dystrybucji w archiwum produktu :
$ productbuild --distribution ./Distribution.xml \
--package-path . \
./Installer.pkg
Polecam zajrzeć do iTunes Installers Distribution.xml, aby zobaczyć, co jest możliwe. Możesz wyodrębnić „Zainstaluj iTunes.pkg” za pomocą:
$ pkgutil --expand "Install iTunes.pkg" "Install iTunes"
Złóżmy to razem
Zwykle w moim projekcie jest folder o nazwie Pakiet, który zawiera między innymi Distribution.xml, listy komponentów, zasoby i skrypty.
Dodaj fazę kompilacji skryptu uruchamiania o nazwie „Generuj pakiet”, 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 za pomocą buildbuild, możesz pozbyć się kroków pkgutil --expand
i pkgutil --flatten
kroków. Również można użyć --sign paramenter na productbuild zamiast prowadzenia productsign .
Podpisz instalatora OS X
Pakiety są podpisane certyfikatem instalatora ID dewelopera, który można pobrać z Narzędzia certyfikatu programisty .
Podpisywanie odbywa się za pomocą --sign "Developer ID Installer: John Doe"
parametru pkgbuild , build produktu lub znak produktu .
Pamiętaj, że jeśli zamierzasz utworzyć podpisane archiwum produktów przy użyciu programu buildbuild, nie ma powodu, aby podpisywać pakiety komponentów .
Całą drogę: Skopiuj pakiet do archiwum Xcode
Aby skopiować coś do Archiwum Xcode, nie możemy użyć fazy kompilacji skryptu Run . W tym celu musimy użyć akcji programu.
Edytuj schemat i rozwiń Archiwum. Następnie kliknij czynności po i dodaj nową akcję Uruchom skrypt :
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 PKG
zamiast:
PKG="${OBJROOT}/ArchiveIntermediates/${TARGET_NAME}/BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"
W przypadku, gdy twoja kontrola wersji nie przechowuje informacji o Xcode Scheme, sugeruję dodać to jako skrypt powłoki do twojego projektu, abyś mógł łatwo przywrócić akcję, przeciągając skrypt z obszaru roboczego do post-action.
Skrypty
Istnieją dwa różne rodzaje skryptów: JavaScript w plikach definicji dystrybucji i skrypty powłoki.
Najlepsza dokumentacja dotycząca skryptów powłoki, którą znalazłam w WhiteBox - PackageMaker - instrukcje , ale przeczytaj ją ostrożnie, ponieważ odnosi się do starego formatu pakietu.
Dodatkowe czytanie
Znane problemy i obejścia
Miejsce docelowe Wybierz okienko
Użytkownik otrzymuje opcję wyboru miejsca docelowego z jednym wyborem - „Zainstaluj dla wszystkich użytkowników tego komputera”. Opcja pojawia się wizualnie wybrana, ale użytkownik musi ją kliknąć, aby kontynuować instalację, powodując pewne zamieszanie.
Dokumentacja jabłek zaleca użycie, <domains enable_anywhere ... />
ale powoduje to pojawienie się nowego, bardziej błędnego okienka wyboru miejsca docelowego, którego Apple nie używa w żadnym ze swoich pakietów.
Używając przestarzałych, <options rootVolumeOnly="true" />
otrzymujesz stare okienko wyboru miejsca docelowego.
Chcesz zainstalować elementy w folderze domowym bieżącego użytkownika.
Krótka odpowiedź: NIE WYPRÓBUJ GO!
Długa odpowiedź: NAPRAWDĘ; NIE WYPRÓBUJ GO! Przeczytaj Problemy i rozwiązania instalatora . Wiesz co zrobiłem nawet po przeczytaniu tego? Byłem na tyle głupi, żeby tego spróbować. Mówiąc sobie, jestem pewien, że rozwiązali problemy w wersji 10.7 lub 10.8.
Przede wszystkim widziałem od czasu do czasu wspomniany wyżej błąd okienka wyboru miejsca docelowego. To powinno mnie zatrzymać, ale zignorowałem to. Jeśli nie chcesz spędzić tygodnia po wydaniu oprogramowania, odpowiadając na e-maile dotyczące pomocy technicznej, które muszą kliknąć raz po ładnym niebieskim zaznaczeniu NIE używaj tego.
Myślisz teraz, że Twoi użytkownicy są wystarczająco inteligentni, aby wymyślić panel, prawda? Cóż, oto kolejna rzecz dotycząca instalacji folderów domowych, NIE DZIAŁAJĄ!
Testowałem go przez dwa tygodnie na około 10 różnych maszynach z różnymi wersjami systemu operacyjnego, a co nie, i nigdy nie zawiodło. Więc wysłałem to. W ciągu godziny od premiery przesyłam serdecznie użytkownikom, 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 for Welcome, Read-me, License and Concellation nie jest akceptowane przez productbuild
.
Instalator od początku obsługiwał pliki RTFD, aby tworzyć ładne ekrany powitalne z obrazami, ale buildbuild produktu ich nie akceptuje.
Obejścia: Użyj fikcyjnego pliku rtf i zamień go w pakiecie po zakończeniu productbuild
.
Uwaga: W pliku RTFD można również umieszczać obrazy Retina. Użyj tiff wielu obrazów na to: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif
. Więcej szczegółów .
Uruchamianie aplikacji po zakończeniu instalacji 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 użytkownik zalogowany, a nie jako użytkownik instalatora. Odbywa się to za pomocą ścieżki identyfikatora użytkownika launchctl asuser . Ponadto uruchamiamy go tylko wtedy, gdy nie jest to instalacja z poziomu wiersza poleceń, wykonana za pomocą narzędzia instalacyjnego lub Apple Remote Desktop .