You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:系统对多个同账户/跨账户的原始联系人聚合后的ID
  • RawContactId:单个账户下的原始联系人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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:45:35