Дозвола за приступ контактима је механизам мобилних оперативних система који захтева изричиту сагласност корисника пре читања именика уређаја. На iOS-у приступ контактима се остварује преко CNContactStore, а на Android-у — преко Contacts API-ја и система runtime permissions. Према Apple Developer Documentation, 2025, од iOS 18 све апликације су обавезне да користе унификовани Contacts Access API. Правилна имплементација захтева за дозволу повећава шансе за одобрење од стране модерације продавница апликација.
Главне тачке
Дозвола за приступ контактима је механизам оперативног система који штити кориснички именик од неовлашћеног читања од стране апликација трећих страна. У мобилним оперативним системима, контакти се сматрају поверљивим подацима јер садрже имена, бројеве телефона, адресе е-поште и фотографије особа из окружења корисника.
На iOS-у дозвола се регулише Contacts оквиром и класом CNContactStore. Корисник види системски дијалог при првом захтеву за приступ, где може да изабере да одобри или одбије приступ. На Android-у заштита се заснива на систему runtime permissions: апликација наводи READ_CONTACTS у манифесту и захтева га током извршавања преко ActivityResultLauncher-а или фрагмента са обрадом резултата.
Према подацима Statista (2025), више од 68% корисника iOS-а и 54% корисника Android-а одбија приступ контактима при првом захтеву апликације. То значи да програмер мора не само да правилно имплементира захтев, већ и да објасни кориснику разлог потребе за приступом.
Индустријски стандард — захтевати приступ само у тренутку када је функционалност заиста потребна, а не при првом покретању. Овакав приступ смањује проценат одбијања и побољшава корисничко искуство.
У Епл екосистему, приступ контактима се регулише Contacts оквиром, представљеним у iOS 9. Класа CNContactStore пружа методе за захтевање дозволе и обављање операција читања и писања. При првом позиву requestAccess(for:) систем приказује изворни дијалог са објашњењем разлога приступа.
Почевши од iOS 17, Епл је увела режим једнократног приступа (single contact access). Корисник може да изабере један контакт из именика и проследи га апликацији без откривања целе базе. Режим се имплементира преко CNContactPickerViewController-а и не захтева позив requestAccess(for:).
Програмер треба да разуме: ако апликација захтева потпуни приступ, а функционално јој је довољан један контакт, модератори App Store-а могу да одбију билд. Према Apple App Review Guidelines (2025), одељак 5.1.1 изричито захтева минимално неопходну количину података.
Са изласком iOS 18, Епл је пооштрила захтеве за Privacy Manifest — датотеку privacy.xcprivacy, у којој програмер декларише разлог приступа заштићеним подацима. За контакте се користи кључ NSContactsUsageDescription са локализованим текстом који се приказује у системском дијалогу.
Без исправног privacy manifest-а апликација не пролази модерацију App Store Connect-а. Текст описа мора бити конкретан: не „За побољшање рада”, већ „За проналажење пријатеља по броју телефона”.
На Android-у приступ контактима је заштићен дозволом READ_CONTACTS, која спада у категорију опасних (dangerous) — мора се захтевати током извршавања, а не само при инсталацији. Механизам runtime permissions је уведен у Android 6.0 (API 23) и остаје главни начин заштите поверљивих података.
Дозвола READ_CONTACTS се наводи у манифесту преко uses-permission тага, а захтева се у коду преко ActivityResultLauncher-а или фрагмента са onRequestPermissionsResult. Корисник може да одбије захтев или изабере опцију „Не питај поново”, након чега апликација мора правилно да обради одбијање.
Почевши од Android 14 (API 34), понашање runtime permissions се променило: при одбијању два узастопна захтева, оперативни систем аутоматски поставља флаг neverAskAgain. Према Google Developer Documentation (2024), програмер треба да провери статус преко shouldShowRequestPermissionRationale пре поновног захтева.
За читање контаката, Android користи ContentProvider под називом ContactsContract. То је структурирана база података доступна преко ContentResolver-а. Подаци су организовани у неколико табела: Contacts (контакти), RawContacts (сирови записи из различитих налога), Data (деталне информације: телефони, е-пошта, адресе).
Упит ContactsContract-у се извршава преко URI-ја ContactsContract.Contacts.CONTENT_URI. Програмер треба да захтева минимум колона и користи пројекцију за филтрирање поља — ово убрзава извршење упита и смањује потрошњу меморије.
Практична имплементација захтева за приступ контактима се разликује на iOS-у и Android-у. Испод су дати конкретни примери на Swift-у и Kotlin-у са обрадом свих могућих стања дозволе.
На iOS-у захтев се извршава преко методе requestAccess класе CNContactStore. Резултат се враћа у затворењу са буловом вредношћу и опционом грешком. Пример испод демонстрира комплетан циклус захтева са обрадом статуса.
import Contacts
let store = CNContactStore()
store.requestAccess(for: .contacts) { granted, error in
if granted {
print("Приступ контактима је добијен")
// Извршавање операција са контактима
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("Приступ одбијен: \(error?.localizedDescription ?? "неизвестная ошибка")")
}
}
На Android-у захтев се извршава преко ActivityResultLauncher-а са RequestPermission уговором. Пример испод приказује рад са ContactsContract.ContentProvider-ом након добијања дозволе.
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", "Contact: $name")
}
}
} else {
// Објашњење кориснику разлога потребе за приступом
showRationaleDialog()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestPermissionLauncher.launch(android.Manifest.permission.READ_CONTACTS)
}
Искусни програмери мобилних апликација прате скуп проверених пракси при раду са дозволом за приступ контактима. Ова правила помажу да се прође модерација продавница апликација и задржи поверење корисника. Праћење најбољих пракси значајно поједностављује процес објављивања и одржавања апликације.
Никада не захтевајте приступ контактима при првом покретању апликације. Први захтев треба да се деси у контексту одређене функције: проналажење пријатеља, позивање учесника, увоз контаката. Корисник који разуме разлог захтева пристаје 2-3 пута чешће, како показују истраживања Apptentive (2024).
Ако је функционалност довољна за приступ једном контакту — користите CNContactPickerViewController на iOS-у или имплицитни intent ACTION_PICK на Android-у. Ове методе не захтевају претходну дозволу и омогућавају кориснику да самостално изабере запис без откривања целог именика апликацији.
Апликација мора правилно да обради ситуацију када је корисник одбио захтев. На iOS-у проверите статус преко CNContactStore.authorizationStatus(for:) и усмерите корисника у Подешавања ако је потребно. На Android-у користите shouldShowRequestPermissionRationale за приказ додатног објашњења пре поновног захтева.
Никада не приказујте поновљени дијалог одмах након одбијања — то се доживљава као агресија и смањује рејтинг апликације. Најбоља пракса: након неког времена прикажите екран са објашњењем и дугметом „Иди на подешавања” које отвара системски екран дозвола преко Intent-а. Тестирајте сценарио одбијања на стварним уређајима — симулатори не репродукују увек исправно понашање системских дијалога дозвола.
Често постављана питања
Апликације захтевају приступ контактима за функције проналажења пријатеља, позивања учесника, аутоматског попуњавања образаца и синхронизације са сервером. Примери: месенџери траже контакте по броју телефона, CRM апликације увозе клијенте.
Једнократни приступ (iOS 17+) преко CNContactPickerViewController-а омогућава кориснику да изабере један контакт без откривања целог именика. Потпуни приступ омогућава апликацији да чита све контакте уређаја преко CNContactStore-а. Једнократни приступ је сигурнији и не захтева навођење NSContactsUsageDescription у privacy manifest-у.
На iOS-у идите на Подешавања — Приватност и безбедност — Контакти и искључите приступ за одређену апликацију. На Android-у отворите Подешавања — Апликације — изаберите апликацију — Дозволе — Контакти и изаберите „Одбиј”.
Privacy Manifest (датотека privacy.xcprivacy) — обавезни документ за iOS 18+ у којем програмер декларише разлоге приступа заштићеним подацима, укључујући контакте. Кључ NSContactsUsageDescription садржи локализовани опис који се приказује у системском дијалогу захтева за дозволу.
Android класификује READ_CONTACTS као опасну дозволу (dangerous permission) јер даје приступ личним подацима корисника. Механизам runtime permissions, уведен у Android 6.0, захтева изричиту сагласност током извршавања, а не само при инсталацији апликације.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође