search
分发文档
分发文档/应用分发/生态政策/控件适配指南/联系人选择控件
联系人选择控件更新时间:2025-12-26 11:14:00

一、背景

传统上,应用在读取用户存储在设备的联系人数据时,通常需要通过权限弹窗,向用户申请读取联系人权限android.permission.READ_CONTACTS,由用户主动授权后,应用才能使用ContentProvider API读取到联系人数据。该方案存在诸多痛点,举例如下:

  • 应用一般不需要读取完整的联系人数据,但申请并获得读取联系人权限,将获得读取完整联系人数据的能力,容易引起监管、用户的质疑,增加应用澄清的负担。
  • 与此同时,用户出于隐私考虑,可能会拒绝授权,进而导致应用相关功能不可用,影响应用的用户体验。
  • 此外,用户如果多次误拒绝授权,但仍然希望使用联系人相关的应用功能,应用将需引导用户,跳转到设置中进行手动授权,用户才能继续正常使用联系人相关应用功能,影响应用的用户体验。

为解决上述问题,联系人Picker应运而生。应用可通过接入联系人Picker,弹出系统级的联系人Picker选择界面,由用户手动选择需要的联系人信息,授权给应用读取,具有如下显著优势:

  • 应用不再需要申请联系人权限,解决用户拒绝授权导致应用功能不可用问题。
  • 应用只能读取用户选择的联系人数据,满足用户最小化授权的需求,同时减少应用的合规压力。

二、功能介绍

1. 应用场景介绍

应用通过接入联系人Picker,可在联系人相关功能中(如图一),拉起系统级的联系人Picker选择界面(如图二)。用户可在联系人Picker界面中执行选择、搜索等(如图二、图三),用户选择希望授权的联系人后,将返回应用界面。应用即可读取到用户选择并授权给应用的联系人数据(如图四)。

图一:

图二:

图三:

图四:

2. 联系人Picker功能介绍

联系人Picker整体支持如下功能:

2.1 单选

  • 电话号码信息单选:用户可选择一个电话号码信息,授权给应用,应用可读取到姓名、电话号码等信息,如图五。
  • 邮箱地址信息单选:用户可选择一个邮箱地址信息,授权给应用,应用可读取到姓名、邮箱地址等信息,如图六。
  • 联系人信息单选:用户可选择一个联系人信息,授权给应用,应用可读取到姓名等信息,如图七。

对应联系人Picker界面如下:

图五:

图六:

图七:

2.2 多选

  • 电话号码信息的多选:用户可选择一个或多个(最多不超过50个)电话号码信息,授权给应用,应用可逐个读取到姓名、电话号码等信息,如图八。
  • 邮箱地址信息的多选:用户可选择一个或多个(最多不超过50个)邮箱地址信息,授权给应用,应用可逐个读取到姓名、邮箱地址等信息,如图九。
  • 联系人信息的多选:用户可选择一个或多个(最多不超过50个)联系人信息,授权给应用,应用可逐个读取到姓名等信息,如图十。

对应联系人Picker界面如下:

图八:

图九:

图十:

三、 适用范围

当前支持联系人Picker的操作系统版本如下:

  • HyperOS 3(基于Android 16)及以上
  • ColorOS 16(基于Android 16)及以上
  • OriginOS 6(基于Android 16)及以上
  • MagicOS 10(基于Android 16)及以上

四、使用说明

以下详细说明适配联系人Picker的接口。

1. Intent构造参数

应用按下述Intent参数说明,构造Intent,使用startActivityForResult(Intent intent, int requestCode),即可拉起联系人Picker界面。

1.1 action

构造Intent,应用需传入action参数,必选。

构造参数action
参数类型String
构造APInew Intent(String action)
new Intent(String action, Uri data)
Intent.setAction(String action)
联系人Picker取值Intent.ACTION_PICK="android.intent.action.PICK"

调用示例:

Intent intent = new Intent(Intent.ACTION_PICK);

1.2 Type

应用还需要传入type或data参数,二选一,用于指定联系人数据类型,必须指定,推荐使用type参数。

构造参数type
参数类型String
构造APIIntent.setType(String type)
Intent.setDataAndType(Uri data, String type)
联系人Picker取值联系人电话号码 ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE
联系人邮箱 ContactsContract.CommonDataKinds.Email.CONTENT_TYPE
联系人 ContactsContract.Contacts.CONTENT_TYPE

调用示例:

intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);

1.3 data

应用如不传入type参数,则需传入data参数。

