The Android Contact Picker deadline is forcing teams to rebuild invite and address-book flows without READ_CONTACTS, and Google Play is making that non-optional for Android 17+ apps by 27 January 2027.
If you treat this as “swap the API call and ship”, you will ship regressions: lower invite conversion, broken dedupe, surprising UI (multi-profile), and a compliance story that fails the Play declaration review.
What changed: READ_CONTACTS is now a restricted permission
Google Play’s April 2026 update makes the rule simple: if your app targets Android 17 (API level 37) or later, you may only request READ_CONTACTS when the Android Contact Picker is not sufficient for your app’s core functionality. Otherwise, you’re expected to remove the permission and use minimum-scope alternatives. (support.google.com)
The enforcement timeline is explicit:
- September 2026: Play Console prompts apps that declare
READ_CONTACTSto submit a declaration justifying core-functionality access or remove the permission and migrate to the picker. (support.google.com) - 27 January 2027: compliance becomes mandatory for apps targeting Android 17+ (with a Console self-extension mentioned, but you should plan as if enforcement starts on the date). (support.google.com)
This is why it feels like the old migrations (READ_PHONE_STATE, SMS/Call Log, background location): permission-heavy “growth features” suddenly count as over-collection.
What the Android Contact Picker actually gives you (and what it doesn’t)
The Android Contact Picker is a system UI available on Android 17+ that lets the user select specific contacts and specific fields (for example, phone numbers or email addresses). Your app gets access only to the selected data, not the whole address book. It is explicitly positioned as a privacy-preserving alternative to READ_CONTACTS. (developer.android.google.cn)
Key properties you should design around:
- The picker is browsable, supports search, profile switching, and multi-select without you building that UI. (developer.android.google.cn)
- Integration is via an intent-based contract (documented as
ContactsPickerSessionContract.ACTION_PICK_CONTACTS). (developer.android.google.cn) - The model changes from “sync and match the whole book” to “user selects exactly who to share”. That is the point; if your product requires full ingestion for the feature to exist, you are now in “justify core functionality” territory.
If you are still on the legacy approach (ACTION_PICK / Contacts Provider URIs), remember: Contacts Provider access is permission-gated (READ_CONTACTS, WRITE_CONTACTS), and you should expect scrutiny for any standing access. (developer.android.com)
Decide first: are you doing invites, or address-book matching?
Most teams conflate three separate behaviours:
- “Invite someone” (share an SMS/email/WhatsApp message)
- “Send to an existing user” (select a recipient and message them in-app)
- “Find my friends” (address-book matching, suggestions, network building)
Under the new policy framing, only the first two are naturally compatible with minimum-scope pickers. The third often relies on bulk processing (hashing, normalisation, repeated background sync). If that third behaviour is not truly core to your app, the correct answer is: do not do this on-device contacts anymore.
A practical decision rule:
- If the user’s intent is “I want to contact Alice now”, use the picker.
- If your intent is “I want to build a social graph from their phonebook”, assume you need a redesign, not a migration.
Google’s own messaging around the picker calls out invites/sharing/one-time lookups as the primary use case. (android-developers.googleblog.com)
Replacement flows that preserve growth loops
1) Invite/share: picker + system sharesheet, not raw contact reads
The highest-leverage refactor is to stop treating invites as a “contacts feature”. Treat them as a “compose and share” feature.
Implementation sketch:
- User taps “Invite”.
- Offer two paths: - “Share link” (Android Sharesheet, no contacts) - “Choose recipients” (Android Contact Picker to pick phone/email)
- After the user selects recipients, your app: - Prepares a message (deep link, referral code, context) - Hands off to the appropriate channel (SMS app, email client, messaging app) via intents
Trade-offs and failure modes:
- You will lose “one-tap invite 20 people” if you previously auto-selected the entire address book. That is intended. Replace it with explicit multi-select.
- You need a durable way to attribute invitations without storing the address book. Use per-invite tokens in your links, not “uploaded contacts”.
2) “Send to contact”: picker to select the identifier you can route on
If you have an in-app messaging or calling feature, your old flow might have been:
- Read contacts
- Match to users
- Display a directory
Under picker-first design:
- Let the user pick a phone number or email.
- Attempt to resolve that identifier to an existing account.
- If it resolves, open the conversation.
- If it doesn’t, offer “Invite” with the same identifier.
This keeps the UX tight while keeping your data collection proportional.
3) Address-book matching: redesign around explicit consent and explicit selection
If you still believe address-book matching is core, you need to be honest about what changes:
- The picker does not give you the entire book, so “silent matching” goes away.
- Your “Find friends” screen becomes a workflow:
- explain what will happen
- ask the user to select contacts
- match only those
This can still work in practice for B2B or small-network apps where the user has a short, known list (“add your team”, “add your family”). It is a poor fit for “discover everyone you know”.
If your growth model needs bulk contact ingestion to function, assume you will not be approved for READ_CONTACTS unless you can make a core-functionality case that survives review.Engineering edge cases teams miss
Multi-profile and work profiles
Android 17’s picker documentation calls out profile switching; users may have personal/work profiles and expect to pick from the correct context. (developer.android.google.cn)
Do not persist “contact IDs” assuming they’re stable across profiles. Treat the picker output as an input to an action (invite/message) rather than as a durable key in your domain model.
Normalisation and dedupe without a full address book
With full contacts access, teams often normalised E.164 numbers, merged duplicates, and ran repeated sync. With picker-based selection:
- Normalise only what the user selected.
- Dedupe within the selected set.
- Avoid building “shadow address books” in your backend.
If you need repeated actions (“invite again”), store only the minimal identifier the user already used (phone/email) and a user-visible label they provided or confirmed, not their full contact card.
Backwards compatibility
The Android Contact Picker is Android 17+ only. (developer.android.google.cn)
For older devices you have three realistic options:
- Keep
READ_CONTACTSonly for pre-17 targets (complicated and still risky as you approach Android 17 targeting deadlines). - Use older system pick intents (
ACTION_PICK) for one-off selection and avoid broad reads (still not the new picker, but less “sync the book”). - Remove contacts-based flows on older OS versions and default to Sharesheet-based invites.
The right choice depends on your user base and how much you can tolerate divergent UX. If you keep legacy behaviour, isolate it behind an interface so you can delete it later.
Testing and analytics
The “success metric” changes. You should instrument:
- Picker open rate vs. completion rate
- Channel chosen (sharesheet vs picker recipients)
- Invite attribution by token redemption
- Error rate resolving picked identifiers to existing users
Do not instrument “contacts uploaded” as a proxy for growth anymore. Besides being unhelpful, it is a compliance smell.
A compliance-first rollout plan (that doesn’t stall delivery)
This is the playbook we’ve used successfully for restricted-permission migrations:
- Inventory every code path that touches contacts: - permissions in manifest - runtime requests - SDKs that might request on your behalf
- Split features into: - one-off recipient selection - persistent directory/sync - enrichment (names/avatars)
- Design the minimum-scope experience first (picker + sharesheet), then decide if anything truly needs
READ_CONTACTS. - Implement the picker path for Android 17+ behind a server-controlled flag.
- Ship an internal build and run UX review specifically for: - multi-select behaviour - cancellation behaviour - fallbacks when the identifier can’t be resolved
- Remove `READ_CONTACTS` (or gate it to older targets only) and verify Play Console declarations are accurate.
- Roll out gradually, watching invite completion and attribution, not “permission grant rate”.
Google Play’s own guidance is that apps should remove READ_CONTACTS if they are using it for invites/sharing and migrate to the picker; only apps that can’t function without broad access should be submitting declarations. (support.google.com)
When the right answer is “do not do this”
Be blunt with yourself in product review. Under the new regime, these are the patterns that will keep hurting you:
- Uploading the full address book “just to suggest friends”
- Repeated background sync of contacts
- Asking for
READ_CONTACTSon first launch “so invites work later”
Even if you manage to justify it today, you are betting your roadmap on a permission that is explicitly being ring-fenced.
Where codeversols fits (briefly)
If you need to refactor quickly, this is mostly engineering execution: reworking UI flows, rebuilding attribution, auditing SDK permission behaviour, and getting the Play declaration story straight. codeversols does hands-on mobile engineering (Android, cross-platform), backend and privacy-conscious product design, and we can slot in to deliver a picker-based migration without turning it into a six-month rewrite.
Close
Treat the Contact Picker deadline as a product change, not a permission change. The teams that ship this cleanly will be the ones that redesign “invite” around explicit user intent, keep only the minimum identifiers they need, and delete READ_CONTACTS before Play Console forces the issue in September 2026 and the mandatory date on 27 January 2027. (support.google.com)



