聯絡人選擇工具

Android 聯絡人挑選器是標準化的可瀏覽介面,使用者可透過這個介面與應用程式分享聯絡人。挑選器適用於搭載 Android 17 以上版本的裝置,可做為廣泛 READ_CONTACTS 權限的替代方案,同時保護隱私權。應用程式不會要求存取使用者的完整地址簿,而是指定需要的資料欄位 (例如電話號碼或電子郵件地址),並由使用者選取要分享的特定聯絡人。這項功能可讓應用程式僅讀取所選資料,確保精細控管,同時提供一致的使用者體驗,包括內建搜尋、切換設定檔和多選功能,不必建構或維護使用者介面。

整合聯絡人挑選器

如要整合聯絡人挑選器,請使用 Intent.ACTION_PICK_CONTACTS 意圖。這項意圖會啟動挑選器,並將所選聯絡人傳回應用程式。

與舊版 ACTION_PICK 不同,聯絡人挑選器可讓您同時指定應用程式所需的多個資料欄位。您可以使用 Intent.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

啟動挑選器

使用 registerForActivityResultStartActivityForResult 合約啟動挑選工具。您可以將意圖設為允許單選或多選。

選取單一聯絡人

在本例中,應用程式只會要求電話號碼。挑選器會篩選清單,只顯示有電話號碼的聯絡人,並允許使用者選取特定號碼。

Kotlin

// Define the specific data fields you need
val requestedFields = arrayListOf(
    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
)

// Set up the intent
val pickContactIntent = Intent(Intent.ACTION_PICK_CONTACTS).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
    putStringArrayListExtra(Intent.EXTRA_REQUESTED_DATA_FIELDS, requestedFields)
}

// Launch the picker
pickContactLauncher.launch(pickContactIntent)

Java

// Define the specific data fields you need
ArrayList<String> requestedFields = new ArrayList<>();
requestedFields.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);

// Set up the intent
Intent pickContactIntent = new Intent(Intent.ACTION_PICK_CONTACTS);
pickContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);
pickContactIntent.putStringArrayListExtra(Intent.EXTRA_REQUESTED_DATA_FIELDS,
        requestedFields);

// Launch the picker
pickContactLauncher.launch(pickContactIntent);

選取多位聯絡人

如要啟用多重選取功能,請新增 Intent.EXTRA_ALLOW_MULTIPLE extra。您可以選擇限制使用者可選取的項目數量。

Kotlin

val requestedFields = arrayListOf(
    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
)

val pickMultipleIntent = Intent(Intent.ACTION_PICK_CONTACTS).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
    putStringArrayListExtra(Intent.EXTRA_REQUESTED_DATA_FIELDS, requestedFields)
    // Enable multi-select
    putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
    // Optional: Set a custom limit (max 50 recommended)
    putExtra(Intent.EXTRA_SELECTION_LIMIT, 10)
}

pickMultipleLauncher.launch(pickMultipleIntent)

處理結果

使用者完成選取後,系統會傳回 RESULT_OK 和工作階段 URI。這個 URI 可授予所選資料的臨時讀取權。

您可以使用標準 ContentResolver 查詢這個 URI。產生的 Cursor 包含所要求的資料欄位,並遵循 ContactsContract.Data 的結構定義。

Kotlin

private val pickContactLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        // The result data contains the Session URI
        val sessionUri = result.data?.data
        sessionUri?.let { uri ->
            processSelectedContacts(uri)
        }
    } else {
        // User cancelled the picker
    }
}

private fun processSelectedContacts(sessionUri: Uri) {
    // Define the projection (columns) you want to retrieve
    val projection = arrayOf(
        ContactsContract.Data.CONTACT_ID,
        ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
        ContactsContract.Data.MIMETYPE,
        ContactsContract.Data.DATA1 // Generic data column (Phone number, Email, etc.)
    )

    contentResolver.query(sessionUri, projection, null, null, null)?.use { cursor ->
        val mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
        val dataIdx = cursor.getColumnIndex(ContactsContract.Data.DATA1)
        val nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)

        while (cursor.moveToNext()) {
            val mimeType = cursor.getString(mimeTypeIdx)
            val dataValue = cursor.getString(dataIdx)
            val name = cursor.getString(nameIdx)

            when (mimeType) {
                ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
                    Log.d("ContactPicker", "Picked Phone: $dataValue for $name")
                }
                ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE -> {
                    Log.d("ContactPicker", "Picked Email: $dataValue for $name")
                }
            }
        }
    }
}

回溯相容性

如果應用程式指定 Android 17 以上版本為目標,系統會自動升級現有的 Intent.ACTION_PICK intent,改用新的聯絡人挑選器介面。

如果應用程式已使用 ACTION_PICK,則不需要變更程式碼即可接收新版 UI。不過,如要使用新功能,例如接收單一 Uri 來查詢聯絡人資料、在個人和工作資料夾之間切換,或是提出多個資料欄位要求,您必須更新實作項目,改用 Intent.ACTION_PICK_CONTACTS 或新的 Intent Extras。

在舊版 SDK 上測試

即使應用程式指定較低的 SDK 版本,您仍可在搭載 Android 17 以上版本的裝置上測試新的挑選器行為,方法是在 ACTION_PICK intent 中加入 EXTRA_USE_SYSTEM_CONTACTS_PICKER 布林值額外資訊。

最佳做法

  • 只要求必要的權限:如果應用程式只需要傳送簡訊,請要求 Phone.CONTENT_ITEM_TYPE。系統會自動篩除沒有電話號碼的聯絡人,讓使用者看到更簡潔的 UI。
  • 立即保存資料:工作階段 URI 會授予暫時的讀取權限。如果稍後需要存取這項聯絡資訊 (應用程式程序終止後),應用程式必須保留聯絡人資料。
  • 請勿依賴帳戶資料:為保護使用者隱私權及防止指紋辨識,系統會從結果中移除帳戶專屬的中繼資料。