备注:type与data参数二选一,用于指定联系人数据类型,必须指定,推荐使用type参数。

构造参数data
参数类型Uri
构造APIIntent.setData(Uri data)
new Intent(String action, Uri data)
Intent.setDataAndType(Uri data, String type)
联系人Picker取值联系人电话号码 ContactsContract.CommonDataKinds.Phone.CONTENT_URI
联系人邮箱 ContactsContract.CommonDataKinds.Email.CONTENT_URI
联系人 ContactsContract.Contacts.CONTENT_URI

调用示例:

intent.setData(ContactsContract.CommonDataKinds.Phone.CONTENT_URI)

1.4 Extras: EXTRA_ALLOW_MULTIPLE

应用可选传入是否多选的EXTRA_ALLOW_MULTIPLE参数,如不传入,则默认为单选。

构造参数EXTRA_ALLOW_MULTIPLE
参数类型boolean
构造APIIntent.putExtra(String name, boolean value)
联系人Picker取值name参数取值:Intent.EXTRA_ALLOW_MULTIPLE
name参数说明:是否多选
value参数取值范围:true/false
value参数说明:
· true对应多选,
· false对应单选
默认值:false,不设置默认为false,单选

使用示例:

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)

2. Intent返回值

应用通过上述Intent构造参数构造出目标intent,加上大于0的requestCode,通过startActivityForResult(Intent intent, int requestCode)即可拉起系统联系人Picker界面。
用户可在联系人Picker界面操作,选择联系人数据,授权给应用。
用户选择后,应用可在onActivityResult(Int requestCode, Int resultCode, Intent data)回调中获取requestCode以及resultCode结果代码、data数据,其中data中包含联系人数据对应的Uri。

2.1 requestCode:

onActivityResult回调中,requestCode值就是传入startActivityForResultrequestCode,关联回调的结果与对应的请求。

返回值requestCode
参数类型int
取值与startActivityForResult(Intent intent, int requestCode)时传入的requestCode一致,代表对应请求的回调。

2.2 resultCode

onActivityResult回调中,resultCode代表请求的结果。

返回值resultCode
参数类型int
取值范围Activity.RESULT_OK,成功
Activity.RESULT_CANCELED,被取消

2.3 data

onActivityResult回调中,data包含授权给应用的联系人数据对应的URI。

返回值data
参数类型Intent
取值范围单选:
data.getData()拿到Uri,可通过ContentResolver.query读取数据
多选:
data.getClipData()获取到ClipData实例,
可通过ClipData.getItemCount拿到返回的个数,
ClipData.getItemAt(index).getUri()拿到对应index的Uri,然后通过ContentResolver.query读取数据

3. 通过Uri查询联系人数据

3.1 查询

通过回调,获取到联系人数据对应的Uri,即可使用getContentResolver().query(Uri)接口查询联系人数据,与使用权限读取联系人数据一致。

调用示例:

Cursor cursor = getContentResolver().query(contactUri, null, null, null, null)

3.2 字段

查询到的联系人数据中包含很多字段,应用可根据需求,读取指定字段。

完整字段请参考Android开发者网站:
https://developer.android.google.cn/reference/android/provider/ContactsContract

https://developer.android.google.cn/reference/android/provider/ContactsContract.CommonDataKinds.Phone

https://developer.android.google.cn/reference/android/provider/ContactsContract.CommonDataKinds.Email

https://developer.android.google.cn/reference/android/provider/ContactsContract.Contacts

下表展示关键的数据字段:

类型数据名称数据字段
联系人电话号码姓名ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
联系人电话号码号码ContactsContract.CommonDataKinds.Phone.NUMBER
联系人邮箱姓名ContactsContract.CommonDataKinds.Email.DISPLAY_NAME_PRIMARY
联系人邮箱邮箱地址ContactsContract.CommonDataKinds.Email.ADDRESS
联系人姓名ContactsContract.Contacts.DISPLAY_NAME

调用示例:

int nameIndex = 
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);String name = cursor.getString(nameIndex);int phoneIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);String phone = cursor.getString(phoneIndex);

五、调用示例

1. AndroidManifest配置

1.1 移除权限配置

在支持联系人Picker的系统版本,应用不再需要申请读取联系人权限。

  • 应用可移除AndroidManiest.xml中的读取联系人权限申请
<!--<uses-permission android:name="android.permission.READ_CONTACTS" />-->
  • 应用也可在AndroidManifest.xml中配置读取联系人权限最高可用的Android版本,以最高支持在Android 15(SDK版本号35)申请读取联系人权限为例
