संपर्क पिकर

Android कॉन्टैक्ट पिकर, एक स्टैंडर्ड इंटरफ़ेस है. इससे उपयोगकर्ता, आपके ऐप्लिकेशन के साथ कॉन्टैक्ट शेयर कर सकते हैं. यह Android 17 (एपीआई लेवल 37) या इसके बाद के वर्शन पर काम करने वाले डिवाइसों पर उपलब्ध है. यह पिकर, READ_CONTACTS अनुमति के मुकाबले निजता बनाए रखने का विकल्प देता है. उपयोगकर्ता की पूरी पता पुस्तिका का ऐक्सेस मांगने के बजाय, आपका ऐप्लिकेशन उन डेटा फ़ील्ड के बारे में बताता है जिनकी उसे ज़रूरत है. जैसे, फ़ोन नंबर या ईमेल पते. इसके बाद, उपयोगकर्ता शेयर करने के लिए कुछ खास संपर्क चुनता है. इससे आपके ऐप्लिकेशन को सिर्फ़ चुने गए डेटा को पढ़ने का ऐक्सेस मिलता है. इससे आपको बेहतर कंट्रोल मिलता है. साथ ही, आपको एक जैसा उपयोगकर्ता अनुभव मिलता है. इसमें खोज करने, प्रोफ़ाइल स्विच करने, और एक से ज़्यादा आइटम चुनने की सुविधाएं पहले से मौजूद होती हैं. इसके लिए, आपको यूज़र इंटरफ़ेस (यूआई) बनाने या उसे बनाए रखने की ज़रूरत नहीं होती.

कॉन्टैक्ट पिकर को इंटिग्रेट करना

कॉन्टैक्ट पिकर को इंटिग्रेट करने के लिए, ContactsPickerSessionContract.ACTION_PICK_CONTACTS इंटेंट का इस्तेमाल करें. इस इंटेंट के ज़रिए, कॉन्टैक्ट पिकर लॉन्च होता है और यह आपके चुने गए संपर्कों को ऐप्लिकेशन में वापस लाता है.

पुराने ACTION_PICK के मुकाबले, कॉन्टैक्ट पिकर की मदद से अपने ऐप्लिकेशन के लिए एक साथ कई ज़रूरी डेटा फ़ील्ड चुने जा सकते हैं. इसके लिए, ContactsPickerSessionContract.EXTRA_REQUESTED_DATA_FIELDS का इस्तेमाल करें. साथ ही, ContactsContract.CommonDataKinds में तय किए गए MIME टाइप का ArrayList<String> पास करें.

सामान्य 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 और सेशन यूआरआई दिखाता है. इस यूआरआई से, चुने गए डेटा को कुछ समय के लिए पढ़ने का ऐक्सेस मिलता है.

स्टैंडर्ड 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 (एपीआई लेवल 37) और इसके बाद के वर्शन को टारगेट करने वाले ऐप्लिकेशन के लिए, सिस्टम अपने-आप मौजूदा Intent.ACTION_PICK इंटेंट को अपग्रेड करता है, ताकि नए कॉन्टैक्ट पिकर इंटरफ़ेस का इस्तेमाल किया जा सके.

अगर आपके ऐप्लिकेशन में पहले से ही ACTION_PICK का इस्तेमाल किया जा रहा है, तो आपको नया यूज़र इंटरफ़ेस (यूआई) पाने के लिए, अपने कोड में बदलाव करने की ज़रूरत नहीं है. हालांकि, नई सुविधाओं का फ़ायदा पाने के लिए, आपको अपने इंटिग्रेशन को अपडेट करना होगा. जैसे, संपर्क डेटा के बारे में क्वेरी करने के लिए एक ही Uri पाना, निजी और वर्क प्रोफ़ाइल के बीच स्विच करना या डेटा फ़ील्ड के लिए कई अनुरोध करना. इसके लिए, आपको ContactsPickerSessionContract.ACTION_PICK_CONTACTS या नए इंटेंट एक्स्ट्रा का इस्तेमाल करना होगा.

टारगेट किए गए पुराने एसडीके पर टेस्टिंग

Android 17 और इसके बाद के वर्शन वाले डिवाइसों पर, नए पिकर के व्यवहार को टेस्ट किया जा सकता है. भले ही, आपका ऐप्लिकेशन एसडीके के पुराने वर्शन को टारगेट करता हो. इसके लिए, आपको अपने ACTION_PICK इंटेंट में EXTRA_USE_SYSTEM_CONTACTS_PICKER बूलियन एक्स्ट्रा जोड़ना होगा.

सबसे सही तरीके

  • सिर्फ़ ज़रूरी अनुमति का अनुरोध करें: अगर आपके ऐप्लिकेशन को सिर्फ़ एसएमएस भेजने की ज़रूरत है, तो Phone.CONTENT_ITEM_TYPE का अनुरोध करें. फ़ोन नंबर चुनने वाला टूल, उन संपर्कों को अपने-आप फ़िल्टर कर देगा जिनके पास फ़ोन नंबर नहीं हैं. इससे उपयोगकर्ता को बेहतर यूज़र इंटरफ़ेस (यूआई) मिलेगा.
  • हर संपर्क के लिए कई डेटा एंट्री मैनेज करना: किसी संपर्क के लिए अक्सर कई ईमेल पते या फ़ोन नंबर होते हैं. उपयोगकर्ता को ये विकल्प साफ़ तौर पर और आसानी से दिखें, इसके लिए हमारा सुझाव है कि आप इन्हें ContactsContract.Contacts.LOOKUP_KEY का इस्तेमाल करके ग्रुप करें. इसके अलावा, हर एंट्री (जैसे, ऑफ़िस या निजी) के लिए खास लेबल वापस पाए जा सकते हैं, ताकि आपके ऐप्लिकेशन के इंटरफ़ेस में ज़्यादा बेहतर तरीके से चुनने के विकल्प दिए जा सकें.
  • डेटा को तुरंत सेव करें: सेशन यूआरआई, पढ़ने की अनुमति कुछ समय के लिए देता है. अगर आपको बाद में इस संपर्क जानकारी को ऐक्सेस करना है (ऐप्लिकेशन की प्रोसेस बंद होने के बाद), तो आपके ऐप्लिकेशन को संपर्क डेटा सेव करके रखना होगा.
  • खाते के डेटा पर भरोसा न करें: उपयोगकर्ता की निजता को सुरक्षित रखने और फ़िंगरप्रिंटिंग को रोकने के लिए, नतीजों से खाते के हिसाब से मेटाडेटा हटा दिया जाता है.