因项目需求,需要将本产品的客服电话信息,默默写入用户手机通讯录中,作为一个程序员,内心是拒绝的,但仍要实现该功能。
1. 动态申请读写权限
首先,在 Maniifest.xml 文件中添加如下两个权限的声明:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
然后在代码中需要用到读写权限时,动态申请权限:
requestRuntimePermission(new String[]{Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS}, new PermissionListener() {
@Override
public void onGranted() {
//todo 处理接下来的流程
}
@Override
public void onDenied(List<String> deniedPermission) {
showToast("权限被拒绝");
}
});
2. 判断该联系人是否存在,如果存在,仅追加手机号码;不存在,则新增该联系人的头像、姓名及手机号等相关信息。
/**
* 添加联系人信息
*
*/
public static void insertConstacts(Context context, String name, List<String> list) {
try {
//该店管家用户是否存在,存在的话,就追加号码,不存在新增联系人
long rawContactId = getContactsId(context, name);
ContentValues values = new ContentValues();
if (rawContactId == 0 ) {
//插入raw_contacts表,并获取_id属性
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
ContentResolver resolver = context.getContentResolver();
rawContactId = ContentUris.parseId(resolver.insert(uri, values));
//插入data表
uri = Uri.parse("content://com.android.contacts/data");
//add Name
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/name");
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
resolver.insert(uri, values);
values.clear();
//写入头像
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_poraital);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
values.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, out.toByteArray());
context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}
//写入手机号码
values.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone1);
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
//插入data表
Uri uri = Uri.parse("content://com.android.contacts/data");
context.getContentResolver().insert(uri, values);
} catch (Exception e) {
Log.i(TAG, "insertConstacts: e = " + e.getMessage());
e.printStackTrace();
}
}
/**
* 判断某个手机号是否存在
*/
public static boolean isThePhoneExist(Context context, String phoneNum) {
//uri= content://com.android.contacts/data/phones/filter/#
Cursor cursor = null;
try {
Uri uri = Uri.parse("content://com.android.contacts/data/phones/filter/" + phoneNum);
ContentResolver resolver = context.getContentResolver();
cursor = resolver.query(uri, new String[]{ContactsContract.Data.DISPLAY_NAME},
null, null, null); //从raw_contact表中返回display_name
if (cursor.moveToFirst()) {
//Log.i(TAG, "name=" + cursor.getString(0) + " , phoneNum = " + phoneNum);
cursor.close();
return true;
}
} catch (Exception e) {
//Log.i(TAG, "163 e =" + e.getMessage());
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
return false;
}
3. 查询数据库中所有的联系人
/**
* 获取所有联系人信息
*/
public static List<SysContactsListBean> getAllSysContacts(Context context) {
List<SysContactsListBean> list = new ArrayList<>();
try {
ContentResolver resolver = context.getContentResolver();
SysContactsListBean sysContactsListBean;
Uri uri = Uri.parse("content://com.android.contacts/data/phones");
Cursor cursor1 = resolver.query(uri,
new String[]{ContactsContract.Data.RAW_CONTACT_ID,
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER},
null, null, null);
while (cursor1.moveToNext()) {
sysContactsListBean = new SysContactsListBean();
sysContactsListBean.setCustomerId(cursor1.getLong(0));
sysContactsListBean.setCustomerName(cursor1.getString(1));
sysContactsListBean.setPhoneNumber(cursor1.getString(2));
list.add(sysContactsListBean);
}
} catch (Exception e) {
e.printStackTrace();
}
if (!CollectorUtils.isEmpty(list)) {
Collections.sort(list, new Comparator<SysContactsListBean>() {
@Override
public int compare(SysContactsListBean o1, SysContactsListBean o2) {
return o2.getCustomerName().compareTo(o1.getCustomerName());
}
});
}
return list;
}
4. 总结
还有几个表需要特别注意:
4.1 raw_contacts:存放联系人的 ID,_id属性为主键,声明为autoincrement,即不需要手动设置,其他属性也不需要手动设置就有默认值;display_name属性为姓名;sort_key属性可以用于查询后的排序
4.2 mimetypes:存放数据的类型,比如"vnd.android.cursor.item/name"表示“姓名”类型的数据,"vnd.android.cursor.item/phone_v2"表示“电话”类型的数据;
4.3 data:存放具体的数据;raw_contact_id 属性用来连接raw_contacts表,每条记录表示一个具体数据;raw_contact_id 需要重点记住,手机中显示的每一个联系人对应一个固定的raw_contact_id,raw_contact_id对应着 raw_contacts表的 _id ,他俩是相同的值,两个表之间的关系必须理清。(我刚开始就是没有理清表之间的关系,以及各个字段代表的意思,做起来就感觉很混乱,这3个表很重要)我们主要的数据(email、phone等)都存放在data表;
ps:有些手机系统下,data 表的 raw_contact_id 和 data 表的 raw_contacts表的 _id 不一定相同,如果用 后者的id 作为主键来追加手机号码,就会出现追加不成功的现象。切记,切记。