advanced_native_contact_picker

A Flutter plugin for picking contacts using native system UIs on Android and iOS. This plugin avoids requiring explicit READ_CONTACTS permissions on Android or contacts permissions on iOS by relying on modern native system pickers that grant zero-permission / temporary read access to the selected contacts.

Features

  • Zero Permissions Required: Operates using native system picker flows (CNContactPickerViewController on iOS, zero-permission ACTION_PICK / API 37+ Contact Picker on Android).
  • Single & Multi Selection: Pick a single contact or enable multi-selection mode (allowMultiple: true).
  • Native Selection Action Sheet (iOS): When a single contact has multiple numbers/emails, iOS automatically presents a native action sheet bottom sheet after contact selection so the user can choose the exact entry.
  • Configurable Fields: Easily choose whether to fetch phone numbers only (default) or include email addresses (includeEmail: true).
  • Clean Models: Returns strongly-typed NativeContact models with lookupKey, name, phones, and emails.

Demo / Visuals

Android 17 Picker Android 16 Picker
Android 17 Picker Android 16 Picker

Important Note for Android 16 and Below

  • No Permissions Required: On Android 16 or lower, the contact picker still works perfectly without requiring explicit READ_CONTACTS permissions.
  • Duplicate Contacts Display: In Android 16 or lower, if a single contact has multiple phone numbers saved (e.g., Contact A has 5 different numbers), the system picker will display 5 separate entries with the same name instead of grouping them together under one contact entry.

Getting Started

Add advanced_native_contact_picker to your pubspec.yaml:

dependencies:
  advanced_native_contact_picker: ^0.0.3

Usage

Import the package in your Dart code:

import 'package:advanced_native_contact_picker/advanced_native_contact_picker.dart';

Pick a Single Contact (Phone Only)

By default, calling pickContact() opens the picker and retrieves phone numbers only:

final List<NativeContact> contacts = await NativeContactPicker.pickContact();

if (contacts.isNotEmpty) {
  final contact = contacts.first;
  print('Name: ${contact.name}');
  for (final phone in contact.phones) {
    print('Phone (${phone.label}): ${phone.value}');
  }
}

Pick a Contact with Emails Included

To include email addresses alongside phone numbers, set includeEmail: true:

final List<NativeContact> contacts = await NativeContactPicker.pickContact(
  includeEmail: true,
);

Pick Multiple Contacts

To enable selecting multiple contacts at once:

final List<NativeContact> contacts = await NativeContactPicker.pickContact(
  allowMultiple: true,
  selectionLimit: 5, // Supported on Android API 37+
  includeEmail: true,
);

for (final contact in contacts) {
  print('${contact.name}: ${contact.phones.map((p) => p.value).join(", ")}');
}

Parameters

Parameter Type Default Description
allowMultiple bool false Enables multi-contact selection mode.
includeEmail bool false When true, fetches email addresses in addition to phone numbers. Defaults to phone-only.
selectionLimit int? null Optional limit on the number of contacts that can be selected in multi-select mode (Android API 37+).

Data Structure

NativeContact

Property Type Description
lookupKey String Unique platform identifier for the contact.
name String Full display name of the contact.
phones List<LabeledValue> List of phone numbers associated with the contact (or the specifically selected phone number).
emails List<LabeledValue> List of email addresses associated with the contact.

LabeledValue

Property Type Description
label String The label associated with the entry (e.g., "mobile", "work", "home").
value String The actual phone number or email address string.

Example App

Check the example/ directory for a complete sample Flutter application.