<uses-permission android:name="android.permission.READ_CONTACTS" android:maxSdkVersion="35" />

1.2 增加query配置

在应用的AndroidManifest.xml增加如下配置

<queries>
<intent>
<action android:name="android.intent.action.PICK" />
<data android:mimeType="vnd.android.cursor.dir/*" />
</intent></queries>

2. 判断系统是否支持

应用可通过如下方法,判断联系人Picker是否可用:

2.1 Java示例

//传入intent,是否PackageManager查询是否支持

public boolean isContactsPickerAvailable(Intent intent) {
return getPackageManager().resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY) != null;}

应用可在不支持联系人Picker的操作系统,继续申请读取联系人权限。

Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
startActivityForResult(intent, REQUEST_CODE_SINGLE_PICK_CONTACTS);} else {
//不支持,申请权限}

2.2 Kotlin示例

//传入intent,是否PackageManager查询是否支持

fun isContactsPickerAvailable(intent: Intent): Boolean {
return getPackageManager().resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY) != null;}

应用可在不支持联系人Picker的操作系统,继续申请读取联系人权限。

val intent = Intent(Intent.ACTION_PICK)
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE)if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
startActivityForResult(intent, REQUEST_CODE_SINGLE_PICK_CONTACTS)} else {
//不支持,申请权限}

3. 单选联系人示例

以下为使用联系人Picker相关API拉起单选联系人界面,并读取用户选择的联系人数据的完整示例。

3.1 Java用法(未集成Android X场景)

以下是Java代码示例,在未集成AndroidX的场景,使用原生API。

final int REQUEST_CODE_SINGLE_PICK_CONTACTS = 1001;
public void pickSingleContact() {
//构造intent,设置action
Intent intent = new Intent(Intent.ACTION_PICK);
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
startActivityForResult(intent, REQUEST_CODE_SINGLE_PICK_CONTACTS);
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission");
}}
//接收回调@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);
//校验requestCode是否与startActivityForResult传入的一致
if (requestCode == REQUEST_CODE_SINGLE_PICK_CONTACTS) {
Log.d(TAG, "resultCode:" + resultCode);
//判断结果是否成功
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
return;
}
//读取到用户选择的联系人数据的Uri
Uri contactUri = data.getData();
if (contactUri == null) {
return;
}
//通过ContentResolver.query接口从Uri读取数据
try (Cursor cursor = getContentResolver().query(contactUri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String name = cursor.getString(nameIndex);
//读取手机号码字段
int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String phone = cursor.getString(phoneIndex);
Log.d(TAG, "name:" + name + ",phone:" + phone);
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled");
}
}}

3.2 Kotlin用法(未集成Android X场景)

以下是Kotlin代码示例,在未集成AndroidX的场景,使用原生API。

val REQUEST_CODE_SINGLE_PICK_CONTACTS = 1001
fun pickSingleContact() {
//构造intent,设置action
val intent = Intent(Intent.ACTION_PICK)
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE)
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
startActivityForResult(intent, REQUEST_CODE_SINGLE_PICK_CONTACTS)
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission")
}}
//接收回调override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
//校验requestCode是否与startActivityForResult传入的一致
if (requestCode == REQUEST_CODE_SINGLE_PICK_CONTACTS) {
Log.d(TAG, "resultCode:" + resultCode)
//判断结果是否成功
if (resultCode == Activity.RESULT_OK) {
//读取到用户选择的联系人数据的Uri
val contactUri = data?.getData()
if (contactUri == null) {
return
}
//通过ContentResolver.query接口从Uri读取数据
getContentResolver().query(contactUri, null, null, null, null).use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
val nameIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val name = cursor.getString(nameIndex)
//读取手机号码字段
val phoneIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val phone = cursor.getString(phoneIndex)
Log.d(TAG, "name:" + name + ",phone:" + phone)
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled")
}
}}

3.3 Java用法(集成Android X场景)

以下是Java代码示例,在集成androidx.activity jetpack库的场景,使用AndroidX的API。

public void pickSingleContact2() {
//构造intent,设置action
Intent intent = new Intent(Intent.ACTION_PICK);
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
contactActivityResultLauncher.launch(intent);
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission");
}}
//使用androidx.activity的ActivityResultLauncherActivityResultLauncher<Intent> contactActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
Log.d(TAG, "resultCode:" + result.getResultCode());
//判断结果是否成功
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
if (data == null) {
return;
}
//读取到用户选择的联系人数据的Uri
Uri contactUri = data.getData();
if (contactUri == null) {
return;
}
//通过ContentResolver.query接口从Uri读取数
try (Cursor cursor = getContentResolver().query(contactUri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String name = cursor.getString(nameIndex);
//读取电话号码字段
int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String phone = cursor.getString(phoneIndex);
Log.d(TAG, "name:" + name + ",phone:" + phone);
}
}
} else if (result.getResultCode() == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled");
}
}
});

