MAUI: Save contact to device

176 views Asked by At

I am trying to save a phone number to the local device in MAUI by Conditional Compilation.

Below is my code:

#if ANDROID

using Android.App;
using Android.Content;
using Android.OS;
using Android.Provider;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using MyApp.Droid.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#elif IOS

using AddressBook;
using Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using UIKit;
using MyApp.iOS.Services;

#endif

namespace MyApp.Renderers
{
    public class SaveContact
    {
        public void SaveContactToPhoneBook(string Name, string Number, string Email)
        {
#if ANDROID
            var activity = Android.App.Application.Context as Activity;
            var intent = new Intent(Intent.ActionInsert).SetFlags(ActivityFlags.ClearTask);
            intent.SetType(ContactsContract.Contacts.ContentType);
            intent.PutExtra(ContactsContract.Intents.Insert.Name, Name);
            intent.PutExtra(ContactsContract.Intents.Insert.Phone, Number);
            intent.PutExtra(ContactsContract.Intents.Insert.Email, Email);
            activity.StartActivity(intent);
#elif IOS
            ABAddressBook ab = new ABAddressBook();
            ABPerson p = new ABPerson();
            p.FirstName = Name;
            ABMutableMultiValue<string> phones = new ABMutableStringMultiValue();
            phones.Add(Number, ABPersonPhoneLabel.Mobile);
            p.SetPhones(phones);
            ABMutableDictionaryMultiValue addresses = new ABMutableDictionaryMultiValue();
            NSMutableDictionary a = new NSMutableDictionary();
            addresses.Add(a, new NSString("Home"));
            p.SetAddresses(addresses);
            ab.Add(p);
            ab.Save();
#endif
        }
    }
}

Then from my contacts save page:

SaveContact saveContact = new SaveContact();
saveContact.SaveContactToPhoneBook("", phone, "");//passing name, phone and email

I am getting exception for this from both Android and iOS platforms.

Android Exception:

System.NullReferenceException: Object reference not set to an instance of an object. at MyProject.Renderers.SaveContact.SaveContactToPhoneBook(String Name, String Number, String Email) in E:\My Projects\MAUI\MyProject-maui\MyProject\Renderers\SaveContact.cs:line 43 [SurfaceComposerClient] XDR setRegion is not supported 0xb4000075d1bc0cf0, 1, 0

iOS Exception:

CoreFoundation.CFException: The operation couldn’t be completed. (ABAddressBookErrorDomain error 1.) at AddressBook.ABAddressBook.Add(ABRecord ) at MyProject.Renderers.SaveContact.SaveContactToPhoneBook(String Name, String Number, String Email) in /Users/MyCompany/Projects/MyProject-maui/MyProject/Renderers/SaveContact.cs:line 55

The codes I have used are from Xamarin Forms Dependency Service and I changed it to Conditional Compilation for MAUI integration.

1

There are 1 answers

0
Jessie Zhang -MSFT On BEST ANSWER

I tried to achieve this function for Android platform.

