連絡先選択ツール

Android の連絡先選択ツールは、ユーザーがアプリと連絡先を共有するための標準化された閲覧可能なインターフェースです。Android 17 以降を搭載したデバイスで利用でき、広範な READ_CONTACTS 権限に代わるプライバシー保護の選択肢を提供します。ユーザーのアドレス帳全体へのアクセスをリクエストする代わりに、アプリは電話番号やメールアドレスなど、必要なデータ フィールドを指定し、ユーザーは共有する特定の連絡先を選択します。これにより、アプリは選択したデータへの読み取りアクセス権のみを取得し、きめ細かい制御を確保しながら、UI を構築または維持することなく、組み込みの検索、プロファイルの切り替え、複数選択機能による一貫したユーザー エクスペリエンスを提供できます。

連絡先ピッカーを統合する

連絡先選択ツールを統合するには、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 を使用して、ピッカーを起動します。1 つまたは複数の選択を許可するようにインテントを構成できます。

連絡先を 1 つ選択する

この例では、アプリは電話番号のみをリクエストしています。ピッカーは、電話番号のある連絡先のみを表示するようにリストをフィルタし、ユーザーが特定の番号を選択できるようにします。

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 エクストラを追加します。ユーザーが選択できるアイテムの数を制限することもできます。

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 は、選択したデータに対する一時的な読み取りアクセス権を付与します。

この URI は、標準の ContentResolver を使用してクエリできます。結果の 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 インテントは、新しい連絡先選択ツール インターフェースを使用するように自動的にアップグレードされます。

アプリですでに ACTION_PICK を使用している場合は、新しい UI を受け取るためにコードを変更する必要はありません。ただし、連絡先データのクエリに単一の Uri を使用する、個人用プロファイルと仕事用プロファイルを切り替える、複数のデータ フィールド リクエストを行うなどの新機能を利用するには、Intent.ACTION_PICK_CONTACTS または新しいインテント エクストラを使用するように実装を更新する必要があります。

古い SDK でのテスト

アプリのターゲット SDK バージョンが低い場合でも、ACTION_PICK インテントに EXTRA_USE_SYSTEM_CONTACTS_PICKER ブール値の追加情報を追加することで、Android 17 以降を搭載したデバイスで新しいピッカーの動作をテストできます。

ベスト プラクティス

  • 必要なものだけをリクエストする: アプリで SMS を送信するだけの場合は、Phone.CONTENT_ITEM_TYPE をリクエストします。電話番号のない連絡先は自動的にフィルタされ、ユーザーにとってよりクリーンな UI が実現します。
  • データをすぐに永続化する: セッション URI は一時的な読み取り権限を付与します。後で(アプリのプロセスが強制終了された後)この連絡先情報にアクセスする必要がある場合は、アプリで連絡先データを永続化する必要があります。
  • アカウント データに依存しない: ユーザーのプライバシーを保護し、フィンガープリントを防止するため、アカウント固有のメタデータは結果から削除されます。