Come disinstallare le app del Mac installate da un pacchetto .pkg
Un'app arrivata con un programma di installazione .pkg non è la stessa cosa di un'app trascinata fuori da un'immagine disco. Il programma di installazione è stato eseguito come root, ha potuto scrivere ovunque il pacchetto gli dicesse, e ha lasciato una traccia di ciò che ha installato nel database delle ricevute di Installer. Trascinare l'app nel Cestino toglie una sola cartella da quella traccia e lascia il resto, compresa la traccia stessa. Questo articolo parla di questo caso: come capire che l'app l'ha installata un pacchetto, come leggere cosa ha messo sul disco, cosa rimuovere e cosa lasciare. Se il Finder si rifiuta e basta, o l'app torna dopo che l'hai eliminata, parti invece da quando un'app del Mac non si disinstalla, e per un'app che hai trascinato tu, la guida alla disinstallazione completa copre il percorso abituale.
Perché il Cestino non basta
Un pacchetto può mettere file accanto all'app, non solo al suo interno. Quando ho disinstallato di nuovo alcune app con i loro programmi di installazione ufficiali, il pacchetto ufficiale di Zoom ha lasciato tre job di launchd e un helper privilegiato, us.zoom.ZoomDaemon, fuori da zoom.us.app. Il programma di installazione di Logi Options+ ha installato anche un secondo prodotto, LogiRightSight, con la sua ricevuta e il suo agente di avvio. DisplayLink Manager ha aggiunto un agente di avvio in /Library/LaunchAgents. Microsoft Office installa un pacchetto di framework condivisi che Word, Excel e PowerPoint caricano tutti, e con esso arrivano Microsoft AutoUpdate e un helper per le licenze. Niente di tutto questo si sposta quando si sposta il bundle dell'app.
Nemmeno la ricevuta si sposta. Vive nel database di Installer, separata dai file che descrive, quindi rimuovere l'app lascia pkgutil a dire che il pacchetto è ancora installato. Dopo un'esecuzione pulita del programma di disinstallazione ufficiale di DisplayLink, le sue due ricevute erano ancora lì.
Una richiesta di password nel Finder è l'altro segnale che hai a che fare con un pacchetto. Il programma di installazione è stato eseguito come root, quindi il bundle che ha lasciato appartiene a root, e spostarlo richiede l'autenticazione. È normale, ed è spiegato nella guida ai problemi di disinstallazione.
Controllare se l'ha installata un pacchetto
Parti dall'elenco delle ricevute e dal percorso dell'app stessa:
pkgutil --pkgs | grep -i zoom
pkgutil --file-info /Applications/zoom.us.app
pkgutil --pkgs elenca ogni ID di pacchetto che Installer ha registrato sul volume di avvio. Cerca il produttore e il nome del prodotto, non solo l'identificatore di bundle dell'app, perché spesso i due non hanno nulla in comune. L'app di Zoom è us.zoom.xos e la sua ricevuta è us.zoom.pkg.videomeeting. La ricevuta che installa Cookie.app è app.fantasticthing.Bookkeeping. Può cambiare perfino l'uso delle maiuscole: l'identificatore di bundle di 爱思助手 è cn.i4Tools.mac e la sua ricevuta è cn.i4tools.mac, e pkgutil confronta gli ID in modo esatto, quindi la grafia con le maiuscole risponde «No receipt» mentre la ricevuta è proprio lì. Copia l'ID dall'output di --pkgs invece di scriverlo a mano.
pkgutil --file-info dovrebbe indicare il pacchetto che ha installato un percorso, in righe pkgid: sotto il percorso. Non leggere una risposta vuota come «non viene da un pacchetto». Su macOS 27 ho visto che per la maggior parte dei percorsi, eliminati o presenti, stampa solo volume e path; l'app di DisplayLink Manager ha ricevuto quella risposta vuota mentre le sue due ricevute erano ancora sul Mac. Una ricevuta non dimostra nemmeno che tu abbia eseguito un .pkg: il Mac App Store ne lascia una per alcune app, come com.apple.pkg.TestFlight.
Cosa registra una ricevuta
Due comandi mostrano cosa ha installato un pacchetto e dove:
pkgutil --pkg-info us.zoom.pkg.videomeeting
pkgutil --files us.zoom.pkg.videomeeting
--pkg-info stampa l'ID del pacchetto, la versione, volume, location e l'ora di installazione. --files stampa percorsi relativi a quel volume e a quella posizione, quindi il percorso reale è l'unione dei tre. Una ricevuta con posizione Applications elenca Foo.app/Contents/...; una con la posizione vuota elenca invece Applications/Foo.app/.... Leggi la posizione prima di leggere l'elenco, altrimenti ogni percorso che cerchi sarà sbagliato.
L'elenco include cartelle oltre ai file. --only-files e --only-dirs li separano, cosa utile quando vedi che una ricevuta può elencare Library e Library/LaunchAgents in sé. I dati grezzi stanno in /private/var/db/receipts, un .bom e un .plist per pacchetto, ma il manuale di pkgutil dice che la posizione dei file delle ricevute può cambiare e che vanno sempre interrogate tramite pkgutil.
Una ricevuta è una mappa, non un elenco da eliminare
Viene la tentazione di passare pkgutil --files a un ciclo e rimuovere tutto. È così che la disinstallazione di un pacchetto rompe qualcos'altro. L'elenco dice cosa ha scritto questo pacchetto, non cosa usa soltanto questo pacchetto:
| Cosa contiene l'elenco | Perché non puoi semplicemente eliminarlo |
|---|---|
Cartelle come Applications, Library, Library/LaunchAgents |
Il pacchetto le ha create o toccate, ma le usano anche tutte le altre app del Mac |
| Framework e helper che un produttore condivide tra le sue app | Word, Excel e PowerPoint caricano tutti i framework condivisi di Office e senza di essi vanno in crash all'avvio |
| Contenuti condivisi da più app | GarageBand, Logic Pro, MainStage e Final Cut Pro condividono /Library/Application Support/GarageBand, /Library/Application Support/Logic e /Library/Audio/Apple Loops, registrati sotto ricevute com.apple.pkg.MAContent10_* |
| Un altro prodotto portato dallo stesso programma di installazione | LogiRightSight è arrivato con Logi Options+ e continua a funzionare da solo |
| Plist di agenti e daemon di avvio | Un job caricato va fermato prima che il suo plist se ne vada, altrimenti launchd tiene un job senza più nulla sul disco dietro |
All'elenco sfuggono anche delle cose. Registra ciò che il payload del pacchetto ha messo sul disco. Gli script di installazione possono fare di più, e i pacchetti li contengono: quello di Foxit, per esempio, ha uno script postinstall e un servizio di aggiornamento. L'app scrive i propri dati nella Libreria della tua cartella Inizio quando viene eseguita, e niente di questo è in una ricevuta. Per quella parte, usa trovare i residui dopo una disinstallazione.
Esegui prima il programma di disinstallazione del produttore
Le indicazioni di Apple per eliminare le app sono chiare su questo: se un'app include un programma di disinstallazione, «è il modo migliore per eliminare l'app e gli eventuali elementi di login, estensioni o altri dati che l'app potrebbe aver salvato in altre posizioni». Il software installato tramite pacchetto spesso ne ha uno, perché il produttore conosce i propri script, helper e componenti condivisi. Cerca nell'immagine disco da cui veniva il pacchetto, nella cartella dell'app in Applicazioni, in /Applications/Utilities, nei menu dell'app stessa e sul sito di supporto del produttore. Splashtop Personal, per esempio, mette il suo programma di disinstallazione nella stessa immagine disco del pacchetto.
Se hai già trascinato l'app nel Cestino, rimettila a posto con Archivio › Ripristina (File › Put Back), aprila ed esegui da lì il suo programma di disinstallazione. Per software di sicurezza, client VPN e driver lo strumento del produttore non è facoltativo: estensioni e filtri di rete si tolgono solo tramite l'app a cui appartengono, come spiega disinstallare un antivirus sul Mac.
Rimuoverlo a mano
Quando non c'è un programma di disinstallazione, la ricevuta ti dice dove guardare. Lavora a partire da essa in questo ordine:
- Chiudi l'app e tutto ciò che esegue in background.
- Leggi
--pkg-infoper la posizione, poi--filesper l'elenco, e annota i percorsi che stanno fuori dal bundle dell'app. - Per ogni agente o daemon di avvio nell'elenco, scarica il job con
launchctl bootoutprima di spostare il suo plist. La sezione su launchd della guida ai problemi spiega perché l'ordine conta. - Sposta nel Cestino solo ciò che appartiene chiaramente a questo prodotto: il bundle dell'app, le cartelle e i plist che portano il nome del suo identificatore di bundle o del prodotto, il suo helper in
/Library/PrivilegedHelperTools. Lascia le cartelle madre condivise e tutto ciò che le altre app del produttore usano ancora.pkgutil --pkgs | grep -i vendornamemostra se sono ancora installati altri pacchetti dello stesso produttore; se sì, i loro framework condivisi restano. - Dimentica la ricevuta per ultima, quando non resta più niente di ciò che elenca:
sudo pkgutil --forget com.vendor.pkg
--forget scarta la ricevuta e, con le parole del manuale, «non tocca i file installati». Eseguirlo per primo lascia ogni file al suo posto senza più una traccia che vi rimandi, e questo complica il resto del lavoro. Serve sudo perché /private/var/db/receipts appartiene a root, e serve l'ID scritto esattamente come lo scrive --pkgs. Una ricevuta rimasta indietro non contiene dati utente, quindi se non sei sicuro che qualcosa che elenca sia ancora in uso, lasciare la ricevuta non costa nulla.
Controllare il risultato
Questi comandi si limitano a leggere. Sostituisci com.vendor.pkg e vendorname con ciò che hai trovato sopra:
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
Il ciclo stampa ogni file della ricevuta che esiste ancora, con il percorso completo. Se non stampa nulla, il payload non c'è più e la ricevuta si può dimenticare senza rischi. Un output dentro il bundle dell'app significa che l'app è ancora installata; un output altrove è ciò che la rimozione ha mancato, o ciò che hai deciso di tenere perché lo condivide un'altra app. Se pkgutil risponde «No receipt for ... found», la ricevuta è già stata dimenticata o l'ID si scrive in un altro modo. Le righe ls e launchctl intercettano gli helper che la ricevuta non ha mai elencato. launchctl list mostra i tuoi agenti e launchctl print system mostra i daemon. Qualsiasi riga dell'uno o dell'altro significa che il job è ancora caricato, e un numero diverso da zero nella prima colonna significa che è in esecuzione adesso.
Come Mole gestisce le app installate da pkg
Quando rimuovi un'app in Mole, legge le ricevute il cui nome corrisponde all'identificatore di bundle o al nome del prodotto dell'app ed elenca i percorsi di quelle ricevute che esistono ancora, ma solo dentro un insieme ristretto: il bundle dell'app in Applicazioni e, sotto /Library, solo le cartelle Application Support, Caches, Logs, PrivilegedHelperTools, WebKit e HTTPStorages, più i plist di Preferences, LaunchAgents e LaunchDaemons che portano esattamente quell'identificatore di bundle. Queste righe arrivano senza spunta, quindi spunti ciascuna dopo averla letta. I percorsi sotto /Users, /opt, /usr e /private non diventano mai righe a partire da una ricevuta, e nemmeno i file delle ricevute stessi.
Quando l'app non c'è più, Mole dimentica la ricevuta che porta il nome del suo identificatore di bundle, con la grafia che pkgutil ha sul disco, e una ricevuta del produttore che trova tramite pkgutil --file-info, quest'ultima solo quando nessuno dei file elencati da quella ricevuta esiste più. Lo fa solo quando l'helper amministratore era già autorizzato per quella rimozione, quindi non fa mai comparire una richiesta di password in più per una ricevuta. La ricerca del produttore salta le ricevute com.apple.* di Apple.
Il limite è quello descritto sopra. Dato che pkgutil --file-info risponde di rado su macOS 27, una ricevuta il cui ID non ha nulla a che vedere con l'app può restare dopo che Mole l'ha rimossa, come è successo alle due di DisplayLink e a quella di Zoom. Sono solo tracce, e sudo pkgutil --forget le cancella. Per driver, client VPN e software di sicurezza, Mole non sostituisce il programma di disinstallazione del produttore.
Domande frequenti
pkgutil --forget disinstalla l'app?
No. Il manuale dice che scarta tutti i dati della ricevuta del pacchetto ma non tocca i file installati. Eseguilo dopo che i file non ci sono più, mai al posto di rimuoverli.
Posso eliminare tutti i file che elenca pkgutil --files?
No. L'elenco include cartelle di sistema come Library e Applications, framework caricati dalle altre app del produttore e plist di job che potrebbero essere ancora in esecuzione. Usalo per capire cosa controllare, poi rimuovi ciò che appartiene solo a questo prodotto.
L'app non c'è più, ma pkgutil --pkgs la elenca ancora. È ancora installata?
Non necessariamente. Eliminare file non aggiorna mai la ricevuta, quindi resta finché qualcuno non la dimentica. Esegui il ciclo di controllo qui sopra: se non esiste più nulla di ciò che la ricevuta elenca, resta solo la traccia, e sudo pkgutil --forget la rimuove.