web-dev-qa-db-fra.com

Préparer des packages d’installateur OS X comme un paquet Pro - Xcode Developer ID

Remarque: ceci concerne uniquement les packages programme d'installation OS X , les packages à soumettre au Mac App Store suivent des règles différentes.

À cause de Mountain Lion Gatekeeper , j'ai finalement dû prendre mon script PackageMaker construire derrière la grange et le filmer. PackageMaker a déjà été supprimé de Xcode et déplacé dans "Outils auxiliaires pour Xcode", alors espérons-le, il sera bientôt oublié.

La question est de savoir comment utiliser pkgbuild, productbuild et pkgutil pour le remplacer.

175
catlan

Notre exemple de projet a deux cibles de construction: HelloWorld.app et Helper.app. Nous fabriquons un package de composants pour chacun et les combinons dans une archive de produit .

Un package de composant contient la charge utile à installer par le programme d'installation OS X. Bien qu'un package de composant puisse être installé seul, il est généralement incorporé dans une archive de produit .

Nos outils: pkgbuild , productbuild , et pkgutil

Après un "Build and Archive" réussi, ouvrez $ BUILT_PRODUCTS_DIR dans le terminal.

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

Cela nous donne le composant-plist, vous trouvez la description de la valeur dans la section "Liste des propriétés du composant" . pkgbuild -root génère les packages de composant , si vous n'en avez pas besoin. Pour modifier les propriétés par défaut, vous pouvez omettre le paramètre - composant-plist dans la commande suivante.

productbuild --synthesize résulte en un définition de la distribution .

$ 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 

Dans Distribution.xml , vous pouvez modifier des éléments tels que le titre, l’arrière-plan, la bienvenue, le fichier Lisez-moi, la licence, etc. Vous transformez votre package packages de composants et votre définition de distribution avec cette commande en une archive de produit :

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

Je recommande de jeter un oeil sur installateurs iTunes Distribution.xml pour voir ce qui est possible. Vous pouvez extraire "Installer iTunes.pkg" avec:

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

Permet de le mettre ensemble

J'ai généralement un dossier nommé Package dans mon projet qui comprend des éléments tels que Distribution.xml, des composants, des ressources et des scripts.

Ajoutez une phase de construction du script d’exécution nommée "Générer le package", définie sur . Exécuter le script uniquement lors de l’installation :

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

Si vous n'avez pas à changer le paquet après l'avoir généré avec productbuild , vous pouvez vous débarrasser de pkgutil --expand et pkgutil --flatten. pas. Vous pouvez aussi utiliser le paramètre - signe sur productbuild au lieu de fonctionner productsign .

Signer un programme d'installation OS X

Les packages sont signés avec le certificat Developer ID Installer que vous pouvez télécharger à partir de Developer Certificate Utility .

La signature se fait avec le paramètre --sign "Developer ID Installer: John Doe" de pkgbuild , productbuild ou productsign .

Notez que si vous allez créer une archive de produit signée à l'aide de productbuild, il n'y a aucune raison de signer le composant . forfaits .

Developer Certificate Utility

Tout le chemin: copier le paquet dans l'archive Xcode

Pour copier quelque chose dans l’archive Xcode, nous ne pouvons pas utiliser la phase de construction du script d’exécution . Pour cela, nous devons utiliser une action de schéma.

Editez le schéma et développez Archive. Cliquez ensuite sur post-actions et ajoutez une nouvelle action de script d'exécution :

Dans 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

Dans Xcode 5, utilisez cette valeur pour PKG à la place:

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

Si votre contrôle de version ne stocke pas les informations du schéma Xcode, je suggère de l'ajouter en tant que script Shell à votre projet afin que vous puissiez simplement restaurer l'action en faisant glisser le script de l'espace de travail dans la post-action.

Scripting

Il existe deux types de script différents: JavaScript dans les fichiers de définition de distribution et les scripts shell.

La meilleure documentation sur les scripts Shell que j'ai trouvée dans WhiteBox - PackageMaker - Comment faire , mais lisez-la avec prudence, car elle fait référence à l'ancien format de package.

Lecture supplémentaire

Problèmes connus et solutions de contournement

Volet Sélectionner une destination

L'utilisateur est présenté avec l'option de sélection de destination avec un seul choix - "Installer pour tous les utilisateurs de cet ordinateur". L'option apparaît visuellement sélectionnée, mais l'utilisateur doit cliquer dessus pour procéder à l'installation, ce qui crée une certaine confusion.

Example showing the installer bug

