安卓短信应用开发:如何通过recipient_id获取正确联系人姓名?
问题分析
你遇到的核心问题是对recipient_ids字段的理解有误:从content://mms-sms/conversations返回的recipient_ids,并不是ContactsContract.Contacts中的CONTACT_ID,而是Android短信系统内部维护的Recipient表ID(属于mms-sms私有数据库)。直接用这个ID去关联联系人表的CONTACT_ID,自然会拿到错误的结果。
解决方案
要通过recipient_ids获取正确的联系人姓名,需要先通过短信系统的规范地址表(canonical-addresses)拿到对应的实际号码,再通过号码去匹配联系人姓名;或者直接通过该表关联到联系人的CONTACT_ID。
步骤1:理解canonical-addresses表
这个表是mms-sms库用来映射内部收件人ID和实际联系人号码的核心表,关键字段:
_id:对应conversations中的recipient_ids值address:与联系人表匹配的真实电话号码
步骤2:重写联系人姓名获取逻辑
下面提供两种可行的实现方式,你可以根据需求选择:
方法一:先拿真实号码,再查姓名(更直观)
// 通过recipient_id获取真实电话号码 private String getRealNumberFromRecipientId(String recipientId) { String realNumber = null; Uri canonicalUri = Uri.parse("content://mms-sms/canonical-addresses"); Cursor cursor = getContentResolver().query( canonicalUri, new String[]{"address"}, "_id = ?", new String[]{recipientId}, null ); if (cursor != null && cursor.moveToFirst()) { realNumber = cursor.getString(cursor.getColumnIndex("address")); cursor.close(); } return realNumber; } // 通过电话号码获取联系人姓名,未找到则返回号码本身 private String getContactNameByNumber(String phoneNumber) { String contactName = phoneNumber; Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber)); Cursor cursor = getContentResolver().query( lookupUri, new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null ); if (cursor != null && cursor.moveToFirst()) { contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME)); cursor.close(); } return contactName; }
在你的循环中替换原有逻辑:
// 替换原来的String num = GetContactData(recipient_id); String realNumber = getRealNumberFromRecipientId(recipient_id); String contactName = getContactNameByNumber(realNumber); msg.setSenderName(contactName);
方法二:直接关联查询CONTACT_ID(更高效)
如果想一步到位,直接通过recipient_id关联到联系人姓名,可以用联合查询:
private String getContactNameByRecipientId(String recipientId) { String contactName = null; Uri canonicalUri = Uri.parse("content://mms-sms/canonical-addresses"); String[] projection = new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}; // 关联规范地址表和联系人号码表 String selection = "ca._id = ? AND ContactsContract.CommonDataKinds.Phone.NUMBER = ca.address"; String[] selectionArgs = new String[]{recipientId}; Cursor cursor = getContentResolver().query( canonicalUri, projection, selection, selectionArgs, null ); if (cursor != null && cursor.moveToFirst()) { contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME)); cursor.close(); } // 未找到联系人时返回真实号码 if (contactName == null) { contactName = getRealNumberFromRecipientId(recipientId); } return contactName; }
额外优化:修复代码中的小错误
你的代码里有一个明显的逻辑错误:
String address = cur.getString(cur.getColumnIndex("_id"));
这里你把会话ID(_id)赋值给了address变量,应该改为获取会话对应的真实号码字段:
String address = cur.getString(cur.getColumnIndex("address"));
注意事项
- 确保已经在Manifest中声明
READ_SMS和READ_CONTACTS权限,并且在Android 6.0及以上版本完成动态权限申请。 - 部分定制ROM的
mms-sms库可能存在字段差异,建议先通过Log.d打印cursor.getColumnNames()确认可用字段。
内容的提问来源于stack exchange,提问作者ALi Akbar
相关产品推荐
相关产品推荐