3.4 Kotlin用法(集成Android X场景)

以下是Kotlin代码示例,在集成androidx.activity jetpack库的场景,使用AndroidX的API。

fun pickSingleContact2() {
//构造intent,设置action
val intent = Intent(Intent.ACTION_PICK)
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
contactActivityResultLauncher.launch(intent)
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission")
}}
//使用androidx.activity的ActivityResultLauncherval contactActivityResultLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()) { result ->
Log.d(TAG, "resultCode:" + result.resultCode)
//判断结果是否成功
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
//读取到用户选择的联系人数据的Uri
val contactUri = data?.getData()
if (contactUri == null)
return@registerForActivityResult

//通过ContentResolver.query接口从Uri读取数
getContentResolver().query(contactUri, null, null, null, null)
.use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
val nameIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val name = cursor.getString(nameIndex)
//读取电话号码字段
val phoneIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val phone = cursor.getString(phoneIndex)
Log.d(TAG, "name:" + name + ",phone:" + phone)
}
}
} else if (result.resultCode == RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled")
}}

4. 多选联系人示例

以下为使用联系人Picker相关API拉起多选联系人界面,并读取用户选择的联系人数据的完整示例。

4.1 Java用法(未集成Android X场景)

以下是Java代码示例,在未集成AndroidX的场景,使用原生API。

final int REQUEST_CODE_MULTIPLE_PICK_CONTACTS = 10002;
public void pickMultipleContact() {
//构造intent,设置action
Intent intent = new Intent(Intent.ACTION_PICK);
//设置intent的是否多选extra参数,指定为true,使用多选
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
startActivityForResult(intent, REQUEST_CODE_MULTIPLE_PICK_CONTACTS);
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission");
}}
//接收回调@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//校验requestCode是否与startActivityForResult传入的一致
if (requestCode == REQUEST_CODE_MULTIPLE_PICK_CONTACTS) {
Log.d(TAG, "resultCode:" + resultCode);
//判断结果是否成功
if (resultCode == Activity.RESULT_OK) {
if (data == null) {
return;
}
//从data中取出ClipData
ClipData clipData = data.getClipData();
if (clipData == null) {
return;
}
//遍历ClipData
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
if (item == null) {
continue;
}
//逐个读取用户选择的联系人数据的Uri
Uri contactUri = item.getUri();
if (contactUri == null) {
continue;
}
//通过ContentResolver.query接口从Uri读取数据
try (Cursor cursor = getContentResolver().query(contactUri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String name = cursor.getString(nameIndex);
//读取手机号码字段
int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String phone = cursor.getString(phoneIndex);
Log.d(TAG, "name:" + name + ",phone:" + phone);
}
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled");
}
}}

4.2 Kotlin用法(未集成Android X场景)

以下是Kotlin代码示例,在未集成AndroidX的场景,使用原生API。

val REQUEST_CODE_MULTIPLE_PICK_CONTACTS = 10002
fun pickMultipleContact() {
//构造intent,设置action
val intent = Intent(Intent.ACTION_PICK)
//设置intent的是否多选extra参数,指定为true,使用多选
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE)
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
startActivityForResult(intent, REQUEST_CODE_MULTIPLE_PICK_CONTACTS)
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission")
}}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_MULTIPLE_PICK_CONTACTS) {
Log.d(TAG, "resultCode:" + resultCode)
//判断结果是否成功
if (resultCode == Activity.RESULT_OK) {
//从data中取出ClipData
val clipData = data?.getClipData()
if (clipData == null) {
return
}
//遍历ClipData
for (i in 0..<clipData.getItemCount()) {
val item = clipData.getItemAt(i)
//逐个读取用户选择的联系人数据的Uri
val contactUri = item.getUri()
if (contactUri == null) {
continue
}
//通过ContentResolver.query接口从Uri读取数据
getContentResolver().query(contactUri, null, null, null, null).use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
val nameIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val name = cursor.getString(nameIndex)
//读取手机号码字段
val phoneIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val phone = cursor.getString(phoneIndex)
Log.d(TAG, "name:" + name + ",phone:" + phone)
}
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled")
}
}}

