संपर्क पिकर

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

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

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

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

सामान्य MIME टाइप में ये शामिल हैं:

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

पिकर लॉन्च करना

पिकर लॉन्च करने के लिए, StartActivityForResult कॉन्ट्रैक्ट के साथ registerForActivityResult का इस्तेमाल करें. इंटेंट को इस तरह कॉन्फ़िगर किया जा सकता है कि एक या एक से ज़्यादा संपर्क चुने जा सकें.

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

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 पाना, निजी और ऑफ़िस की प्रोफ़ाइल के बीच स्विच करना या एक से ज़्यादा डेटा फ़ील्ड के लिए अनुरोध करना. इसके लिए, Intent.ACTION_PICK_CONTACTS या नए इंटेंट एक्स्ट्रा का इस्तेमाल करें.

टारगेट एसडीके के पुराने वर्शन पर जांच करना

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

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

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