Il nostro progetto di esempio ha due target di build: HelloWorld.app e Helper.app. Realizziamo un pacchetto di componenti per ciascuno e li combiniamo in un archivio prodotti .
Un pacchetto di componenti contiene payload che deve essere installato dal programma di installazione di OS X. Sebbene un pacchetto di componenti possa essere installato da solo, in genere è incorporato in un archivio prodotti .
Dopo un "Build and Archive" riuscito apri $ BUILT_PRODUCTS_DIR nel Terminale.
$ cd ~/Library/Developer/Xcode/DerivedData/.../InstallationBuildProductsLocation
$ pkgbuild --analyze --root ./HelloWorld.app HelloWorldAppComponents.plist
$ pkgbuild --analyze --root ./Helper.app HelperAppComponents.plist
Questo ci dà la lista dei componenti, puoi trovare la descrizione del valore nella sezione "Elenco delle proprietà dei componenti" . pkgbuild -root genera i pacchetti dei componenti , se non è necessario modificare nessuna delle proprietà predefinite è possibile omettere il parametro --component-plist nel comando seguente.
productbuild --synthesize risulta in una definizione di distribuzione .
$ 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
In Distribution.xml puoi cambiare cose come titolo, sfondo, benvenuto, readme, licenza e così via. Trasforma i pacchetti dei componenti e la definizione di distribuzione con questo comando in un archivio prodotti :
$ productbuild --distribution ./Distribution.xml \
--package-path . \
./Installer.pkg
Consiglio di dare un'occhiata a iTunes Installers Distribution.xml per vedere cosa è possibile. Puoi estrarre "Installa iTunes.pkg" con:
$ pkgutil --expand "Install iTunes.pkg" "Install iTunes"
Mettiamolo insieme
Di solito ho una cartella chiamata Package nel mio progetto che include cose come Distribution.xml, componenti, risorse e script.
Aggiungi una fase di costruzione dello script Run denominata "Genera pacchetto", che è impostata su Esegui script solo durante l'installazione :
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}"
Se non è necessario modificare il pacchetto dopo che è stato generato con productbuild, è possibile eliminare i passaggi pkgutil --expand
e pkgutil --flatten
. Inoltre è possibile utilizzare il --sign paramenter su productbuild invece di correre productsign .
Firma un programma di installazione di OS X.
I pacchetti sono firmati con il certificato Installer ID sviluppatore che è possibile scaricare dall'Utilità certificato sviluppatore .
La firma viene eseguita con il --sign "Developer ID Installer: John Doe"
parametro di pkgbuild , productbuild o productsign .
Si noti che se si intende creare un archivio prodotti firmato utilizzando productbuild, non vi è alcun motivo per firmare i pacchetti dei componenti .
Completamente: copia il pacchetto in Xcode Archive
Per copiare qualcosa nell'archivio Xcode non possiamo usare la fase di costruzione Run Script . Per questo abbiamo bisogno di usare un'azione Scheme.
Modifica schema ed espandi Archivio. Quindi fare clic su post-azioni e aggiungere una nuova azione Script di esecuzione :
In 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
In Xcode 5, utilizzare invece questo valore per PKG
:
PKG="${OBJROOT}/ArchiveIntermediates/${TARGET_NAME}/BuildProductsPath/${CONFIGURATION}/${ARCHIVE_FILENAME}"
Nel caso in cui il controllo della versione non memorizzi le informazioni sullo schema Xcode, suggerisco di aggiungerlo come script shell al progetto in modo da poter ripristinare semplicemente l'azione trascinando lo script dallo spazio di lavoro in post-azione.
Scripting
Esistono due diversi tipi di script: JavaScript nei file di definizione della distribuzione e Script di shell.
La migliore documentazione sugli script Shell che ho trovato in WhiteBox - Come fare PackageMaker , ma leggi questo con cautela perché si riferisce al vecchio formato del pacchetto.
Letture aggiuntive
Problemi noti e soluzioni alternative
Riquadro di selezione della destinazione
All'utente viene presentata l'opzione di selezione della destinazione con una sola scelta: "Installa per tutti gli utenti di questo computer". L'opzione appare visivamente selezionata, ma l'utente deve fare clic su di essa per procedere con l'installazione, creando confusione.
La documentazione sulle mele consiglia di utilizzare, <domains enable_anywhere ... />
ma ciò innesca il nuovo riquadro di selezione della destinazione più difettoso che Apple non utilizza in nessuno dei loro pacchetti.
L'utilizzo del deprecato <options rootVolumeOnly="true" />
fornisce il riquadro di selezione della destinazione precedente.
Si desidera installare elementi nella cartella principale dell'utente corrente.
Risposta breve: NON PROVARLO!
Risposta lunga: DAVVERO; NON PROVARLO! Leggi i problemi e le soluzioni dell'installatore . Sai cosa ho fatto anche dopo aver letto questo? Sono stato abbastanza stupido da provarlo. Mi dico che sono sicuro che hanno risolto i problemi in 10.7 o 10.8.
Prima di tutto ho visto di tanto in tanto il suddetto errore nel riquadro di selezione della destinazione. Ciò avrebbe dovuto fermarmi, ma l'ho ignorato. Se non vuoi passare la settimana dopo aver rilasciato il tuo software rispondendo alle e-mail di supporto che devono fare clic una volta che la bella selezione blu NON usa questo.
Ora stai pensando che i tuoi utenti siano abbastanza intelligenti da capire il pannello, vero? Bene, ecco un'altra cosa sull'installazione della cartella home, NON FUNZIONANO!
L'ho provato per due settimane su circa 10 macchine diverse con diverse versioni del sistema operativo e cosa no, e non ha mai fallito. Quindi l'ho spedito. Entro un'ora dal rilascio rincuoro gli utenti che non sono riusciti a installarlo. I registri suggeriscono problemi di autorizzazione che non sarai in grado di risolvere.
Ripetiamolo ancora una volta: non utilizziamo l'Installer per le installazioni di cartelle home!
RTFD per Benvenuto, Leggimi, Licenza e Conclusione non è accettato da productbuild
.
Programma di installazione supportato sin dall'inizio file RTFD per creare schermate di benvenuto con immagini, ma productbuild non le accetta.
Soluzioni alternative: utilizzare un file rtf fittizio e sostituirlo nel pacchetto dopo aver terminato productbuild
.
Nota: è anche possibile avere immagini Retina all'interno del file RTFD. Utilizzare file tiff multi-immagine per questo: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif
. Maggiori dettagli .
Avvio di un'applicazione al termine dell'installazione con uno script 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
È importante eseguire l'app come utente connesso, non come utente del programma di installazione. Questo viene fatto con launchctl asuser uid path . Inoltre lo eseguiamo solo quando non è un'installazione da riga di comando, eseguita con lo strumento di installazione o Apple Remote Desktop .