Kebijakan Izin Kontak Google Play berarti bahwa mulai 27 Januari 2027, aplikasi yang menargetkan Android 17 (API level 37) atau lebih baru hanya boleh meminta READ_CONTACTS jika Android Contact Picker tidak dapat mendukung fitur inti, dan harus membenarkannya lewat deklarasi Play Console. Untuk sebagian besar aplikasi Capacitor yang membaca kontak untuk mengundang teman, membagikan file, atau mengisi nomor telepon, solusinya adalah beralih ke Contact Picker dan menghapus izin tersebut. Panduan ini menjelaskan kebijakan tersebut dan menunjukkan cara melakukannya dengan @capgo/capacitor-contacts, serta membahas apa yang harus dilakukan jika Anda benar-benar membutuhkan seluruh buku alamat.
Isi kebijakan tersebut
Google mengumumkan kebijakan ini pada 15 April 2026, sebagai bagian dari rangkaian pembaruan privasi. Poin-poin utamanya, dari halaman Bantuan Play Console:
- Cakupan: aplikasi yang menargetkan Android 17 (API 37) atau lebih tinggi dan meminta
READ_CONTACTS. - Aturan: Anda hanya boleh meminta
READ_CONTACTSjika Android Contact Picker tidak cukup untuk fitur utama aplikasi Anda. - Deklarasi: aplikasi yang tetap memakai izin tersebut harus mengisi deklarasi di Play Console yang menjelaskan fitur mana yang membutuhkannya dan mengapa picker tidak cukup.
- Timeline: Play Console began prompting apps that declare
READ_CONTACTSpada September 2026. Kepatuhan bersifat wajib pada 27 Januari 2027. Google menyebutkan adanya perpanjangan mandiri selama 30 hari di Play Console. - Pengecualian: aplikasi privat dan aplikasi manajemen perangkat enterprise tidak termasuk dalam cakupan ini.
- Data: data kontak bersifat pribadi dan sensitif di bawah kebijakan User Data, dan Anda tidak boleh memublikasikan data kontak non-publik tanpa izin dari orang yang bersangkutan.
Use cases that can keep READ_CONTACTS
Google mencantumkan fitur inti seperti aplikasi manajemen kontak, dialer dan SMS, riwayat panggilan dan call screening, CRM, fitur aksesibilitas, asisten pribadi, pencocokan teman, backup dan restore, serta keyboard atau autocomplete.
Kasus penggunaan yang harus beralih ke picker
Mengundang atau mereferensikan seseorang, berbagi file, kolaborasi, atau memilih kontak untuk mengirim uang. Jika itu alasan aplikasi Anda membaca kontak, deklarasi tidak akan diterima. Gunakan picker.
Apa yang berubah di Android 17
Android 17 menyertakan Contact Picker sistem yang baru. Aplikasi mendapatkan URI sesi read-only sementara yang hanya mengekspos kontak dan field yang dipilih pengguna, tanpa izin apa pun. Untuk aplikasi yang menargetkan Android 17, sistem secara otomatis meningkatkan classic Intent.ACTION_PICK contacts intent ke picker baru ini. Aplikasi juga dapat meminta field data spesifik (telepon, email, alamat pos) dan pemilihan ganda melalui intent action baru.
Pada versi Android lama, memilih baris data tertentu (misalnya nomor telepon) lewat contact picker selalu mengembalikan URI yang bisa dibaca aplikasi tanpa READ_CONTACTS. Inilah yang membuat alur tanpa permission bisa jalan di semua versi Android.
Mengapa “pick a contact” dulu butuh READ_CONTACTS
Banyak plugin Capacitor mengimplementasikan “pick contact” dengan membuka picker untuk seluruh kontak, lalu meng-query buku alamat untuk nomor telepon dan email kontak tersebut. Query kedua itu butuh READ_CONTACTS. Jadi aplikasi yang sebenarnya cuma butuh satu nomor telepon pun akhirnya mendeklarasikan izin tersebut, dan itulah yang jadi sasaran kebijakan ini.
Solusinya adalah dengan meminta field spesifik yang Anda butuhkan ke picker, sehingga URI hasilnya sudah menyertakan data tersebut.
Pilih telepon, email, atau alamat tanpa READ_CONTACTS
@capgo/capacitor-contacts menambahkan property opsi di versi 8.1.0. Jika diaktifkan, Android membuka picker pada tabel telepon, email, atau alamat pos dan membaca baris yang dipilih dari URI yang diberikan. Tidak perlu READ_CONTACTS di versi Android mana pun. Di iOS, picker bawaan sistem tidak pernah butuh izin kontak.
bun add @capgo/capacitor-contacts
bunx cap sync
import { CapacitorContacts, ContactProperty } from '@capgo/capacitor-contacts';
export async function pickPhoneNumber(): Promise<string | undefined> {
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.PhoneNumber,
});
const picked = contacts[0];
return picked?.phoneNumbers?.[0]?.value;
}
export async function pickEmail(): Promise<string | undefined> {
const { contacts } = await CapacitorContacts.pickContacts({
property: ContactProperty.EmailAddress,
});
return contacts[0]?.emailAddresses?.[0]?.value;
}
Dengan property, hasilnya berisi kontak id, displayName dan hanya properti yang dipilih. Seleksi ganda akan diabaikan, pengambilan properti selalu mengembalikan satu nilai. Jika pengguna membatalkan, periksa array kosong.
Plugin ini tidak mendeklarasikan READ_CONTACTS atau WRITE_CONTACTS di manifest-nya sendiri, jadi jika Anda hanya menggunakan pengambilan properti, merged manifest Anda tetap bersih.
Saat Anda masih membutuhkan READ_CONTACTS
Metode plugin ini membaca buku alamat dan terus meminta izin:
pickContacts()ataupickContact()tanpaproperty, saat Anda menginginkan data kontak lengkapgetContacts(),getContactById(),countContacts()getGroups(),getGroupById(),getAccounts()
Jika aplikasi Anda adalah CRM, alat backup, atau fitur pencocokan teman, itu adalah penggunaan inti yang sah. Tambahkan izin sendiri dan ajukan deklarasi:
<!-- android/app/src/main/AndroidManifest.xml -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
import { CapacitorContacts } from '@capgo/capacitor-contacts';
const perm = await CapacitorContacts.requestPermissions({ permissions: ['readContacts'] });
if (perm.readContacts === 'granted' || perm.readContacts === 'limited') {
const { contacts } = await CapacitorContacts.getContacts({
fields: ['displayName', 'phoneNumbers'],
limit: 200,
offset: 0,
});
console.log(contacts.length);
}
Kebijakan ini menargetkan READ_CONTACTS. Menulis kontak dengan WRITE_CONTACTS (untuk createContact, updateContactById, deleteContactById) bukan merupakan subjek dari kebijakan ini, namun tambahkan saja jika Anda menggunakan metode tersebut.
Rencana migrasi untuk aplikasi Capacitor
-
Audit merged manifest. Build release Anda dan buka
android/app/build/intermediates/merged_manifest/(atau gunakan tab Merged Manifest di Android Studio). Beberapa plugin menambahkannyaREAD_CONTACTStanpa Anda sadari. Jika plugin menambahkannya padahal tidak perlu, hapus dengantools:node="remove":<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.READ_CONTACTS" tools:node="remove" /> </manifest> -
List setiap bagian yang mengakses kontak. Untuk tiap bagian, tentukan: picker dengan properti, atau seluruh buku alamat.
-
Ganti alur invite dan share dengan
pickContacts({ property }). -
Simpan permission hanya untuk fitur inti, dan siapkan teks deklarasi: fitur apa, mengapa picker saja tidak cukup, serta video jika fitur tersebut sulit ditemukan.
-
Rilis build native. Perubahan manifest dan plugin butuh rilis Play baru. Jika Anda build di CI, Build Capgo bisa menghasilkan signed Android builds, dan Generator keystore Android membantu jika Anda baru pertama kali mengatur signing.
-
Rilis perubahan UI secara OTA. Setelah plugin native baru aktif, penyesuaian wording dan flow di sekitar picker bisa dikirim melalui Live updates Capgo.
Migrasi dari plugin kontak lain
If you use @capacitor-community/contacts (8.0.0 saat tulisan ini dibuat), Android-nya pickContact meminta grup izin kontak sebelum membuka picker, lalu membaca kontak lengkap dari buku alamat. Tidak ada mode properti. Nama metodenya juga berbeda (getContact vs getContactById, objek proyeksi vs sebuah fields array). Kami membandingkan plugin kontak komunitas dan plugin Capgo memetakan setiap panggilan.
Jika Anda masih menggunakan plugin kontak Cordova di dalam Capacitor, sekarang saat yang tepat untuk menggantinya. Lihat migrasi dari Cordova ke Capacitor.
Pemecahan Masalah
Picker mengembalikan kontak tanpa nomor telepon. Anda memanggil pickContacts() tanpa property dan aplikasi tidak memiliki READ_CONTACTS. Hanya id dan displayName (dan pada Android 17+, field yang diizinkan picker) akan kembali. Tambahkan property.
Play Console masih menyatakan aplikasi mendeklarasikan READ_CONTACTS. Sebuah library menambahkannya. Cek merged manifest dan hapus dengan tools:node="remove". Cek juga rilis lama di track lain, setiap artifact aktif akan dihitung.
Deklarasi ditolak. Undangan, referral, dan sharing dicantumkan sebagai kasus untuk picker. Rombak fiturnya atau jelaskan dengan jelas mengapa daftar lengkap itu inti (misalnya friend matching yang dijalankan terhadap seluruh buku alamat).
iOS meminta izin kontak. Anda memanggil method yang membaca buku alamat. Picker tidak membutuhkannya. Hapus NSContactsUsageDescription jika Anda hanya memilih.
Tanggal penting
| Tanggal | Apa yang terjadi |
|---|---|
| 15 April 2026 | Kebijakan diumumkan |
| September 2026 | Play Console meminta aplikasi yang mendeklarasikan READ_CONTACTS untuk mengajukan deklarasi |
| 27 Januari 2027 | Kepatuhan wajib bagi aplikasi yang menargetkan Android 17 (API 37) atau lebih baru |
Cek halaman Bantuan Play Console untuk kebijakan ini sebelum submit, Google dapat memperbarui tenggat waktu dan redaksi.