Désinstaller une app Mac installée avec un paquet .pkg
Une app arrivée par un programme d’installation .pkg n’est pas la même chose qu’une app que vous avez glissée hors d’une image disque. Le programme d’installation a tourné en root, il a pu écrire partout où le paquet le lui demandait, et il a laissé une trace de ce qu’il a installé dans la base de reçus du Programme d’installation. Glisser l’app dans la Corbeille retire un seul dossier de cette trace et laisse le reste, y compris la trace elle-même. Cet article porte sur ce cas : comment savoir qu’un paquet a installé l’app, comment lire ce qu’il a mis sur le disque, quoi supprimer et quoi laisser. Si le Finder refuse net, ou si l’app revient après que vous l’avez supprimée, commencez plutôt par quand une app Mac refuse de se désinstaller, et pour une app que vous avez glissée vous-même, le guide de désinstallation complète couvre la méthode habituelle.
Pourquoi la Corbeille ne suffit pas
Un paquet peut placer des fichiers à côté de l’app, pas seulement à l’intérieur. Quand j’ai redésinstallé des apps via leurs programmes d’installation officiels, le paquet officiel de Zoom a laissé trois tâches launchd et un helper privilégié, us.zoom.ZoomDaemon, en dehors de zoom.us.app. Le programme d’installation de Logi Options+ a aussi installé un second produit, LogiRightSight, avec son propre reçu et son propre agent de lancement. DisplayLink Manager a ajouté un agent de lancement dans /Library/LaunchAgents. Microsoft Office installe un paquet de frameworks partagés que Word, Excel et PowerPoint chargent tous, et Microsoft AutoUpdate ainsi qu’un helper de licence arrivent avec lui. Rien de tout cela ne bouge quand le bundle de l’app bouge.
Le reçu ne bouge pas non plus. Il vit dans la base de données propre au Programme d’installation, séparée des fichiers qu’il décrit, si bien que supprimer l’app laisse pkgutil indiquer que le paquet est toujours installé. Après un passage propre du programme de désinstallation officiel de DisplayLink, ses deux reçus étaient toujours là.
Une demande de mot de passe dans le Finder est l’autre signe que vous avez affaire à un paquet. Le programme d’installation a tourné en root, donc le bundle qu’il a laissé appartient à root, et le déplacer demande une authentification. C’est normal, et c’est expliqué dans le guide de dépannage de la désinstallation.
Vérifier si un paquet l’a installée
Commencez par la liste des reçus et le chemin de l’app elle-même :
pkgutil --pkgs | grep -i zoom
pkgutil --file-info /Applications/zoom.us.app
pkgutil --pkgs liste tous les identifiants de paquet que le Programme d’installation a enregistrés sur le volume de démarrage. Cherchez le nom de l’éditeur et celui du produit, pas seulement l’identifiant de bundle de l’app, parce que les deux n’ont souvent rien en commun. L’app de Zoom est us.zoom.xos et son reçu est us.zoom.pkg.videomeeting. Le reçu qui installe Cookie.app est app.fantasticthing.Bookkeeping. Même la casse peut différer : l’identifiant de bundle de 爱思助手 est cn.i4Tools.mac et son reçu est cn.i4tools.mac, et pkgutil compare les identifiants à l’identique, donc l’orthographe avec majuscules répond « No receipt » alors que le reçu est bien là. Copiez l’identifiant depuis la sortie de --pkgs plutôt que de le taper.
pkgutil --file-info est censé nommer le paquet qui a installé un chemin, dans des lignes pkgid: sous le chemin. Ne lisez pas une réponse vide comme « ne vient pas d’un paquet ». Sur macOS 27, j’ai constaté qu’il n’affiche que volume et path pour la plupart des chemins, supprimés ou présents ; l’app de DisplayLink Manager a obtenu cette réponse vide alors que ses deux reçus étaient encore sur le Mac. Un reçu ne prouve pas non plus que vous avez lancé un .pkg vous-même : le Mac App Store en laisse un pour certaines apps, comme com.apple.pkg.TestFlight.
Ce qu’un reçu enregistre
Deux commandes montrent ce qu’un paquet a installé et où :
pkgutil --pkg-info us.zoom.pkg.videomeeting
pkgutil --files us.zoom.pkg.videomeeting
--pkg-info affiche l’identifiant du paquet, sa version, volume, location et la date d’installation. --files affiche des chemins relatifs à ce volume et à cet emplacement, donc le vrai chemin est la réunion des trois. Un reçu dont l’emplacement est Applications liste Foo.app/Contents/... ; un reçu à l’emplacement vide liste Applications/Foo.app/... à la place. Lisez l’emplacement avant de lire la liste, sinon chaque chemin que vous chercherez sera faux.
La liste contient des répertoires aussi bien que des fichiers. --only-files et --only-dirs séparent les deux, ce qui devient utile quand on voit qu’un reçu peut lister Library et Library/LaunchAgents eux-mêmes. Les enregistrements bruts se trouvent dans /private/var/db/receipts, sous la forme d’un .bom et d’un .plist par paquet, mais le manuel de pkgutil précise que l’emplacement des fichiers de reçu peut changer et qu’il faut toujours les interroger via pkgutil.
Un reçu est une carte, pas une liste de suppression
Il est tentant de faire passer pkgutil --files dans une boucle et de tout supprimer. C’est comme cela qu’une désinstallation de paquet casse autre chose. La liste dit ce que ce paquet a écrit, pas ce que ce paquet est seul à utiliser :
| Ce que contient la liste | Pourquoi on ne peut pas simplement le supprimer |
|---|---|
Des répertoires comme Applications, Library, Library/LaunchAgents |
Le paquet les a créés ou modifiés, mais toutes les autres apps du Mac s’en servent aussi |
| Des frameworks et des helpers qu’un éditeur partage entre ses apps | Word, Excel et PowerPoint chargent tous les frameworks partagés d’Office et plantent au lancement sans eux |
| Du contenu que plusieurs apps partagent | GarageBand, Logic Pro, MainStage et Final Cut Pro partagent /Library/Application Support/GarageBand, /Library/Application Support/Logic et /Library/Audio/Apple Loops, enregistrés sous des reçus com.apple.pkg.MAContent10_* |
| Un autre produit apporté par le même programme d’installation | LogiRightSight est arrivé avec Logi Options+ et continue de fonctionner seul |
| Des plists d’agents et de démons de lancement | Une tâche chargée doit être arrêtée avant que son plist parte, sinon launchd garde une tâche sans plus rien derrière sur le disque |
La liste oublie aussi des choses. Elle enregistre ce que la charge utile du paquet a mis sur le disque. Les scripts d’installation peuvent en faire davantage, et les paquets en contiennent : celui de Foxit, par exemple, a un script postinstall et un service de mise à jour. L’app écrit ses propres données dans la Bibliothèque de votre dossier personnel une fois lancée, et rien de cela ne figure dans un reçu. Pour ce côté-là, utilisez retrouver les restes après une désinstallation.
Lancer d’abord le programme de désinstallation de l’éditeur
Les conseils d’Apple pour supprimer des apps sont clairs sur ce point : si une app comprend un programme de désinstallation, « c’est la meilleure façon de supprimer l’app ainsi que les éléments d’ouverture, les extensions ou les autres données que l’app a pu stocker à d’autres emplacements ». Les logiciels installés par paquet en fournissent souvent un, parce que l’éditeur connaît ses propres scripts, helpers et composants partagés. Cherchez dans l’image disque d’où venait le paquet, dans le dossier de l’app dans Applications, dans /Applications/Utilities, dans les menus de l’app elle-même, et sur le site d’assistance de l’éditeur. Splashtop Personal, par exemple, place son programme de désinstallation dans la même image disque que le paquet.
Si vous avez déjà glissé l’app dans la Corbeille, remettez-la avec Fichier › Remettre en place (File › Put Back), ouvrez-la, et lancez son programme de désinstallation depuis là. Pour les logiciels de sécurité, les clients VPN et les pilotes, l’outil de l’éditeur n’est pas optionnel : les extensions et les filtres réseau ne se retirent que par l’app qui les possède, ce que couvre désinstaller un antivirus sur Mac.
Le supprimer à la main
Quand il n’y a pas de programme de désinstallation, le reçu vous dit où chercher. Travaillez à partir de lui, dans cet ordre :
- Quittez l’app et tout ce qu’elle fait tourner en arrière-plan.
- Lisez
--pkg-infopour l’emplacement, puis--filespour la liste, et notez les chemins situés en dehors du bundle de l’app. - Pour chaque agent ou démon de lancement de la liste, déchargez la tâche avec
launchctl bootoutavant de déplacer son plist. La section launchd du guide de dépannage explique pourquoi l’ordre compte. - Ne placez dans la Corbeille que ce qui appartient clairement à ce produit : le bundle de l’app, les dossiers et plists nommés d’après son identifiant de bundle ou son produit, son helper dans
/Library/PrivilegedHelperTools. Laissez les dossiers parents partagés et tout ce que les autres apps de l’éditeur utilisent encore.pkgutil --pkgs | grep -i vendornamemontre si d’autres paquets du même éditeur sont encore installés ; si c’est le cas, leurs frameworks partagés restent. - Oubliez le reçu en dernier, une fois que plus rien de ce qu’il liste ne reste :
sudo pkgutil --forget com.vendor.pkg
--forget supprime le reçu et, selon les mots du manuel, « ne touche pas aux fichiers installés ». Le lancer en premier laisse chaque fichier en place sans aucune trace qui y renvoie, ce qui complique le reste du travail. Il faut sudo parce que /private/var/db/receipts appartient à root, et il faut l’identifiant exactement comme --pkgs l’écrit. Un reçu périmé ne contient aucune donnée utilisateur, donc si vous n’êtes pas sûr que quelque chose qu’il liste soit encore utilisé, garder le reçu ne coûte rien.
Vérifier le résultat
Ces commandes ne font que lire. Remplacez com.vendor.pkg et vendorname par ce que vous avez trouvé plus haut :
id=com.vendor.pkg
loc=$(pkgutil --pkg-info "$id" | sed -n 's/^location: //p')
pkgutil --files "$id" --only-files | while IFS= read -r f; do
p="/${loc:+$loc/}$f"
[ -e "$p" ] && echo "$p"
done
pkgutil --pkgs | grep -i vendorname
ls /Library/LaunchAgents /Library/LaunchDaemons /Library/PrivilegedHelperTools | grep -i vendorname
launchctl list | grep -i vendorname
launchctl print system | grep -i vendorname
La boucle affiche chaque fichier du reçu qui existe encore, avec son chemin complet. Si elle n’affiche rien, la charge utile a disparu et le reçu peut être oublié sans risque. Une sortie à l’intérieur du bundle de l’app signifie que l’app est toujours installée ; une sortie ailleurs correspond à ce que la suppression a manqué, ou à ce que vous avez décidé de garder parce qu’une autre app le partage. Si pkgutil répond « No receipt for ... found », le reçu a déjà été oublié ou l’identifiant s’écrit autrement. Les lignes ls et launchctl attrapent les helpers que le reçu n’a jamais listés. launchctl list montre vos propres agents et launchctl print system montre les démons. Toute ligne de l’un ou de l’autre signifie que la tâche est encore chargée, et un nombre non nul dans sa première colonne signifie qu’elle tourne en ce moment.
Comment Mole gère les apps installées par pkg
Quand vous supprimez une app dans Mole, il lit les reçus dont le nom correspond à l’identifiant de bundle ou au nom de produit de l’app et liste les chemins de ces reçus qui existent encore, mais seulement dans un périmètre étroit : le bundle de l’app dans Applications, et sous /Library uniquement les dossiers Application Support, Caches, Logs, PrivilegedHelperTools, WebKit et HTTPStorages, plus les plists de Preferences, LaunchAgents et LaunchDaemons, nommés avec cet identifiant de bundle exact. Ces lignes arrivent décochées, donc vous cochez chacune après l’avoir lue. Les chemins sous /Users, /opt, /usr et /private ne deviennent jamais des lignes à partir d’un reçu, et les fichiers de reçu eux-mêmes non plus.
Une fois l’app partie, Mole oublie le reçu nommé d’après son identifiant de bundle, avec l’orthographe que pkgutil a sur le disque, ainsi qu’un reçu d’éditeur qu’il trouve via pkgutil --file-info, ce dernier seulement quand aucun des fichiers que ce reçu liste n’existe encore. Il ne le fait que lorsque le helper administrateur était déjà autorisé pour cette suppression, si bien qu’il ne déclenche jamais de demande de mot de passe supplémentaire pour un reçu. La recherche côté éditeur ignore les reçus com.apple.* d’Apple.
La limite est celle décrite plus haut. Comme pkgutil --file-info répond rarement sur macOS 27, un reçu dont l’identifiant n’a rien à voir avec l’app peut rester après que Mole l’a supprimée, comme les deux reçus de DisplayLink et celui de Zoom. Ce ne sont que des traces, et sudo pkgutil --forget les efface. Pour les pilotes, les clients VPN et les logiciels de sécurité, Mole ne remplace pas le programme de désinstallation de l’éditeur.
FAQ
pkgutil --forget désinstalle-t-il l’app ?
Non. Le manuel dit qu’il supprime toutes les données de reçu du paquet mais ne touche pas aux fichiers installés. Lancez-le une fois les fichiers partis, jamais à la place de leur suppression.
Peut-on supprimer tous les fichiers que liste pkgutil --files ?
Non. La liste contient des répertoires système comme Library et Applications, des frameworks que chargent les autres apps de l’éditeur, et des plists de tâches qui tournent peut-être encore. Servez-vous-en pour savoir quoi examiner, puis supprimez ce qui appartient uniquement à ce produit.
L’app a disparu, mais pkgutil --pkgs la liste encore. Est-elle toujours installée ?
Pas forcément. Supprimer des fichiers ne met jamais le reçu à jour, il reste donc jusqu’à ce que quelqu’un l’oublie. Lancez la boucle de vérification ci-dessus : si plus rien de ce que liste le reçu n’existe, il ne reste que la trace, et sudo pkgutil --forget la supprime.