انتخابگر مخاطب

«انتخابگر مخاطب Android» واسطی استانداردشده و قابل‌مرور است که کاربران می‌توانند ازطریق آن مخاطبین را با برنامه شما هم‌رسانی کنند. این انتخابگر که در دستگاه‌های دارای Android 17 (سطح میانای برنامه‌سازی کاربردی 37) یا بالاتر دردسترس است، جایگزینی حافظ حریم خصوصی برای اجازه گسترده READ_CONTACTS ارائه می‌دهد. به‌جای درخواست دسترسی به کل دفترچه تلفن کاربر، برنامه‌تان فیلدهای داده موردنیازش را مشخص می‌کند (مثلاً شماره تلفن یا نشانی ایمیل) و کاربر مخاطبین خاصی را برای هم‌رسانی انتخاب می‌کند. این کار به برنامه شما اجازه خواندن فقط داده‌های انتخاب‌شده را می‌دهد، کنترل جزئی را تضمین می‌کند و درعین‌حال تجربه کاربری ثابتی را با قابلیت‌های جستجوی داخلی، تعویض نمایه، و چندانتخابی بدون نیاز به ساختن یا نگهداری واسط کاربر ارائه می‌دهد.

یکپارچه‌سازی «انتخاب‌گر مخاطب»

برای ادغام «انتخابگر مخاطب»، از هدف ContactsPickerSessionContract.ACTION_PICK_CONTACTS استفاده کنید. این هدف، انتخابگر را راه‌اندازی می‌کند و مخاطبین انتخاب‌شده را به برنامه‌تان برمی‌گرداند.

برخلاف ACTION_PICK قدیمی، «انتخابگر مخاطب» به شما امکان می‌دهد چندین فیلد داده را که برنامه‌تان به‌طور هم‌زمان نیاز دارد مشخص کنید. این کار را بااستفاده از ContactsPickerSessionContract.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 برای راه‌اندازی انتخابگر استفاده کنید. می‌توانید قصد را برای اجازه دادن به انتخاب تکی یا چندتایی پیکربندی کنید.

// 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)
        }
    }
}

حالت انتخاب

رابط کاربری «انتخابگر مخاطب» براساس فیلدهای داده درخواست‌شده تنظیم می‌شود. بسته به این الزامات، کاربران می‌توانند کل سابقه مخاطب را زمانی که چندین فیلد موردنیاز است انتخاب کنند، یا موارد داده خاصی را از اطلاعات مخاطب انتخاب کنند.

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

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

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

// 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 {
    putExtra(EXTRA_USE_SYSTEM_CONTACTS_PICKER, true)
    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 {
    putExtra(EXTRA_USE_SYSTEM_CONTACTS_PICKER, true)
    // 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 و «شناسه منبع یکسان» جلسه را برمی‌گرداند. این URI دسترسی خواندن موقت به داده‌های انتخاب‌شده را اعطا می‌کند.

می‌توانید این URI را بااستفاده از ContentResolver استاندارد پُرسمان کنید. 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()
}

سازگاری با نسخه قدیمی

برای برنامه‌هایی که Android 17 (سطح میانای برنامه‌سازی کاربردی ۳۷) و بالاتر را هدف قرار می‌دهند، سیستم به‌طور خودکار قصد Intent.ACTION_PICK موجود را ارتقا می‌دهد تا از میانای جدید «انتخاب‌گر مخاطب» استفاده کند.

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

آزمایش روی کیت‌های توسعه نرم‌افزار هدف قدیمی‌تر

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

روال‌های مطلوب

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