Desinstalar no Mac apps que vieram de um pacote .pkg
Um app que chegou como instalador .pkg não é a mesma coisa que um app que você arrastou de uma imagem de disco. O instalador rodou como root, pôde gravar onde o pacote mandou e deixou um registro do que instalou no banco de recibos do Instalador. Arrastar o app para o Lixo remove uma das pastas que esse registro lista e deixa o resto, inclusive o próprio registro. Este artigo é sobre esse caso: como saber que um pacote instalou o app, como ler o que ele pôs no disco, o que remover e o que deixar. Se o Finder recusa de saída, ou o app volta depois que você apaga, comece por quando um app do Mac não desinstala. Para um app que você mesmo arrastou, o guia completo de desinstalação cobre o caminho usual.
Por que o Lixo não basta
Um pacote pode pôr arquivos ao lado do app, não só dentro dele. Quando reinstalei um lote de apps pelos instaladores oficiais e os removi de novo, o pacote oficial do Zoom deixou três tarefas do launchd e um auxiliar privilegiado, us.zoom.ZoomDaemon, fora de zoom.us.app. O instalador do Logi Options+ também instalou um segundo produto, o LogiRightSight, com o próprio recibo e o próprio agente de inicialização. O DisplayLink Manager acrescentou um agente de inicialização em /Library/LaunchAgents. O Microsoft Office instala um pacote de frameworks compartilhado que Word, Excel e PowerPoint carregam, e o Microsoft AutoUpdate mais um auxiliar de licenciamento vêm junto. Nada disso se move quando o pacote do app se move.
O recibo também não se move. Ele vive no banco do próprio Instalador, separado dos arquivos que descreve, então remover o app deixa o pkgutil ainda informando o pacote como instalado. Depois de uma execução limpa do desinstalador oficial do DisplayLink, os dois recibos dele ainda estavam lá.
Um pedido de senha no Finder é o outro sinal de que você está lidando com um pacote. O instalador rodou como root, então o pacote que deixou pertence ao root, e movê-lo pede autenticação. Isso é normal e está coberto em o guia de problemas na desinstalação.
Confira se um pacote instalou
Comece pela lista de recibos e pelo caminho do próprio app:
pkgutil --pkgs | grep -i zoom
pkgutil --file-info /Applications/zoom.us.app
pkgutil --pkgs lista todo ID de pacote que o Instalador registrou no volume de inicialização. Busque o fornecedor e o nome do produto, não só o identificador do pacote do app, porque os dois muitas vezes não têm nada em comum. O app do Zoom é us.zoom.xos e o recibo é us.zoom.pkg.videomeeting. O recibo que instala o Cookie.app é app.fantasticthing.Bookkeeping. Até a caixa pode diferir: o identificador do pacote do 爱思助手 é cn.i4Tools.mac e o recibo é cn.i4tools.mac, e o pkgutil combina IDs exatamente, então a grafia com caixa mista responde "No receipt" enquanto o recibo está ali. Copie o ID da saída de --pkgs em vez de digitá-lo.
pkgutil --file-info deveria nomear o pacote que instalou um caminho, em linhas pkgid: sob o caminho. Não leia uma resposta ausente como "não veio de um pacote". No macOS 27, vi que ele imprime só volume e path para a maioria dos caminhos, apagados ou presentes; o app do DisplayLink Manager recebeu essa resposta vazia enquanto os dois recibos ainda estavam no Mac. Um recibo também não prova que você mesmo rodou um .pkg: a Mac App Store deixa um para alguns apps, como com.apple.pkg.TestFlight.
O que um recibo registra
Dois comandos mostram o que um pacote instalou e onde:
pkgutil --pkg-info us.zoom.pkg.videomeeting
pkgutil --files us.zoom.pkg.videomeeting
--pkg-info imprime o ID do pacote, a versão, volume, location e a hora da instalação. --files imprime caminhos relativos a esse volume e a essa localização, então o caminho real é os três unidos. Um recibo com localização Applications lista Foo.app/Contents/...; um com localização vazia lista Applications/Foo.app/.... Leia a localização antes de ler a lista, senão todo caminho que você procurar vai estar errado.
A lista inclui diretórios além de arquivos. --only-files e --only-dirs separam os dois, o que é útil quando você vê que um recibo pode listar Library e Library/LaunchAgents em si. Os registros brutos ficam em /private/var/db/receipts como um .bom e um .plist por pacote, mas o manual do pkgutil diz que a localização dos arquivos de recibo está sujeita a mudança e que se deve sempre consultá-los pelo pkgutil.
Um recibo é um mapa, não uma lista de exclusão
É tentador alimentar pkgutil --files num laço e remover tudo. É assim que a desinstalação de um pacote quebra outra coisa. A lista diz o que este pacote gravou, não o que só este pacote usa:
| O que a lista contém | Por que você não pode simplesmente apagar |
|---|---|
Diretórios como Applications, Library, Library/LaunchAgents |
O pacote os criou ou tocou, mas todos os outros apps do Mac também os usam |
| Frameworks e auxiliares que um fornecedor compartilha entre apps | Word, Excel e PowerPoint carregam os frameworks compartilhados do Office e travam na abertura sem eles |
| Conteúdo que vários apps compartilham | GarageBand, Logic Pro, MainStage e Final Cut Pro compartilham /Library/Application Support/GarageBand, /Library/Application Support/Logic e /Library/Audio/Apple Loops, registrados em recibos com.apple.pkg.MAContent10_* |
| Outro produto que o mesmo instalador trouxe | O LogiRightSight veio com o Logi Options+ e continua funcionando por conta própria |
| Plists de agente e daemon de inicialização | Uma tarefa carregada precisa ser parada antes de o plist sair, senão o launchd mantém uma tarefa sem nada em disco atrás dela |
A lista também deixa coisas de fora. Registra o que a carga do pacote pôs no disco. Scripts do Instalador podem fazer mais, e os pacotes os carregam: o da Foxit, por exemplo, tem um script de postinstall e um serviço de atualização. O app grava os próprios dados na Library da sua pasta pessoal depois que roda, e nada disso está em recibo nenhum. Para esse lado, use achar resíduos depois de uma desinstalação.
Rode primeiro o desinstalador do fornecedor
A orientação da Apple para apagar apps é direta nisto: se um app inclui um desinstalador, "esse é o melhor jeito de apagar o app e quaisquer itens de início, extensões ou outros dados que o app possa ter guardado em outros lugares." Software instalado por pacote muitas vezes traz um, porque o fornecedor conhece os próprios scripts, auxiliares e partes compartilhadas. Procure na imagem de disco de onde o pacote veio, na pasta do app em Aplicativos, em /Applications/Utilities, nos menus do próprio app e no site de suporte do fornecedor. O Splashtop Personal, por exemplo, põe o desinstalador na mesma imagem de disco do pacote.
Se você já arrastou o app para o Lixo, devolva com Arquivo › Devolver, abra e rode o desinstalador a partir dali. Para software de segurança, clientes de VPN e drivers, a ferramenta do fornecedor não é opcional: extensões e filtros de rede só saem pelo app que é dono deles, o que desinstalar antivírus no Mac cobre.
Removendo na mão
Quando não há desinstalador, o recibo diz onde olhar. Trabalhe a partir dele nesta ordem:
- Encerre o app e qualquer coisa que ele rode em segundo plano.
- Leia
--pkg-infopara a localização, depois--filespara a lista, e anote os caminhos fora do pacote do app. - Para cada agente ou daemon de inicialização na lista, descarregue a tarefa com
launchctl bootoutantes de mover o plist. A seção de launchd do guia de problemas explica por que a ordem importa. - Mova para o Lixo só o que claramente pertence a este produto: o pacote do app, pastas e plists nomeados a partir do identificador do pacote ou do produto, o auxiliar dele em
/Library/PrivilegedHelperTools. Deixe pastas pai compartilhadas e qualquer coisa que os outros apps do fornecedor ainda usem.pkgutil --pkgs | grep -i vendornamemostra se outros pacotes do mesmo fornecedor ainda estão instalados; se estiverem, os frameworks compartilhados deles ficam. - Esqueça o recibo por último, quando nada do que ele lista restar:
sudo pkgutil --forget com.vendor.pkg
--forget descarta o recibo e, nas palavras do manual, não "toca os arquivos instalados". Rodá-lo primeiro deixa todos os arquivos no lugar, sem um registro apontando para eles, o que torna o resto deste trabalho mais difícil. Precisa de sudo porque /private/var/db/receipts pertence ao root, e precisa do ID exatamente como --pkgs o escreve. Um recibo velho não guarda dados seus, então, se você não tem certeza de que algo que ele lista ainda está em uso, deixar o recibo não custa nada.
Conferindo o resultado
Estes comandos só leem. Troque com.vendor.pkg e vendorname pelo que você achou acima:
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
O laço imprime todo arquivo do recibo que ainda existe, com o caminho completo. Nenhuma saída significa que a carga se foi e que o recibo pode ser esquecido com segurança. Saída dentro do pacote do app significa que o app ainda está instalado; saída em outro lugar é o que a remoção deixou passar, ou o que você decidiu guardar porque outro app compartilha. Se o pkgutil responder "No receipt for ... found", o recibo já foi esquecido ou o ID está escrito de outro jeito. As linhas de ls e launchctl pegam auxiliares que o recibo nunca listou. launchctl list mostra os seus agentes e launchctl print system mostra os daemons. Qualquer linha de um dos dois significa que a tarefa ainda está carregada, e um número diferente de zero na primeira coluna significa que está rodando agora.
Como o Mole trata apps instalados por pkg
Quando você remove um app no Mole, ele lê os recibos cujos nomes combinam com o identificador do pacote ou o nome do produto do app e lista os caminhos deles que ainda existem, mas só num conjunto estreito: o pacote do app em Aplicativos e, em /Library, só as pastas Application Support, Caches, Logs, PrivilegedHelperTools, WebKit e HTTPStorages, mais plists de Preferences, LaunchAgents e LaunchDaemons, nomeados com esse identificador exato de pacote. Essas linhas chegam desmarcadas, então você marca cada uma depois de ler. Caminhos em /Users, /opt, /usr e /private nunca viram linhas a partir de um recibo, e os arquivos de recibo também não.
Depois que o app sai, o Mole esquece o recibo nomeado a partir do identificador do pacote, usando a grafia que o pkgutil tem em disco, e um recibo de fornecedor que encontra por pkgutil --file-info, este último só quando nenhum dos arquivos que esse recibo lista ainda existe. Faz isso só quando o auxiliar de administrador já estava autorizado para essa remoção, então nunca pede uma senha extra por um recibo. A busca do fornecedor pula os recibos com.apple.* da Apple.
O limite é o descrito acima. Como pkgutil --file-info raramente responde no macOS 27, um recibo cujo ID não tem nada a ver com o app pode continuar depois que o Mole o remove, como aconteceu com os dois do DisplayLink e com o do Zoom. São só registros, e sudo pkgutil --forget os limpa. Para drivers, clientes de VPN e software de segurança, o Mole não substitui o desinstalador do fornecedor.
Perguntas frequentes
pkgutil --forget desinstala o app?
Não. O manual diz que descarta todos os dados de recibo do pacote, mas não toca os arquivos instalados. Rode depois que os arquivos tiverem saído, nunca no lugar de removê-los.
Posso apagar todo arquivo que pkgutil --files lista?
Não. A lista inclui diretórios do sistema como Library e Applications, frameworks que os outros apps do fornecedor carregam e plists de tarefas que ainda podem estar rodando. Use para achar o que revisar e depois remova o que pertence só a este produto.
O app sumiu, mas pkgutil --pkgs ainda o lista. Ainda está instalado?
Não necessariamente. Apagar arquivos nunca atualiza o recibo, então ele fica até alguém esquecê-lo. Rode o laço de conferência acima: se nada do que o recibo lista ainda existe, só o registro sobrou, e sudo pkgutil --forget o remove.