A permissão de acesso a contatos é um mecanismo dos sistemas operacionais móveis que exige o consentimento explícito do usuário antes de ler a agenda do dispositivo. No iOS, o acesso aos contatos é feito através do CNContactStore, enquanto no Android utiliza a Contacts API e o sistema de permissões em tempo de execução. De acordo com Apple Developer Documentation, 2025, a partir do iOS 18 todos os aplicativos devem usar a API unificada Contacts Access API. A implementação correta da solicitação de permissão aumenta as chances de aprovação pela moderação das lojas de aplicativos.
Pontos principais
A permissão de acesso a contatos é um mecanismo do sistema operacional que protege a agenda do usuário contra leitura não autorizada por aplicativos de terceiros. Em sistemas operacionais móveis, os contatos são considerados dados confidenciais porque contêm nomes, números de telefone, endereços de e-mail e fotos de pessoas do círculo do usuário.
No iOS, a permissão é regida pelo framework Contacts e pela classe CNContactStore. O usuário vê um diálogo do sistema na primeira solicitação de acesso, onde pode escolher conceder ou negar o acesso. No Android, a proteção é baseada no sistema de permissões em tempo de execução: o aplicativo declara READ_CONTACTS no manifesto e o solicita em tempo de execução através do ActivityResultLauncher ou de um fragmento que trata o resultado.
De acordo com Statista (2025), mais de 68% dos usuários do iOS e 54% dos usuários do Android negam o acesso aos contatos na primeira solicitação. Isso significa que o desenvolvedor não só precisa implementar corretamente a solicitação, mas também explicar ao usuário por que o acesso é necessário.
Padrão da indústria — solicitar acesso apenas quando a funcionalidade for realmente necessária, não na primeira inicialização. Essa abordagem reduz a taxa de negações e melhora a experiência do usuário.
No ecossistema Apple, o acesso aos contatos é regulado pelo framework Contacts, introduzido no iOS 9. A classe CNContactStore fornece métodos para solicitar permissão e realizar operações de leitura e escrita. Na primeira chamada a requestAccess(for:), o sistema exibe um diálogo nativo explicando o motivo do acesso.
A partir do iOS 17, a Apple introduziu o modo de acesso a um único contato. O usuário pode selecionar um contato da agenda e compartilhá-lo com o aplicativo sem revelar todo o banco de dados. Este modo é implementado através do CNContactPickerViewController e não requer a chamada de requestAccess(for:).
É importante que o desenvolvedor entenda: se um aplicativo solicita acesso total mas funcionalmente precisa apenas de um contato, os moderadores da App Store podem rejeitar a versão. De acordo com as Apple App Review Guidelines (2025), a seção 5.1.1 exige explicitamente a quantidade mínima necessária de dados.
Com o lançamento do iOS 18, a Apple endureceu os requisitos para o Privacy Manifest — o arquivo privacy.xcprivacy onde o desenvolvedor declara o motivo do acesso aos dados protegidos. Para contatos, é usada a chave NSContactsUsageDescription com texto localizado exibido no diálogo do sistema.
Sem um privacy manifest correto, o aplicativo não passa na moderação do App Store Connect. O texto da descrição deve ser específico: não “Para melhorar o desempenho”, mas “Para encontrar amigos pelo número de telefone”.
No Android, o acesso aos contatos é protegido pela permissão READ_CONTACTS, que pertence à categoria perigosa (dangerous) — deve ser solicitada em tempo de execução, não apenas na instalação. O mecanismo de permissões em tempo de execução foi introduzido no Android 6.0 (API 23) e continua sendo a principal forma de proteger dados confidenciais.
A permissão READ_CONTACTS é declarada no manifesto através da tag uses-permission e solicitada no código através do ActivityResultLauncher ou de um fragmento com onRequestPermissionsResult. O usuário pode negar a solicitação ou selecionar “Não perguntar novamente”, após o que o aplicativo deve tratar corretamente a negação.
A partir do Android 14 (API 34), o comportamento das permissões em tempo de execução mudou: após duas negações consecutivas, o sistema operacional define automaticamente a flag neverAskAgain. De acordo com Google Developer Documentation (2024), o desenvolvedor deve verificar o status através de shouldShowRequestPermissionRationale antes de solicitar novamente.
Para ler contatos, o Android usa um ContentProvider chamado ContactsContract. É um banco de dados estruturado acessível através do ContentResolver. Os dados são organizados em várias tabelas: Contacts (contatos), RawContacts (registros brutos de diferentes contas), Data (informações detalhadas: telefones, e-mails, endereços).
A consulta ao ContactsContract é feita através da URI ContactsContract.Contacts.CONTENT_URI. O desenvolvedor deve solicitar o mínimo de colunas e usar projeção para filtrar campos — isso acelera a execução da consulta e reduz o consumo de memória.
A implementação prática da solicitação de acesso a contatos difere entre iOS e Android. Abaixo estão exemplos específicos em Swift e Kotlin com tratamento de todos os estados possíveis da permissão.
No iOS, a solicitação é feita através do método requestAccess da classe CNContactStore. O resultado é retornado em uma closure com um valor booleano e um erro opcional. O exemplo abaixo demonstra o ciclo completo de solicitação com tratamento de status.
import Contacts
let store = CNContactStore()
store.requestAccess(for: .contacts) { granted, error in
if granted {
print("Acesso a contatos concedido")
// Execução de operações com contatos
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey]
let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
try? store.enumerateContacts(with: request) { contact, stop in
print("\(contact.givenName) \(contact.familyName)")
}
} else {
print("Acesso negado: \(error?.localizedDescription ?? "erro desconhecido")")
}
}
No Android, a solicitação é feita através do ActivityResultLauncher com o contrato RequestPermission. O exemplo abaixo mostra o trabalho com ContactsContract.ContentProvider após obter a permissão.
val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
val uri = ContactsContract.Contacts.CONTENT_URI
val cursor = contentResolver.query(uri, null, null, null, null)
cursor?.use {
val nameIndex = it.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
while (it.moveToNext()) {
val name = it.getString(nameIndex)
Log.d("Contacts", "Contato: $name")
}
}
} else {
// Explicar ao usuário o motivo da necessidade de acesso
showRationaleDialog()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestPermissionLauncher.launch(android.Manifest.permission.READ_CONTACTS)
}
Desenvolvedores experientes de aplicativos móveis seguem um conjunto de práticas comprovadas ao trabalhar com a permissão de acesso a contatos. Estas regras ajudam a passar pela moderação das lojas de aplicativos e manter a confiança dos usuários. Seguir as melhores práticas simplifica significativamente o processo de publicação e manutenção.
Nunca solicite acesso a contatos na primeira inicialização do aplicativo. A primeira solicitação deve ocorrer no contexto de uma função específica: encontrar amigos, convidar participantes, importar contatos. Um usuário que entende o motivo da solicitação concorda 2 a 3 vezes mais, de acordo com pesquisas da Apptentive (2024).
Se a funcionalidade precisar apenas de acesso a um único contato, use CNContactPickerViewController no iOS ou uma intent implícita ACTION_PICK no Android. Esses métodos não exigem permissão prévia e permitem que o usuário selecione um registro sem revelar toda a agenda ao aplicativo.
O aplicativo deve tratar corretamente as situações em que o usuário nega o acesso. No iOS, verifique o status através de CNContactStore.authorizationStatus(for:) e direcione o usuário para as Configurações, se necessário. No Android, use shouldShowRequestPermissionRationale para mostrar uma explicação adicional antes de solicitar novamente.
Nunca mostre um segundo diálogo imediatamente após uma negação — isso é percebido como agressivo e reduz a classificação do aplicativo. A melhor prática: após algum tempo, mostre uma tela com explicação e um botão “Ir para Configurações” que abre a tela de permissões do sistema através de uma Intent. Teste o cenário de negação em dispositivos reais — os simuladores nem sempre reproduzem corretamente o comportamento dos diálogos de permissão do sistema.
Perguntas frequentes
Os aplicativos solicitam acesso aos contatos para funções como encontrar amigos, convidar participantes, preenchimento automático de formulários e sincronização com o servidor. Exemplos: mensageiros procuram contatos por número de telefone, aplicativos CRM importam clientes.
O acesso a um único contato (iOS 17+) através do CNContactPickerViewController permite ao usuário selecionar um contato sem revelar toda a agenda. O acesso total permite ao aplicativo ler todos os contatos do dispositivo através do CNContactStore. O acesso a um único contato é mais seguro e não requer a especificação de NSContactsUsageDescription no privacy manifest.
No iOS, vá para Configurações — Privacidade e segurança — Contatos e desative o acesso para o aplicativo específico. No Android, abra Configurações — Aplicativos — selecione o aplicativo — Permissões — Contatos e escolha “Negar”.
O Privacy Manifest (arquivo privacy.xcprivacy) é um documento obrigatório para iOS 18+, no qual o desenvolvedor declara os motivos de acesso aos dados protegidos, incluindo contatos. A chave NSContactsUsageDescription contém uma descrição localizada exibida no diálogo de solicitação de permissão do sistema.
O Android classifica READ_CONTACTS como uma permissão perigosa porque concede acesso aos dados pessoais do usuário. O mecanismo de permissões em tempo de execução, introduzido no Android 6.0, exige consentimento explícito em tempo de execução, não apenas durante a instalação do aplicativo.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também