با انتخابگر تماس بگیرید

انتخابگر مخاطب اندروید (Android Contact Picker) یک رابط کاربری استاندارد و قابل مرور برای کاربران است تا مخاطبین را با برنامه شما به اشتراک بگذارند. این انتخابگر که در دستگاه‌های دارای اندروید ۱۷ (سطح API ۳۷) یا بالاتر موجود است، جایگزینی با حفظ حریم خصوصی برای مجوز گسترده READ_CONTACTS ارائه می‌دهد. برنامه شما به جای درخواست دسترسی به کل دفترچه آدرس کاربر، فیلدهای داده مورد نیاز خود، مانند شماره تلفن یا آدرس ایمیل را مشخص می‌کند و کاربر مخاطبین خاصی را برای اشتراک‌گذاری انتخاب می‌کند. این به برنامه شما اجازه می‌دهد فقط به داده‌های انتخاب شده دسترسی داشته باشد و کنترل جزئی را تضمین کند و در عین حال یک تجربه کاربری سازگار با قابلیت‌های جستجوی داخلی، تغییر پروفایل و انتخاب چندگانه را بدون نیاز به ساخت یا نگهداری رابط کاربری ارائه دهد.

انتخابگر مخاطب را ادغام کنید

برای ادغام انتخابگر مخاطب، از Intent.ACTION_PICK_CONTACTS استفاده کنید. این intent انتخابگر را اجرا می‌کند و مخاطبین انتخاب شده را به برنامه شما برمی‌گرداند.

برخلاف ACTION_PICK قدیمی، Contact Picker به شما امکان می‌دهد چندین فیلد داده‌ای را که برنامه شما به طور همزمان نیاز دارد، مشخص کنید. شما این کار را با استفاده از Intent.EXTRA_REQUESTED_DATA_FIELDS انجام می‌دهید و یک ArrayList<String> از انواع MIME تعریف شده در ContactsContract.CommonDataKinds را ارسال می‌کنید.

انواع MIME رایج عبارتند از:

  • ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
  • ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE
  • ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE

انتخابگر را راه اندازی کنید

registerForActivityResult به همراه قرارداد StartActivityForResult برای اجرای انتخابگر (picker) استفاده کنید. می‌توانید اینتنت را طوری پیکربندی کنید که امکان انتخاب تکی یا چندگانه را فراهم کند.

// Launcher for the Contact Picker intent
val pickContact = rememberLauncherForActivityResult(StartActivityForResult()) {
    if (it.resultCode == Activity.RESULT_OK) {
        val resultUri = it.data?.data ?: return@rememberLauncherForActivityResult

        // Process the result URI in a background thread to fetch all selected contacts
        coroutine.launch {
            contacts = processContactPickerResultUri(resultUri, context)
        }
    }
}

حالت انتخاب

رابط کاربری انتخابگر مخاطب (Contact Picker) بر اساس فیلدهای داده درخواستی تنظیم می‌شود. بسته به این الزامات، کاربران می‌توانند در صورت نیاز به چندین فیلد، کل یک رکورد مخاطب را انتخاب کنند، یا موارد داده‌ای خاصی را از اطلاعات یک مخاطب انتخاب کنند.

حالت‌های مختلف رابط کاربری انتخابگر مخاطب
شکل ۱. رابط انتخابگر مخاطب با فیلدهای داده درخواستی (انتخاب یک مخاطب، چندین مخاطب و چندین شماره تلفن) سازگار می‌شود.

یک مخاطب واحد را انتخاب کنید

در این مثال، برنامه فقط شماره تلفن‌ها را درخواست می‌کند. انتخابگر، لیست را فیلتر می‌کند تا فقط مخاطبین دارای شماره تلفن را نشان دهد و به کاربر اجازه می‌دهد یک شماره خاص را انتخاب کند.

// Define the specific contact data fields you need
val requestedFields = arrayListOf(
    Email.CONTENT_ITEM_TYPE,
    Phone.CONTENT_ITEM_TYPE,
)

// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
    putStringArrayListExtra(
        EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
        requestedFields
    )
}

// Launch the picker
pickContact.launch(pickContactIntent)

انتخاب چندین مخاطب

برای فعال کردن انتخاب چندگانه، Intent.EXTRA_ALLOW_MULTIPLE را اضافه کنید. می‌توانید به صورت اختیاری تعداد مواردی را که کاربر می‌تواند انتخاب کند محدود کنید.

val requestedFields = arrayListOf(
    Email.CONTENT_ITEM_TYPE,
    Phone.CONTENT_ITEM_TYPE,
)

// Set up the intent for the Contact Picker
val pickContactIntent = Intent(ACTION_PICK_CONTACTS).apply {
    // Enable multi-select
    putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
    // Set limit of selectable contacts
    putExtra(EXTRA_PICK_CONTACTS_SELECTION_LIMIT, 5)
    // Define the specific contact data fields you need
    putStringArrayListExtra(
        EXTRA_PICK_CONTACTS_REQUESTED_DATA_FIELDS,
        requestedFields
    )
    // Enable this option to only filter contacts that have all the requested data fields
    putExtra(EXTRA_PICK_CONTACTS_MATCH_ALL_DATA_FIELDS, false)
}

// Launch the picker
pickContact.launch(pickContactIntent)

نتایج را مدیریت کنید

وقتی کاربر انتخاب را کامل می‌کند، سیستم یک RESULT_OK و یک Session URI برمی‌گرداند. این URI دسترسی موقت خواندن به داده‌های انتخاب شده را اعطا می‌کند.