You can refer to the following code:

    public class SaveContact
    {
        public void SaveContactToPhoneBook(string displayName, string Number1, string Email)
        {
#if ANDROID

            List<ContentProviderOperation> ops = new List<ContentProviderOperation>();

            ContentProviderOperation.Builder builder =
    ContentProviderOperation.NewInsert(ContactsContract.RawContacts.ContentUri);
            builder.WithValue(ContactsContract.RawContacts.InterfaceConsts.AccountType, null);
            builder.WithValue(ContactsContract.RawContacts.InterfaceConsts.AccountName, null);
            ops.Add(builder.Build());

            //Name  
            builder = ContentProviderOperation.NewInsert(ContactsContract.Data.ContentUri);
            builder.WithValueBackReference(ContactsContract.Data.InterfaceConsts.RawContactId, 0);
            builder.WithValue(ContactsContract.Data.InterfaceConsts.Mimetype,
                              ContactsContract.CommonDataKinds.StructuredName.ContentItemType);
            builder.WithValue(ContactsContract.CommonDataKinds.StructuredName.DisplayName, displayName);
            //builder.WithValue(ContactsContract.CommonDataKinds.StructuredName.GivenName, firstName);  
            ops.Add(builder.Build());

            //Number1  
            builder = ContentProviderOperation.NewInsert(ContactsContract.Data.ContentUri);
            builder.WithValueBackReference(ContactsContract.Data.InterfaceConsts.RawContactId, 0);
            builder.WithValue(ContactsContract.Data.InterfaceConsts.Mimetype,
                              ContactsContract.CommonDataKinds.Phone.ContentItemType);
            builder.WithValue(ContactsContract.CommonDataKinds.Phone.Number, Number1);
            builder.WithValue(ContactsContract.CommonDataKinds.Phone.InterfaceConsts.Type,
                              ContactsContract.CommonDataKinds.Phone.InterfaceConsts.TypeCustom);
            builder.WithValue(ContactsContract.CommonDataKinds.Phone.InterfaceConsts.Data2, (int)PhoneDataKind.Mobile);

            ops.Add(builder.Build());



            //Add the new contact
            ContentProviderResult[] res;
            try
            {
                res =  Android.App.Application.Context.ContentResolver.ApplyBatch(ContactsContract.Authority, ops);
                ops.Clear();//Add this line  
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine( e.Message);
            }

#elif IOS

 
#endif
        }
    }

And we need to check and request the write contacts permission on the shared platform.

private async void SaveContactButton_Clicked(object sender, EventArgs e)
{
    await RequestWriteContactPermission();
}

// write contact
async Task RequestWriteContactPermission()
{

    var status = PermissionStatus.Unknown;

    {
        status = await Permissions.CheckStatusAsync<Permissions.ContactsWrite>();

        if (status == PermissionStatus.Granted)
        {
            SaveContact saveContact = new SaveContact();
            saveContact.SaveContactToPhoneBook("Test", "123999999", "");//passing name, phone and email
            return;
        }

        if (Permissions.ShouldShowRationale<Permissions.Phone>())
        {
            await Shell.Current.DisplayAlert("Needs permissions", "BECAUSE!!!", "OK");
        }

        status = await Permissions.RequestAsync<Permissions.ContactsWrite>();

    }


    if (status != PermissionStatus.Granted)
        await Shell.Current.DisplayAlert("Permission required",
            "Write Contact permission is required for test. " +
            "We just want to do a test.", "OK");

    else if (status == PermissionStatus.Granted)
    {
        SaveContact saveContact = new SaveContact();
        saveContact.SaveContactToPhoneBook("Test", "123999999", "");//passing name, phone and email
    }
}


public async Task<PermissionStatus> CheckAndRequestContactsWritePermission()
{
    PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.ContactsWrite>();

    if (status == PermissionStatus.Granted)
        return status;

    if (status == PermissionStatus.Denied && DeviceInfo.Platform == DevicePlatform.iOS)
    {
        // Prompt the user to turn on in settings
        // On iOS once a permission has been denied it may not be requested again from the application
        return status;
    }

    if (Permissions.ShouldShowRationale<Permissions.ContactsWrite>())
    {
        // Prompt the user with additional information as to why the permission is needed

        await Shell.Current.DisplayAlert("Need permission", "We need the Write Contact permission", "Ok");
    }

    status = await Permissions.RequestAsync<Permissions.ContactsWrite>();

    if (status == PermissionStatus.Granted)
    {

        SaveContact saveContact = new SaveContact();
        saveContact.SaveContactToPhoneBook("Test", "123999999", "");//passing name, phone and email

    }
    else
    {
        await Shell.Current.DisplayAlert("Permission required",
              "Write Contact permission is required for test . " +
              "We just want to test", "OK");

    }

    return status;
}

Note:

Remember to add the following permission on AndroidManifest.xml

   <uses-permission android:name="android.permission.WRITE_CONTACTS" />