Apples Documentation recommande d'utiliser <domains enable_anywhere ... />, mais cela déclenche le nouveau volet de sélection de destination plus bogué que Apple n'utilise dans aucun de leurs packages.

L'utilisation de la commande obsolète <options rootVolumeOnly="true" /> vous permet d'accéder à l'ancien volet de sélection de la destination. Example showing old Destination Select Pane


Vous souhaitez installer des éléments dans le dossier personnel de l’utilisateur actuel.

Réponse courte: NE PAS ESSAYER!

Réponse longue: VRAIMENT; NE PAS ESSAYER! Lire Problèmes d'installation et solutions . Tu sais ce que j'ai fait même après avoir lu ça? J'ai été assez stupide pour l'essayer. En me disant que je suis sûr qu'ils ont résolu les problèmes en 10.7 ou 10.8.

Tout d’abord, j’ai vu de temps en temps le bogue du volet de sélection de la destination mentionné ci-dessus. Cela aurait dû m'arrêter, mais je l'ai ignoré. Si vous ne souhaitez pas passer la semaine après la publication de votre logiciel, il doit cliquer sur les courriers d’assistance technique une fois que la sélection Nice en bleu n’EST PAS utilisée.

Vous pensez maintenant que vos utilisateurs sont suffisamment intelligents pour comprendre le panneau, n'est-ce pas? Eh bien, voici une autre chose à propos de l’installation du dossier personnel: ils ne fonctionnent pas!

Je l'ai testé pendant deux semaines sur environ 10 machines différentes avec des versions de système d'exploitation différentes et non, et cela n'a jamais échoué. Alors je l'ai expédié. Moins d'une heure après sa publication, je suis de retour des utilisateurs qui ne pouvaient tout simplement pas l'installer. Les journaux suggéraient des problèmes d’autorisation que vous ne pourrez pas résoudre.

Répétons-le encore une fois: nous n’utilisons pas le programme d’installation pour les installations de dossiers personnels!


RTFD pour Welcome, Read-me, Licence et Conclusion n'est pas accepté par productbuild.

Programme d'installation pris en charge depuis le début Les fichiers RTFD permettent de créer de jolis écrans de bienvenue avec des images, mais productbuild ne les accepte pas.

Solutions de contournement: utilisez un fichier rtf factice et remplacez-le dans le package après productbuild.

Remarque: vous pouvez également avoir des images Retina dans le fichier RTFD. Utilisez des fichiers TIFF multi-images pour cela: tiffutil -cat Welcome.tif Welcome_2x.tif -out FinalWelcome.tif. Plus détails .


Démarrage d'une application lorsque l'installation est terminée avec un 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

Il est important d'exécuter l'application en tant qu'utilisateur connecté et non en tant qu'utilisateur du programme d'installation. Ceci est fait avec launchctl comme chemin d'utilisateur . De plus, nous ne l'exécutons que lorsqu'il ne s'agit pas d'une installation en ligne de commande, effectuée avec l'outil du programme d'installation ou Apple Remote Desktop .


317
catlan

Il existe une application très intéressante de Stéphane Sudre qui fait tout cela pour vous, est scriptable/prend en charge la construction depuis la ligne de commande, possède une superbe interface graphique et est GRATUITE. Ce qui est triste, c’est que cela s’appelle "Packages", ce qui le rend impossible à trouver dans Google.

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

J'aurais aimé le savoir avant de commencer à créer mes propres scripts.

Packages application screenshot

179
Bram de Jong

Un +1 à la réponse acceptée:

Sélection de la destination dans l'installateur

Si la sélection de domaine (destination a.k.a) est souhaitée entre le domaine utilisateur et le domaine système, alors plutôt que d'essayer <domains enable_anywhere="true">, utilisez ce qui suit:

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

enable_currentUserHome installe l'application sous ~/Applications/ et enable_localSystem permet à l'application d'être installée sous /Application

J'ai essayé ceci dans El Capitan 10.11.6 (15G1217) et il semble fonctionner parfaitement dans 1 machine de développement et 2 machines virtuelles différentes que j'ai essayées.

3
PnotNP

Voici un script de construction qui crée un paquet d'installation signé à partir d'une racine de construction.

#!/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
3
Doug Richardson

Pour votre information, ceux qui essaient de créer un programme d’installation de paquet pour un bundle ou un plugin, c’est simple:

pkgbuild --component "Color Lists.colorPicker" --install-location ~/Library/ColorPickers ColorLists.pkg
2
gngrwzrd