เครื่องมือเลือกรายชื่อติดต่อของ Android เป็นอินเทอร์เฟซที่ได้มาตรฐานและเรียกดูได้สำหรับผู้ใช้ในการ
แชร์รายชื่อติดต่อกับแอปของคุณ เครื่องมือเลือกนี้พร้อมใช้งานในอุปกรณ์ที่ใช้
Android 17 (API ระดับ 37) ขึ้นไป โดยเป็นทางเลือกที่ช่วยรักษาความเป็นส่วนตัวแทนREAD_CONTACTSสิทธิ์แบบกว้าง แทนที่จะขอสิทธิ์เข้าถึงสมุดที่อยู่ทั้งหมดของผู้ใช้ แอปจะระบุฟิลด์ข้อมูลที่ต้องการ เช่น หมายเลขโทรศัพท์หรืออีเมล และผู้ใช้จะเลือกรายชื่อติดต่อที่ต้องการแชร์ได้ ซึ่งจะให้สิทธิ์แอปของคุณในการเข้าถึงแบบอ่านเฉพาะข้อมูลที่เลือก เพื่อให้ควบคุมได้อย่างละเอียดพร้อมมอบประสบการณ์ของผู้ใช้ที่สอดคล้องกันด้วยความสามารถในการค้นหาในตัว การสลับโปรไฟล์ และการเลือกหลายรายการโดยไม่ต้องสร้างหรือดูแลรักษา UI
ผสานรวมเครื่องมือเลือกรายชื่อติดต่อ
หากต้องการผสานรวมเครื่องมือเลือกรายชื่อติดต่อ ให้ใช้ Intent.ACTION_PICK_CONTACTS Intent
Intent นี้จะเปิดตัวเครื่องมือเลือกและส่งคืนรายชื่อติดต่อที่เลือกไปยังแอปของคุณ
เครื่องมือเลือกรายชื่อติดต่อช่วยให้คุณระบุฟิลด์ข้อมูลหลายรายการที่แอปต้องการได้พร้อมกัน ซึ่งแตกต่างจาก ACTION_PICK แบบเดิม โดยทำได้โดยใช้
Intent.EXTRA_REQUESTED_DATA_FIELDS และส่ง ArrayList<String> ของ MIME
types ที่กำหนดไว้ใน ContactsContract.CommonDataKinds
ประเภท MIME ทั่วไป ได้แก่
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPEContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE
เปิดเครื่องมือเลือก
ใช้ registerForActivityResult กับสัญญา StartActivityForResult เพื่อ
เปิดใช้เครื่องมือเลือก คุณกำหนดค่า Intent เพื่ออนุญาตการเลือกรายการเดียวหรือหลายรายการได้
// 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)
}
}
}
โหมดการเลือก
UI ของเครื่องมือเลือกรายชื่อติดต่อจะปรับตามช่องข้อมูลที่ขอ ผู้ใช้สามารถเลือกทั้งระเบียนรายชื่อติดต่อ เมื่อต้องการหลายฟิลด์ หรือเลือกรายการข้อมูลที่เฉพาะเจาะจงจาก ภายในข้อมูลของรายชื่อติดต่อ ทั้งนี้ขึ้นอยู่กับข้อกำหนดเหล่านี้
เลือกรายชื่อติดต่อเดียว
ในตัวอย่างนี้ แอปขอเฉพาะหมายเลขโทรศัพท์ เครื่องมือเลือกจะกรอง รายการเพื่อแสดงเฉพาะรายชื่อติดต่อที่มีหมายเลขโทรศัพท์และให้ผู้ใช้เลือกหมายเลขที่ต้องการ
// 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 extra คุณ
จำกัดจำนวนรายการที่ผู้ใช้เลือกได้ (ไม่บังคับ)
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 และ URI ของเซสชัน 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 (ระดับ API 37) ขึ้นไป ระบบจะอัปเกรด Intent.ACTION_PICK Intent ที่มีอยู่โดยอัตโนมัติเพื่อใช้อินเทอร์เฟซเครื่องมือเลือกรายชื่อติดต่อใหม่
หากแอปใช้ ACTION_PICK อยู่แล้ว คุณไม่จำเป็นต้องเปลี่ยนโค้ดเพื่อ
รับ UI ใหม่ อย่างไรก็ตาม หากต้องการใช้ประโยชน์จากฟีเจอร์ใหม่ๆ เช่น
รับ Uri รายการเดียวเพื่อค้นหาข้อมูลรายชื่อติดต่อ สลับระหว่างโปรไฟล์ส่วนตัวและโปรไฟล์งาน หรือคำขอฟิลด์ข้อมูลหลายรายการ คุณต้องอัปเดตการติดตั้งใช้งานเพื่อใช้ Intent.ACTION_PICK_CONTACTS หรือส่วนเพิ่มเติมของ Intent ใหม่
การทดสอบใน SDK เป้าหมายรุ่นเก่า
คุณสามารถทดสอบลักษณะการทำงานใหม่ของเครื่องมือเลือกในอุปกรณ์ที่ใช้ Android 17 ขึ้นไปได้ แม้ว่าแอปจะกำหนดเป้าหมายเป็น SDK เวอร์ชันที่ต่ำกว่าก็ตาม โดยการเพิ่มEXTRA_USE_SYSTEM_CONTACTS_PICKERบูลีนพิเศษลงใน Intent ของACTION_PICK
แนวทางปฏิบัติแนะนำ
- ขอเฉพาะสิ่งที่จำเป็น: หากแอปของคุณต้องการส่ง SMS เท่านั้น
ให้ขอ
Phone.CONTENT_ITEM_TYPEเครื่องมือเลือกจะกรองรายชื่อติดต่อที่ไม่มีหมายเลขโทรศัพท์ออกโดยอัตโนมัติ ทำให้ UI สำหรับผู้ใช้ดูสะอาดตามากขึ้น - การจัดการรายการข้อมูลหลายรายการต่อผู้ติดต่อ 1 ราย: ผู้ติดต่อแต่ละรายมักมีอีเมลหรือหมายเลขโทรศัพท์หลายรายการ
เราขอแนะนำให้จัดกลุ่มโดยใช้
ContactsContract.Contacts.LOOKUP_KEYเพื่อช่วยให้มั่นใจว่าข้อมูลเหล่านี้จะแสดงต่อผู้ใช้อย่างชัดเจนและใช้งานง่าย นอกจากนี้ คุณยังดึงป้ายกำกับที่เฉพาะเจาะจงสำหรับแต่ละรายการ (เช่น งานหรือส่วนตัว) เพื่อเสนอตัวเลือกการเลือกที่ละเอียดยิ่งขึ้นภายในอินเทอร์เฟซของแอปได้ด้วย - คงข้อมูลทันที: URI ของเซสชันให้สิทธิ์อ่านชั่วคราว หากต้องการเข้าถึงข้อมูลติดต่อนี้ในภายหลัง (หลังจากระบบปิดกระบวนการของแอป) แอปจะต้องเก็บข้อมูลรายชื่อติดต่อไว้
- อย่าใช้ข้อมูลบัญชี: ระบบจะนำข้อมูลเมตาเฉพาะบัญชีออกจากผลการค้นหาเพื่อปกป้องความเป็นส่วนตัวของผู้ใช้และป้องกันการลายนิ้วมือ