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.
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" />