Créer un DMG macOS et vérifier l’installation de l’app

DevOps et CI/CD ·~6 min de lecture

Créer un DMG macOS et vérifier l’installation de l’app

La machine de build a déjà produit Example.app, et la tâche de publication a créé le DMG. Avant la livraison, trois points restent à vérifier : l’image montée contient-elle l’app complète et un raccourci vers « Applications » ? La signature de l’app reste-t-elle valide après copie ? L’installation par glisser-déposer fonctionne-t-elle dans l’interface graphique ? Voici comment rendre ces contrôles reproductibles. Dans les exemples, remplacez Example.app par le nom de votre app.

Définir d’abord ce qui doit être empaqueté

L’entrée doit être la version définitive du paquet de l’app. Commencez par fixer le chemin de l’artefact dans la tâche de build, vérifiez que l’exécutable de l’app existe et terminez la procédure de signature prévue. La création du DMG n’est pas l’occasion de retoucher le contenu de l’app : toute modification des ressources, des exécutables ou des composants intégrés risque d’invalider la signature existante.

Pour vérifier le répertoire, utilisez test -d plutôt que de vous contenter de rechercher un fichier du même nom. Assurez-vous également qu’aucun ancien DMG ne se trouve au chemin de sortie : un échec explicite est plus facile à diagnostiquer que l’écrasement silencieux de la livraison précédente. Si le pipeline relance des tâches, laissez-le nettoyer son propre répertoire de sortie au préalable, au lieu de demander au script d’empaquetage de supprimer des fichiers inconnus.

L’intégrité de l’image, la validité de la signature de l’app et la confiance que lui accorde le système sont trois conclusions distinctes. Réussir l’un de ces contrôles ne dispense pas des deux autres.

Créer une image avec un raccourci d’installation

Le script suivant prépare le contenu du volume dans un répertoire temporaire : il copie l’app signée et crée un lien symbolique vers /Applications. ditto sert à copier le paquet de l’app ; ne modifiez pas les fichiers du paquet après cette copie.

#!/bin/bash
set -euo pipefail

APP="$PWD/build/Release/Example.app"
OUT="$PWD/dist/Example.dmg"

test -d "$APP"
test -f "$APP/Contents/MacOS/Example"
mkdir -p "$(dirname "$OUT")"
test ! -e "$OUT"

work="$(mktemp -d "${TMPDIR:-/tmp}/dmg-build.XXXXXX")"
trap 'rm -rf "$work"' EXIT

stage="$work/stage"
mkdir -p "$stage"
ditto "$APP" "$stage/Example.app"
ln -s /Applications "$stage/Applications"

hdiutil create -volname "Example" \
  -srcfolder "$stage" -fs HFS+ -format UDZO "$OUT"

Si l’exécutable de l’app ne s’appelle pas Example, adaptez également le chemin vérifié. Le nom du volume est simplement celui que voit l’utilisateur après le montage ; il ne détermine pas où l’app sera installée. Séparer le répertoire temporaire de préparation du répertoire de sortie facilite le nettoyage à la fin du script et évite d’inclure par erreur une ancienne image dans la nouvelle.

Ce qui ne doit pas figurer sur le volume

Vérifiez d’abord la liste des éléments du répertoire de préparation : elle ne doit contenir que le paquet de l’app et le raccourci d’installation. Les journaux de build, les éléments utilisés pour la signature, les fichiers de débogage et le dépôt du projet ne doivent pas être livrés dans le DMG. Dans le script, stage est le seul répertoire d’entrée. Si vous ajoutez ensuite un fichier d’instructions, ajoutez-le et contrôlez-le explicitement plutôt que d’exécuter hdiutil create sur tout l’espace de travail.

Remonter l’image et vérifier le contenu réellement livré

Ne vous limitez pas au répertoire source : ouvrez le DMG que vous venez de créer. hdiutil verify contrôle l’image ; le script la monte ensuite en lecture seule, vérifie les chemins sur le volume, puis copie l’app dans un répertoire distinct et contrôle sa signature :

#!/bin/bash
set -euo pipefail

OUT="$PWD/dist/Example.dmg"
work="$(mktemp -d "${TMPDIR:-/tmp}/dmg-check.XXXXXX")"
mountpoint="$work/mount"
attached=0