شما می‌توانید با استفاده از یک ContentResolver استاندارد، این URI را جستجو کنید. Cursor حاصل شامل فیلدهای داده درخواستی است و از طرح ContactsContract.Data پیروی می‌کند.

// Data class representing a parsed Contact with selected details.
data class Contact(
    val lookupKey: String,
    val name: String,
    val emails: List<String>,
    val phones: List<String>
)

// Helper function to query the content resolver with the URI returned by the Contact Picker.
// Parses the cursor to extract contact details such as name, email, and phone number.
private suspend fun processContactPickerResultUri(
    sessionUri: Uri,
    context: Context
): List<Contact> = withContext(Dispatchers.IO) {
    // Define the columns we want to retrieve from the ContactPicker ContentProvider
    val projection = arrayOf(
        ContactsContract.Contacts.LOOKUP_KEY,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Data.MIMETYPE, // Type of data (e.g., email or phone)
        ContactsContract.Data.DATA1, // The actual data (Phone number / Email string)
    )

    // We use `LOOKUP_KEY` as a unique ID to aggregate all contact info related to a same person
    val contactsMap = mutableMapOf<String, Contact>()

    // Note: The Contact Picker Session Uri doesn't support custom selection & selectionArgs.
    // We query the URI directly to get the results chosen by the user.
    context.contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        // Get the column indices for our requested projection
        val lookupKeyIdx = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)
        val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)
        val data1Idx = cursor.getColumnIndex(ContactsContract.Data.DATA1)

        while (cursor.moveToNext()) {
            val lookupKey = cursor.getString(lookupKeyIdx)
            val mimeType = cursor.getString(mimeTypeIdx)
            val name = cursor.getString(nameIdx) ?: ""
            val data1 = cursor.getString(data1Idx) ?: ""

            val email = if (mimeType == Email.CONTENT_ITEM_TYPE) data1 else null
            val phone = if (mimeType == Phone.CONTENT_ITEM_TYPE) data1 else null

            val existingContact = contactsMap[lookupKey]
            if (existingContact != null) {
                contactsMap[lookupKey] = existingContact.copy(
                    emails = if (email != null) existingContact.emails + email else existingContact.emails,
                    phones = if (phone != null) existingContact.phones + phone else existingContact.phones
                )
            } else {
                contactsMap[lookupKey] = Contact(
                    lookupKey = lookupKey,
                    name = name,
                    emails = if (email != null) listOf(email) else emptyList(),
                    phones = if (phone != null) listOf(phone) else emptyList()
                )
            }
        }
    }

    return@withContext contactsMap.values.toList()
}

سازگاری با نسخه‌های قبلی

برای برنامه‌هایی که اندروید ۱۷ (سطح API ۳۷) و بالاتر را هدف قرار می‌دهند، سیستم به طور خودکار Intent.ACTION_PICK موجود را برای استفاده از رابط کاربری جدید Contact Picker ارتقا می‌دهد.

اگر برنامه شما از قبل از ACTION_PICK استفاده می‌کند، نیازی به تغییر کد خود برای دریافت رابط کاربری جدید ندارید. با این حال، برای بهره‌مندی از ویژگی‌های جدید، مانند دریافت یک Uri واحد برای جستجوی داده‌های مخاطب، جابجایی بین پروفایل‌های شخصی و کاری یا درخواست‌های فیلد داده چندگانه، باید پیاده‌سازی خود را برای استفاده از Intent.ACTION_PICK_CONTACTS یا موارد اضافی جدید intent به‌روزرسانی کنید.

آزمایش روی SDK های هدف قدیمی تر

شما می‌توانید رفتار جدید انتخابگر را روی دستگاه‌هایی که اندروید ۱۷ و بالاتر دارند، حتی اگر برنامه شما نسخه SDK پایین‌تری را هدف قرار داده است، با اضافه کردن مقدار بولی EXTRA_USE_SYSTEM_CONTACTS_PICKER به تابع ACTION_PICK خود، آزمایش کنید.

بهترین شیوه‌ها

  • فقط مواردی را که نیاز دارید درخواست کنید : اگر برنامه شما فقط نیاز به ارسال پیامک دارد، Phone.CONTENT_ITEM_TYPE را درخواست کنید. انتخابگر به طور خودکار مخاطبینی را که شماره تلفن ندارند فیلتر می‌کند و در نتیجه رابط کاربری تمیزتری برای کاربر ایجاد می‌شود.
  • مدیریت چندین ورودی داده برای هر مخاطب : مخاطبین منفرد اغلب حاوی آدرس‌های ایمیل یا شماره تلفن‌های مختلفی هستند. برای اطمینان از نمایش واضح و شهودی این موارد برای کاربر، توصیه می‌شود آنها را با استفاده از ContactsContract.Contacts.LOOKUP_KEY گروه‌بندی کنید. علاوه بر این، می‌توانید برچسب‌های خاصی را برای هر ورودی (مانند کاری یا شخصی) بازیابی کنید تا گزینه‌های انتخاب جزئی‌تری را در رابط برنامه خود ارائه دهید.
  • داده‌ها را فوراً ذخیره کنید : آدرس اینترنتی Session، مجوز خواندن موقت را اعطا می‌کند. اگر بعداً (پس از خاتمه فرآیند برنامه) نیاز به دسترسی به این اطلاعات مخاطب داشته باشید، برنامه شما باید داده‌های مخاطب را ذخیره کند.
  • به داده‌های حساب کاربری اعتماد نکنید : برای محافظت از حریم خصوصی کاربر و جلوگیری از ردیابی اثر انگشت، فراداده‌های مربوط به حساب کاربری از نتایج حذف می‌شوند.