Xamarin.Android通过ContentProvider更新联系人手机号失败问题
Xamarin.Forms Android端更新联系人无法添加新手机号的解决方案
我正在开发一款Xamarin.Forms应用,支持联系人的保存与更新(存在则更新),目前iOS端功能正常。保存联系人功能运行良好,但Android端更新联系人时,删除原有手机号的操作正常,却无法重新添加新的手机号。尝试过用RawContactID替代ContactID、调用ContentProvider.NewUpdate替换NewInsert,代码无异常抛出且正常执行,但新手机号始终无法添加。
获取待更新联系人ID的原代码
public string GetPhoneContactID(Contact contact) { string id = "0"; var uri = ContactsContract.Contacts.ContentUri; var cursor = Android.App.Application.Context.ContentResolver.Query(uri, new string[] { ContactsContract.Contacts.InterfaceConsts.Id }, ContactsContract.Contacts.InterfaceConsts.DisplayName + "='" + GetDisplayName(contact.FirstName, contact.LastName) + "'", null, null); if (cursor.MoveToNext()) { id = cursor.GetString(cursor.GetColumnIndex(ContactsContract.Contacts.InterfaceConsts.Id)); } cursor.Close(); return id; }
更新联系人的原代码
public bool UpdateExistingContact(Contact contact) { var id = GetPhoneContactID(contact); string selection = ContactsContract.Data.InterfaceConsts.ContactId + "=? AND " + ContactsContract.Data.InterfaceConsts.Mimetype + "=?"; String[] selectionArgs = new string[] { id, ContactsContract.CommonDataKinds.Phone.ContentItemType }; // DELETE ALL PHONE NUMBERS FROM CONTACT Android.App.Application.Context.ContentResolver.Delete(ContactsContract.Data.ContentUri, selection, selectionArgs); List<ContentProviderOperation> ops = new List<ContentProviderOperation>(); var counterPhoneNumbers = 0; if (contact.PhoneNumbers != null) { // ADD NEW PHONENUMBERS TO CONTACT while (counterPhoneNumbers < contact.PhoneNumbers.Count) { var builder = ContentProviderOperation.NewInsert(ContactsContract.Data.ContentUri); builder.WithValue(ContactsContract.Data.InterfaceConsts.RawContactId, id); builder.WithValue(ContactsContract.Data.InterfaceConsts.Mimetype, ContactsContract.CommonDataKinds.Phone.ContentItemType); builder.WithValue(ContactsContract.CommonDataKinds.Phone.Number, contact.PhoneNumbers[counterPhoneNumbers].Value); builder.WithValue(ContactsContract.CommonDataKinds.Phone.InterfaceConsts.Data2, (int)PhoneDataKind.Work); ops.Add(builder.Build()); counterPhoneNumbers++; } } ContentProviderResult[] result; try { result = Android.App.Application.Context.ContentResolver.ApplyBatch(ContactsContract.Authority, ops); if (result.Length > 0) { ops.Clear(); return true; } } catch (System.Exception ex) { _logger.Error(ex); return false; } return false; }
问题根源与修复方案
核心问题:混淆ContactId与RawContactId
原代码中,GetPhoneContactID获取的是系统聚合后的ContactId,但插入手机号时错误地将其赋值给RawContactId字段。Android联系人系统中:
ContactId:系统对多个同账户/跨账户的原始联系人聚合后的IDRawContactId:单个账户下的原始联系人ID,所有联系人数据(手机号、邮箱等)必须关联到RawContactId才能正确存储
修复步骤
1. 修改ID查询逻辑,获取正确的RawContactId
替换原GetPhoneContactID方法,改为查询RawContacts表获取目标联系人的RawContactId:
public string GetRawContactID(Contact contact) { string rawId = "0"; var displayName = GetDisplayName(contact.FirstName, contact.LastName); // 查询RawContacts表,通过DisplayName获取RawContactId var uri = ContactsContract.RawContacts.ContentUri; var cursor = Android.App.Application.Context.ContentResolver.Query( uri, new string[] { ContactsContract.RawContacts.InterfaceConsts.Id }, ContactsContract.RawContacts.InterfaceConsts.DisplayName + "=?", new string[] { displayName }, null); if (cursor.MoveToNext()) { rawId = cursor.GetString(cursor.GetColumnIndex(ContactsContract.RawContacts.InterfaceConsts.Id)); } cursor.Close(); return rawId; }
2. 修正更新联系人的逻辑
在UpdateExistingContact中,使用正确的RawContactId进行删除和插入操作:
public bool UpdateExistingContact(Contact contact) { // 获取正确的RawContactId,若未找到直接返回失败 var rawContactId = GetRawContactID(contact); if(rawContactId == "0") return false; // 修正删除条件:用RawContactId精准匹配,避免误删同DisplayName的其他联系人数据 string selection = ContactsContract.Data.InterfaceConsts.RawContactId + "=? AND " + ContactsContract.Data.InterfaceConsts.Mimetype + "=?"; String[] selectionArgs = new string[] { rawContactId, ContactsContract.CommonDataKinds.Phone.ContentItemType }; Android.App.Application.Context.ContentResolver.Delete(ContactsContract.Data.ContentUri, selection, selectionArgs); List<ContentProviderOperation> ops = new List<ContentProviderOperation>(); // 遍历添加新手机号 if (contact.PhoneNumbers != null && contact.PhoneNumbers.Count > 0) { foreach (var phone in contact.PhoneNumbers) { var builder = ContentProviderOperation.NewInsert(ContactsContract.Data.ContentUri); // 关联正确的RawContactId builder.WithValue(ContactsContract.Data.InterfaceConsts.RawContactId, rawContactId); builder.WithValue(ContactsContract.Data.InterfaceConsts.Mimetype, ContactsContract.CommonDataKinds.Phone.ContentItemType); builder.WithValue(ContactsContract.CommonDataKinds.Phone.Number, phone.Value); builder.WithValue(ContactsContract.CommonDataKinds.Phone.InterfaceConsts.Data2, (int)PhoneDataKind.Work); ops.Add(builder.Build()); } } try { var result = Android.App.Application.Context.ContentResolver.ApplyBatch(ContactsContract.Authority, ops); return result != null && result.Length > 0; } catch (Exception ex) { _logger.Error(ex); return false; } }
额外注意事项
- 权限验证:确保已申请
READ_CONTACTS和WRITE_CONTACTS权限,Android 10+无需额外适配分区存储(联系人操作不受影响) - 精准匹配:仅通过
DisplayName查询可能匹配多个联系人,建议结合原有手机号、邮箱等字段缩小查询范围,避免错误更新
内容的提问来源于stack exchange,提问作者Lisa Maria
相关产品推荐
相关产品推荐