4.3 Java用法(集成Android X场景)

以下是Java代码示例,在集成androidx.activity jetpack库的场景,使用AndroidX的API。

public void pickMultiContact2() {
//构造intent,设置action
Intent intent = new Intent(Intent.ACTION_PICK);
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
//设置intent的是否多选extra参数,指定为true,使用多选
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
multiContactActivityResultLauncher.launch(intent);
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission");
}}
//使用androidx.activity的ActivityResultLauncherActivityResultLauncher<Intent> multiContactActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
Log.d(TAG, "resultCode:" + result.getResultCode());
//判断结果是否成功
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
if (data == null) {
return;
}
//从data中取出ClipData
ClipData clipData = data.getClipData();
if (clipData == null) {
return;
}
//遍历ClipData
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
if (item == null) {
continue;
}
//逐个读取用户选择的联系人数据的Uri
Uri contactUri = item.getUri();
if (contactUri == null) {
continue;
}
//通过ContentResolver.query接口从Uri读取数据
try (Cursor cursor = getContentResolver().query(contactUri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
String name = cursor.getString(nameIndex);
//读取电话号码字段
int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String phone = cursor.getString(phoneIndex);
Log.d(TAG, "name:" + name + ",phone:" + phone);
}
}
}
} else if (result.getResultCode() == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled");
}
}
});

4.4 Kotlin用法(集成Android X场景)

以下是Kotlin代码示例,在集成androidx.activity jetpack库的场景,使用AndroidX的API。

fun pickMultiContact2() {
//构造intent,设置action
val intent = Intent(Intent.ACTION_PICK)
//设置intent的type参数,指定为电话号码类型
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE)
//设置intent的是否多选extra参数,指定为true,使用多选
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
//判断系统是否支持联系人Picker
if (isContactsPickerAvailable(intent)) {
//支持,拉起联系人Picker
multiContactActivityResultLauncher.launch(intent)
} else {
//不支持,申请权限
Log.d(TAG, "Not Support, request permission")
}}
//使用androidx.activity的ActivityResultLauncherval multiContactActivityResultLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()) { result ->
Log.d(TAG, "resultCode:" + result.resultCode)
//判断结果是否成功
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
//从data中取出ClipData
val clipData = data?.getClipData()
if (clipData == null) {
return@registerForActivityResult
}
//遍历ClipData
for (i in 0..<clipData.getItemCount()) {
val item = clipData.getItemAt(i)
//逐个读取用户选择的联系人数据的Uri
val contactUri = item.getUri()
if (contactUri == null) {
continue
}
//通过ContentResolver.query接口从Uri读取数据
getContentResolver().query(contactUri, null, null, null, null)
.use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
//读取姓名字段
val nameIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
val name = cursor.getString(nameIndex)
//读取电话号码字段
val phoneIndex =
cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
val phone = cursor.getString(phoneIndex)
Log.d(TAG, "name:" + name + ",phone:" + phone)
}
}
}
} else if (result.resultCode == Activity.RESULT_CANCELED) {
//用户在选择过程中取消
Log.d(TAG, "user canceled")
}}

六、 Android开发者文档参考

  • Intent相关

联系人提供程序:https://developer.android.google.cn/identity/providers/contacts-provider?hl=zh-cn#Intents

常见intent:https://developer.android.google.cn/guide/components/intents-common?hl=zh-cn#PickContact

  • ActivityResult相关

startActivityForResult:https://developer.android.google.cn/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int)

从Activity获取结果:https://developer.android.com/training/basics/intents/result?hl=zh-cn

  • Provider数据查询相关

ContentResolver.query查询:https://developer.android.google.cn/reference/android/content/ContentResolver

  • 联系人数据相关字段

ContactsContract:https://developer.android.google.cn/reference/android/provider/ContactsContract

ContactsContract.CommonDataKinds.Phone:https://developer.android.google.cn/reference/android/provider/ContactsContract.CommonDataKinds.Phone

ContactsContract.CommonDataKinds.Email:https://developer.android.google.cn/reference/android/provider/ContactsContract.CommonDataKinds.Email

ContactsContract.Contacts:https://developer.android.google.cn/reference/android/provider/ContactsContract.Contacts

该适配指南与金标联盟官网适配指南一致,您也可查阅金标联盟官网中公示适配指南。

金标联盟官方文档地址:https://www.itgsa.com/doc/6631953378231296

上一篇:应用权限申请操作指南
下一篇:文件选择控件
文档内容是否有帮助?
有帮助
无帮助