cleanup() {
  if [ "$attached" -eq 1 ]; then
    hdiutil detach "$mountpoint" >/dev/null || true
  fi
  rm -rf "$work"
}
trap cleanup EXIT

mkdir -p "$mountpoint" "$work/installed"
hdiutil verify "$OUT"
hdiutil attach -readonly -nobrowse \
  -mountpoint "$mountpoint" "$OUT" >/dev/null
attached=1

test -d "$mountpoint/Example.app"
test -L "$mountpoint/Applications"
test "$(readlink "$mountpoint/Applications")" = /Applications

ditto "$mountpoint/Example.app" "$work/installed/Example.app"
codesign --verify --deep --strict \
  "$work/installed/Example.app"

Le script renvoie un code non nul en cas d’échec, ce qui permet de l’intégrer à la tâche de publication. Si le démontage échoue, vérifiez manuellement qu’aucun processus n’utilise encore le volume ; ne masquez pas cette occupation par un démontage forcé. codesign --verify contrôle que le paquet copié satisfait toujours aux exigences de signature, mais ne signifie pas que le système lui fait confiance. Si votre distribution externe prévoit une procédure de signature et de notarisation, vérifiez séparément le résultat de l’évaluation par le système selon cette procédure.

Reproduire le parcours utilisateur dans une session graphique

La ligne de commande permet de contrôler les chemins et la signature, mais pas de confirmer que la disposition des icônes est claire, que la destination du glisser-déposer est visible ou que le premier lancement se déroule sans incident. Ouvrez le DMG dans une session graphique macOS ouverte et suivez les étapes d’un utilisateur ordinaire :

  1. Vérifiez que le volume ne contient que l’app attendue et le raccourci « Applications », sans nom tronqué ni ambigu.
  2. Faites glisser l’app dans « Applications » et attendez la fin de la copie. Un lancement directement depuis le volume en lecture seule ne remplace pas un test d’installation.
  3. Lancez l’app copiée, puis vérifiez sa première fenêtre et les étapes nécessaires pour accéder aux fichiers.
  4. Démontez le volume et relancez l’app installée afin de vérifier qu’elle ne dépend plus de ressources présentes dans l’image.

Avant ce test, assurez-vous qu’aucune ancienne app du même nom ne se trouve à l’emplacement choisi, faute de quoi vous pourriez ouvrir la version installée précédemment. Vérifiez aussi le chemin avant de supprimer la copie de test pour ne pas effacer l’app utilisée au quotidien. Si aucune session graphique n’est disponible, indiquez « contrôles en ligne de commande réussis, validation graphique non effectuée » pour cette publication ; ne présentez pas ces deux contrôles comme un succès global.

Situer chaque échec à la bonne étape

Si hdiutil verify échoue, conservez d’abord le DMG d’origine et le journal de création. Vérifiez que le fichier n’a pas été envoyé ou lu avant la fin de son écriture. S’il manque des fichiers sur le volume, examinez le répertoire de préparation et le chemin d’entrée de ditto. Si la vérification de signature échoue, recherchez un script qui aurait modifié le paquet après la signature, puis recréez l’image à partir de l’app définitive. Des retouches répétées du DMG existant compliquent la traçabilité de la livraison.

Si tous les contrôles en ligne de commande réussissent, mais que l’app ne se lance pas après le glisser-déposer, vérifiez en priorité le chemin depuis lequel elle est réellement lancée, sa signature et les contrôles de confiance du système requis pour une distribution externe. Enfin, consignez l’identifiant de build de l’app, la somme de contrôle du fichier DMG, les résultats des vérifications automatiques et la conclusion de la validation graphique. Lors de la prochaine livraison, ces informations aideront à déterminer si le problème vient du build, de l’empaquetage ou de l’installation.

Questions fréquentes

hdiutil verify confirme-t-il que l’application démarre ?

Non. Il contrôle l’image disque, pas le lancement de l’app copiée. Vérifiez séparément la signature et le démarrage.

Faut-il signer l’application avant de créer le DMG ?

Oui. Signez et vérifiez sa version définitive avant l’empaquetage ; toute modification impose un nouveau DMG.

Besoin d’un Mac cloud dédié ?

Choisissez le modèle, la région et la durée de facturation. Vous bénéficiez d’une machine physique dédiée ; la disponibilité réelle est indiquée en temps réel dans la console.

Voir les configurations et commander