android 获取通讯录全选反选_Xamarin.Forms读取并展示Android和iOS通讯录 TerminalMACS客户端...
本文同步更新地址:
https://dotnet9.com/11520.html
https://terminalmacs.com/861.html
閱讀導航:
一、功能說明
二、代碼實現
三、源碼獲取
四、參考資料
五、后面計劃
一、功能說明
完整思維導圖:https://github.com/dotnet9/TerminalMACS/blob/master/docs/TerminalMACS.xmind?
本文介紹圖中右側畫紅圈處的功能,即使用Xamarin.Forms獲取和展示Android和iOS的通訊錄信息,下面是最終效果,由于使用的是真實手機,所以聯系人姓名及電話號碼打碼顯示。
并簡單的進行了搜索功能處理,之所以說簡單,是因為通訊錄列表是全部讀取出來了,搜索是直接從此列表進行過濾的。
下圖來自:https://www.xamboy.com/2019/10/10/getting-phone-contacts-in-xamarin-forms/,本功能是參考此文所寫,所以直接引用文中的圖片。
二、代碼實現
1、共享庫工程創建聯系人實體類:Contacts.cs
namespace TerminalMACS.Clients.App.Models
{
? ///
? /// 通訊錄
? ///
? ?public class Contact
? ?{
? ? ? ///
? ? ? /// 獲取或者設置名稱
? ? ? ///
? ? ? ?public string Name { get; set; }
? ? ? ///
? ? ? /// 獲取或者設置 頭像
? ? ? ///
? ? ? ?public string Image { get; set; }
? ? ? ///
? ? ? /// 獲取或者設置 郵箱地址
? ? ? ///
? ? ? ?public string[] Emails { get; set; }
? ? ? ///
? ? ? /// 獲取或者設置 手機號碼
? ? ? ///
? ? ? ?public string[] PhoneNumbers { get; set; }
? ?}
}
2、共享庫創建通訊錄服務接口:IContactsService.cs
包括:
一個通訊錄獲取請求接口:RetrieveContactsAsync
一個讀取一條通訊結果通知事件:OnContactLoaded
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TerminalMACS.Clients.App.Models;
namespace TerminalMACS.Clients.App.Services
{
? ///
? /// 通訊錄事件參數
? ///
? ?public class ContactEventArgs:EventArgs
? ?{
? ? ? ?public Contact Contact { get; }
? ? ? ?public ContactEventArgs(Contact contact)
? ? ? ?{
? ? ? ? ? ?Contact = contact;
? ? ? ?}
? ?}
? ///
? /// 通訊錄服務接口,android和iOS終端具體的通訊錄獲取服務需要繼承此接口
? ///
? ?public interface IContactsService
? ?{
? ? ? ///
? ? ? /// 讀取一條數據通知
? ? ? ///
? ? ? ?event EventHandler OnContactLoaded;
? ? ? ///
? ? ? /// 是否正在加載
? ? ? ///
? ? ? ?bool IsLoading { get; }
? ? ? ///
? ? ? /// 嘗試獲取所有通訊錄
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?Task> RetrieveContactsAsync(CancellationToken? token = null);
? ?}
}
3、iOS工程中添加通訊錄服務,實現IContactsService接口:
using Contacts;
using Foundation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TerminalMACS.Clients.App.Models;
using TerminalMACS.Clients.App.Services;
namespace TerminalMACS.Clients.App.iOS.Services
{
? ///
? /// 通訊錄獲取服務
? ///
? ?public class ContactsService : NSObject, IContactsService
? ?{
? ? ? ?const string ThumbnailPrefix = "thumb";
? ? ? ?bool requestStop = false;
? ? ? ?public event EventHandler OnContactLoaded;
? ? ? ?bool _isLoading = false;
? ? ? ?public bool IsLoading => _isLoading;
? ? ? ///
? ? ? /// 異步請求權限
? ? ? ///
? ? ? ///
? ? ? ?public async Task<bool> RequestPermissionAsync()
? ? ? ?{
? ? ? ? ? ?var status = CNContactStore.GetAuthorizationStatus(CNEntityType.Contacts);
? ? ? ? ? ?Tuple<bool, NSError> authotization = new Tuple<bool, NSError>(status == CNAuthorizationStatus.Authorized, null);
? ? ? ? ? ?if (status == CNAuthorizationStatus.NotDetermined)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?using (var store = new CNContactStore())
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?authotization = await store.RequestAccessAsync(CNEntityType.Contacts);
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ? ? ?return authotization.Item1;
? ? ? ?}
? ? ? ///
? ? ? /// 異步請求通訊錄,此方法由界面真正調用
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?public async Task> RetrieveContactsAsync(CancellationToken? cancelToken = null)
? ? ? ?{
? ? ? ? ? ?requestStop = false;
? ? ? ? ? ?if (!cancelToken.HasValue)
? ? ? ? ? ? ? ?cancelToken = CancellationToken.None;
? ? ? ? ? // 我們創建了一個十進制的TaskCompletionSource
? ? ? ? ? ?var taskCompletionSource = new TaskCompletionSource>();
? ? ? ? ? // 在cancellationToken中注冊lambda
? ? ? ? ? ?cancelToken.Value.Register(() =>
? ? ? ? ? ?{
? ? ? ? ? ? ? // 我們收到一條取消消息,取消TaskCompletionSource.Task
? ? ? ? ? ? ? ?requestStop = true;
? ? ? ? ? ? ? ?taskCompletionSource.TrySetCanceled();
? ? ? ? ? ?});
? ? ? ? ? ?_isLoading = true;
? ? ? ? ? ?var task = LoadContactsAsync();
? ? ? ? ? // 等待兩個任務中的第一個任務完成
? ? ? ? ? ?var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);
? ? ? ? ? ?_isLoading = false;
? ? ? ? ? ?return await completedTask;
? ? ? ?}
? ? ? ///
? ? ? /// 異步加載通訊錄,具體的通訊錄讀取方法
? ? ? ///
? ? ? ///
? ? ? ?async Task> LoadContactsAsync()
? ? ? ?{
? ? ? ? ? ?IList contacts = new List();
? ? ? ? ? ?var hasPermission = await RequestPermissionAsync();
? ? ? ? ? ?if (hasPermission)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?NSError error = null;
? ? ? ? ? ? ? ?var keysToFetch = new[] { CNContactKey.PhoneNumbers, CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.EmailAddresses, CNContactKey.ImageDataAvailable, CNContactKey.ThumbnailImageData };
? ? ? ? ? ? ? ?var request = new CNContactFetchRequest(keysToFetch: keysToFetch);
? ? ? ? ? ? ? ?request.SortOrder = CNContactSortOrder.GivenName;
? ? ? ? ? ? ? ?using (var store = new CNContactStore())
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?var result = store.EnumerateContacts(request, out error, new CNContactStoreListContactsHandler((CNContact c, ref bool stop) =>
? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ?string path = null;
? ? ? ? ? ? ? ? ? ? ? ?if (c.ImageDataAvailable)
? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ?path = path = Path.Combine(Path.GetTempPath(), $"{ThumbnailPrefix}-{Guid.NewGuid()}");
? ? ? ? ? ? ? ? ? ? ? ? ? ?if (!File.Exists(path))
? ? ? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?var imageData = c.ThumbnailImageData;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?imageData?.Save(path, true);
? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?var contact = new Contact()
? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ?Name = string.IsNullOrEmpty(c.FamilyName) ? c.GivenName : $"{c.GivenName} {c.FamilyName}",
? ? ? ? ? ? ? ? ? ? ? ? ? ?Image = path,
? ? ? ? ? ? ? ? ? ? ? ? ? ?PhoneNumbers = c.PhoneNumbers?.Select(p => p?.Value?.StringValue).ToArray(),
? ? ? ? ? ? ? ? ? ? ? ? ? ?Emails = c.EmailAddresses?.Select(p => p?.Value?.ToString()).ToArray(),
? ? ? ? ? ? ? ? ? ? ? ?};
? ? ? ? ? ? ? ? ? ? ? ?if (!string.IsNullOrWhiteSpace(contact.Name))
? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ?OnContactLoaded?.Invoke(this, new ContactEventArgs(contact));
? ? ? ? ? ? ? ? ? ? ? ? ? ?contacts.Add(contact);
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?stop = requestStop;
? ? ? ? ? ? ? ? ? ?}));
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ? ? ?return contacts;
? ? ? ?}
? ?}
}
4、在iOS工程中的Info.plist文件添加通訊錄權限使用說明
5、在Android工程中添加讀取通訊錄權限配置:AndroidManifest.xml
android:name="android.permission.READ_CONTACTS"/>
完整權限配置如下
xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.terminalmacs.clients.app">
? android:minSdkVersion="21" android:targetSdkVersion="28" />
? android:label="TerminalMACS.Clients.App.Android">
? android:name="android.permission.ACCESS_NETWORK_STATE" />
? android:name="android.permission.READ_CONTACTS"/>
? android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
6、在Android工程中添加通訊錄服務,實現IContactServer接口:ContactsService.cs
using Acr.UserDialogs;
using Android;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Database;
using Android.Provider;
using Android.Runtime;
using Android.Support.V4.App;
using Plugin.CurrentActivity;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TerminalMACS.Clients.App.Models;
using TerminalMACS.Clients.App.Services;
namespace TerminalMACS.Clients.App.Droid.Services
{
? ///
? /// 通訊錄獲取服務
? ///
? ?public class ContactsService : IContactsService
? ?{
? ? ? ?const string ThumbnailPrefix = "thumb";
? ? ? ?bool stopLoad = false;
? ? ? ?static TaskCompletionSource<bool> contactPermissionTcs;
? ? ? ?public string TAG
? ? ? ?{
? ? ? ? ? ?get
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return "MainActivity";
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?bool _isLoading = false;
? ? ? ?public bool IsLoading => _isLoading;
? ? ? //權限請求狀態碼
? ? ? ?public const int RequestContacts = 1239;
? ? ? ///
? ? ? /// 獲取通訊錄需要的請求權限
? ? ? ///
? ? ? ?static string[] PermissionsContact = {
? ? ? ? ? ?Manifest.Permission.ReadContacts
? ? ? ?};
? ? ? ?public event EventHandler OnContactLoaded;
? ? ? ///
? ? ? /// 異步請求通訊錄權限
? ? ? ///
? ? ? ?async void RequestContactsPermissions()
? ? ? ?{
? ? ? ? ? //檢查是否可以彈出申請讀、寫通訊錄權限
? ? ? ? ? ?if (ActivityCompat.ShouldShowRequestPermissionRationale(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts)
? ? ? ? ? ? ? ?|| ActivityCompat.ShouldShowRequestPermissionRationale(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts))
? ? ? ? ? ?{
? ? ? ? ? ? ? // 如果未授予許可,請向用戶提供其他理由用戶將從使用權限的附加上下文中受益。
? ? ? ? ? ? ? // 例如,如果請求先前被拒絕。
? ? ? ? ? ? ? ?await UserDialogs.Instance.AlertAsync("通訊錄權限", "此操作需要“通訊錄”權限", "確定");
? ? ? ? ? ?}
? ? ? ? ? ?else
? ? ? ? ? ?{
? ? ? ? ? ? ? // 尚未授予通訊錄權限。直接請求這些權限。
? ? ? ? ? ? ? ?ActivityCompat.RequestPermissions(CrossCurrentActivity.Current.Activity, PermissionsContact, RequestContacts);
? ? ? ? ? ?}
? ? ? ?}
? ? ? ///
? ? ? /// 收到用戶響應請求權限操作后的結果
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?public static void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
? ? ? ?{
? ? ? ? ? ?if (requestCode == RequestContacts)
? ? ? ? ? ?{
? ? ? ? ? ? ? // 我們請求了多個通訊錄權限,因此需要檢查相關的所有權限
? ? ? ? ? ? ? ?if (PermissionUtil.VerifyPermissions(grantResults))
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? // 已授予所有必需的權限,顯示聯系人片段。
? ? ? ? ? ? ? ? ? ?contactPermissionTcs.TrySetResult(true);
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?else
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?contactPermissionTcs.TrySetResult(false);
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ?}
? ? ? ///
? ? ? /// 異步請求權限
? ? ? ///
? ? ? ///
? ? ? ?public async Task<bool> RequestPermissionAsync()
? ? ? ?{
? ? ? ? ? ?contactPermissionTcs = new TaskCompletionSource<bool>();
? ? ? ? ? // 驗證是否已授予所有必需的通訊錄權限。
? ? ? ? ? ?if (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts) != (int)Permission.Granted
? ? ? ? ? ? ? ?|| Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts) != (int)Permission.Granted)
? ? ? ? ? ?{
? ? ? ? ? ? ? // 尚未授予通訊錄權限。
? ? ? ? ? ? ? ?RequestContactsPermissions();
? ? ? ? ? ?}
? ? ? ? ? ?else
? ? ? ? ? ?{
? ? ? ? ? ? ? // 已授予通訊錄權限。
? ? ? ? ? ? ? ?contactPermissionTcs.TrySetResult(true);
? ? ? ? ? ?}
? ? ? ? ? ?return await contactPermissionTcs.Task;
? ? ? ?}
? ? ? ///
? ? ? /// 異步請求通訊錄,此方法由界面真正調用
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?public async Task> RetrieveContactsAsync(CancellationToken? cancelToken = null)
? ? ? ?{
? ? ? ? ? ?stopLoad = false;
? ? ? ? ? ?if (!cancelToken.HasValue)
? ? ? ? ? ? ? ?cancelToken = CancellationToken.None;
? ? ? ? ? // 我們創建了一個十進制的TaskCompletionSource
? ? ? ? ? ?var taskCompletionSource = new TaskCompletionSource>();
? ? ? ? ? // 在cancellationToken中注冊lambda
? ? ? ? ? ?cancelToken.Value.Register(() =>
? ? ? ? ? ?{
? ? ? ? ? ? ? // 我們收到一條取消消息,取消TaskCompletionSource.Task
? ? ? ? ? ? ? ?stopLoad = true;
? ? ? ? ? ? ? ?taskCompletionSource.TrySetCanceled();
? ? ? ? ? ?});
? ? ? ? ? ?_isLoading = true;
? ? ? ? ? ?var task = LoadContactsAsync();
? ? ? ? ? // 等待兩個任務中的第一個任務完成
? ? ? ? ? ?var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);
? ? ? ? ? ?_isLoading = false;
? ? ? ? ? ?return await completedTask;
? ? ? ?}
? ? ? ///
? ? ? /// 異步加載通訊錄,具體的通訊錄讀取方法
? ? ? ///
? ? ? ///
? ? ? ?async Task> LoadContactsAsync()
? ? ? ?{
? ? ? ? ? ?IList contacts = new List();
? ? ? ? ? ?var hasPermission = await RequestPermissionAsync();
? ? ? ? ? ?if (!hasPermission)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?return contacts;
? ? ? ? ? ?}
? ? ? ? ? ?var uri = ContactsContract.Contacts.ContentUri;
? ? ? ? ? ?var ctx = Application.Context;
? ? ? ? ? ?await Task.Run(() =>
? ? ? ? ? ?{
? ? ? ? ? ? ? // 暫時只請求通訊錄Id、DisplayName、PhotoThumbnailUri,可以擴展
? ? ? ? ? ? ? ?var cursor = ctx.ApplicationContext.ContentResolver.Query(uri, new string[]
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ?ContactsContract.Contacts.InterfaceConsts.Id,
? ? ? ? ? ? ? ? ? ? ? ?ContactsContract.Contacts.InterfaceConsts.DisplayName,
? ? ? ? ? ? ? ? ? ? ? ?ContactsContract.Contacts.InterfaceConsts.PhotoThumbnailUri
? ? ? ? ? ? ? ?}, null, null, $"{ContactsContract.Contacts.InterfaceConsts.DisplayName} ASC");
? ? ? ? ? ? ? ?if (cursor.Count > 0)
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?while (cursor.MoveToNext())
? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ?var contact = CreateContact(cursor, ctx);
? ? ? ? ? ? ? ? ? ? ? ?if (!string.IsNullOrWhiteSpace(contact.Name))
? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? // 讀取出一條,即通知界面展示
? ? ? ? ? ? ? ? ? ? ? ? ? ?OnContactLoaded?.Invoke(this, new ContactEventArgs(contact));
? ? ? ? ? ? ? ? ? ? ? ? ? ?contacts.Add(contact);
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?if (stopLoad)
? ? ? ? ? ? ? ? ? ? ? ? ? ?break;
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}
? ? ? ? ? ?});
? ? ? ? ? ?return contacts;
? ? ? ?}
? ? ? ///
? ? ? /// 讀取一條通訊錄數據
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?Contact CreateContact(ICursor cursor, Context ctx)
? ? ? ?{
? ? ? ? ? ?var contactId = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.Id);
? ? ? ? ? ?var numbers = GetNumbers(ctx, contactId);
? ? ? ? ? ?var emails = GetEmails(ctx, contactId);
? ? ? ? ? ?var uri = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.PhotoThumbnailUri);
? ? ? ? ? ?string path = null;
? ? ? ? ? ?if (!string.IsNullOrEmpty(uri))
? ? ? ? ? ?{
? ? ? ? ? ? ? ?try
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?using (var stream = Android.App.Application.Context.ContentResolver.OpenInputStream(Android.Net.Uri.Parse(uri)))
? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ?path = Path.Combine(Path.GetTempPath(), $"{ThumbnailPrefix}-{Guid.NewGuid()}");
? ? ? ? ? ? ? ? ? ? ? ?using (var fstream = new FileStream(path, FileMode.Create))
? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ?stream.CopyTo(fstream);
? ? ? ? ? ? ? ? ? ? ? ? ? ?fstream.Close();
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?stream.Close();
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?catch (Exception ex)
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?System.Diagnostics.Debug.WriteLine(ex);
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ? ? ?var contact = new Contact
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Name = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.DisplayName),
? ? ? ? ? ? ? ?Emails = emails,
? ? ? ? ? ? ? ?Image = path,
? ? ? ? ? ? ? ?PhoneNumbers = numbers,
? ? ? ? ? ?};
? ? ? ? ? ?return contact;
? ? ? ?}
? ? ? ///
? ? ? /// 讀取聯系人電話號碼
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?string[] GetNumbers(Context ctx, string contactId)
? ? ? ?{
? ? ? ? ? ?var key = ContactsContract.CommonDataKinds.Phone.Number;
? ? ? ? ? ?var cursor = ctx.ApplicationContext.ContentResolver.Query(
? ? ? ? ? ? ? ?ContactsContract.CommonDataKinds.Phone.ContentUri,
? ? ? ? ? ? ? ?null,
? ? ? ? ? ? ? ?ContactsContract.CommonDataKinds.Phone.InterfaceConsts.ContactId + " = ?",
? ? ? ? ? ? ? ?new[] { contactId },
? ? ? ? ? ? ? ?null
? ? ? ? ? ?);
? ? ? ? ? ?return ReadCursorItems(cursor, key)?.ToArray();
? ? ? ?}
? ? ? ///
? ? ? /// 讀取聯系人郵箱地址
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?string[] GetEmails(Context ctx, string contactId)
? ? ? ?{
? ? ? ? ? ?var key = ContactsContract.CommonDataKinds.Email.InterfaceConsts.Data;
? ? ? ? ? ?var cursor = ctx.ApplicationContext.ContentResolver.Query(
? ? ? ? ? ? ? ?ContactsContract.CommonDataKinds.Email.ContentUri,
? ? ? ? ? ? ? ?null,
? ? ? ? ? ? ? ?ContactsContract.CommonDataKinds.Email.InterfaceConsts.ContactId + " = ?",
? ? ? ? ? ? ? ?new[] { contactId },
? ? ? ? ? ? ? ?null);
? ? ? ? ? ?return ReadCursorItems(cursor, key)?.ToArray();
? ? ? ?}
? ? ? ?IEnumerable<string> ReadCursorItems(ICursor cursor, string key)
? ? ? ?{
? ? ? ? ? ?while (cursor.MoveToNext())
? ? ? ? ? ?{
? ? ? ? ? ? ? ?var value = GetString(cursor, key);
? ? ? ? ? ? ? ?yield return value;
? ? ? ? ? ?}
? ? ? ? ? ?cursor.Close();
? ? ? ?}
? ? ? ?string GetString(ICursor cursor, string key)
? ? ? ?{
? ? ? ? ? ?return cursor.GetString(cursor.GetColumnIndex(key));
? ? ? ?}
? ?}
}
需要添加?Plugin.CurrentActivity?和?Acr.UserDialogs?包。
7、Android工程添加權限處理判斷類
Permission.Util.cs
using Android.Content.PM;
namespace TerminalMACS.Clients.App.Droid
{
? ?public static class PermissionUtil
? ?{
? ? ? ?/**
? ?* 通過驗證給定數組中的每個條目的值是否為Permission.Granted,檢查是否已授予所有給定權限。
? ?*
? ?* See Activity#onRequestPermissionsResult (int, String[], int[])
? ?*/
? ? ? ?public static bool VerifyPermissions(Permission[] grantResults)
? ? ? ?{
? ? ? ? ? // 必須至少檢查一個結果.
? ? ? ? ? ?if (grantResults.Length < 1)
? ? ? ? ? ? ? ?return false;
? ? ? ? ? // 驗證是否已授予每個必需的權限,否則返回false.
? ? ? ? ? ?foreach (Permission result in grantResults)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?if (result != Permission.Granted)
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?return false;
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ? ? ?return true;
? ? ? ?}
? ?}
}
MainActivity.OnRequestPermissionResult是權限申請結果處理函數,在此函數中調用ContactsService.OnRequestPermissionsResult通知通訊錄服務權限處理結果。
MainActivity.cs
using Acr.UserDialogs;
using Android.App;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using TerminalMACS.Clients.App.Droid.Services;
using TerminalMACS.Clients.App.Services;
namespace TerminalMACS.Clients.App.Droid
{
? ?[Activity(Label = "TerminalMACS.Clients.App", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
? ?public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
? ?{
? ? ? ?IContactsService contactsService = new ContactsService();
? ? ? ?protected override void OnCreate(Bundle savedInstanceState)
? ? ? ?{
? ? ? ? ? ?TabLayoutResource = Resource.Layout.Tabbar;
? ? ? ? ? ?ToolbarResource = Resource.Layout.Toolbar;
? ? ? ? ? ?base.OnCreate(savedInstanceState);
? ? ? ? ? ?Xamarin.Essentials.Platform.Init(this, savedInstanceState);
? ? ? ? ? ?global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
? ? ? ? ? ?UserDialogs.Init(() => this);
? ? ? ? ? // 將通訊錄服務實例傳遞給共享庫,由共享庫使用讀取通訊錄接口
? ? ? ? ? ?LoadApplication(new App(contactsService));
? ? ? ?}
? ? ? ?public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
? ? ? ?{
? ? ? ? ? ?Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
? ? ? ? ? // 通訊錄服務處理權限請求結果
? ? ? ? ? ?ContactsService.OnRequestPermissionsResult(requestCode, permissions, grantResults);
? ? ? ? ? ?base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
? ? ? ?}
? ?}
}
8、創建通訊錄ViewModel,并使用通訊錄服務
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using TerminalMACS.Clients.App.Models;
using TerminalMACS.Clients.App.Services;
using Xamarin.Forms;
namespace TerminalMACS.Clients.App.ViewModels
{
? ///
? /// 通訊錄ViewModel
? ///
? ?public class ContactViewModel : BaseViewModel
? ?{
? ? ? ///
? ? ? /// 通訊錄服務接口
? ? ? ///
? ? ? ?IContactsService _contactService;
? ? ? ///
? ? ? /// 標題
? ? ? ///
? ? ? ?public new string Title => "通訊錄";
? ? ? ?private string _SearchText;
? ? ? ///
? ? ? /// 搜索關鍵字
? ? ? ///
? ? ? ?public string SearchText
? ? ? ?{
? ? ? ? ? ?get { return _SearchText; }
? ? ? ? ? ?set
? ? ? ? ? ?{
? ? ? ? ? ? ? ?SetProperty(ref _SearchText, value);
? ? ? ? ? ?}
? ? ? ?}
? ? ? ///
? ? ? /// 通訊錄搜索命令
? ? ? ///
? ? ? ?public ICommand RaiseSearchCommand { get; }
? ? ? ///
? ? ? /// 通訊錄列表
? ? ? ///
? ? ? ?public ObservableCollection Contacts { get; set; }
? ? ? ?private List _FilteredContacts;
? ? ? ///
? ? ? /// 通訊錄過濾列表
? ? ? ///
? ? ? ?public List FilteredContacts
? ? ? ?{
? ? ? ? ? ?get { return _FilteredContacts; }
? ? ? ? ? ?set
? ? ? ? ? ?{
? ? ? ? ? ? ? ?SetProperty(ref _FilteredContacts, value);
? ? ? ? ? ?}
? ? ? ?}
? ? ? ?public ContactViewModel(IContactsService contactService)
? ? ? ?{
? ? ? ? ? ?_contactService = contactService;
? ? ? ? ? ?Contacts = new ObservableCollection();
? ? ? ? ? ?Xamarin.Forms.BindingBase.EnableCollectionSynchronization(Contacts, null, ObservableCollectionCallback);
? ? ? ? ? ?_contactService.OnContactLoaded += OnContactLoaded;
? ? ? ? ? ?LoadContacts();
? ? ? ? ? ?RaiseSearchCommand = new Command(RaiseSearchHandle);
? ? ? ?}
? ? ? ///
? ? ? /// 過濾通訊錄
? ? ? ///
? ? ? ?void RaiseSearchHandle()
? ? ? ?{
? ? ? ? ? ?if (string.IsNullOrEmpty(SearchText))
? ? ? ? ? ?{
? ? ? ? ? ? ? ?FilteredContacts = Contacts.ToList();
? ? ? ? ? ? ? ?return;
? ? ? ? ? ?}
? ? ? ? ? ?Funcbool> checkContact = (s) =>
? ? ? ? ? ?{
? ? ? ? ? ? ? ?if (!string.IsNullOrWhiteSpace(s.Name) && s.Name.ToLower().Contains(SearchText.ToLower()))
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?return true;
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?else if (s.PhoneNumbers.Length > 0 && s.PhoneNumbers.ToList().Exists(cu => cu.ToString().Contains(SearchText)))
? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ?return true;
? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?return false;
? ? ? ? ? ?};
? ? ? ? ? ?FilteredContacts = Contacts.ToList().Where(checkContact).ToList();
? ? ? ?}
? ? ? ///
? ? ? /// BindingBase.EnableCollectionSynchronization 為集合啟用跨線程更新
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
? ? ? ?{
? ? ? ? ? // `lock` ensures that only one thread access the collection at a time
? ? ? ? ? ?lock (collection)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?accessMethod?.Invoke();
? ? ? ? ? ?}
? ? ? ?}
? ? ? ///
? ? ? /// 收到事件通知,讀取一條通訊錄信息
? ? ? ///
? ? ? ///
? ? ? ///
? ? ? ?private void OnContactLoaded(object sender, ContactEventArgs e)
? ? ? ?{
? ? ? ? ? ?Contacts.Add(e.Contact);
? ? ? ? ? ?RaiseSearchHandle();
? ? ? ?}
? ? ? ///
? ? ? /// 異步讀取終端通訊錄
? ? ? ///
? ? ? ///
? ? ? ?async Task LoadContacts()
? ? ? ?{
? ? ? ? ? ?try
? ? ? ? ? ?{
? ? ? ? ? ? ? ?await _contactService.RetrieveContactsAsync();
? ? ? ? ? ?}
? ? ? ? ? ?catch (TaskCanceledException)
? ? ? ? ? ?{
? ? ? ? ? ? ? ?Console.WriteLine("任務已經取消");
? ? ? ? ? ?}
? ? ? ?}
? ?}
}
9、添加通訊錄頁面展示通訊錄數據
<?xml version="1.0" encoding="utf-8" ?>
"http://xamarin.com/schemas/2014/forms"
? ? ? ? ? ? xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
? ? ? ? ? ? xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
? ? ? ? ? ? xmlns:d="http://xamarin.com/schemas/2014/forms/design"
? ? ? ? ? ? xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
? ? ? ? ? ? mc:Ignorable="d"
? ? ? ? ? ? Title="{Binding Title}"
? ? ? ? ? ? x:Class="TerminalMACS.Clients.App.Views.ContactPage"
? ? ? ? ? ? ios:Page.UseSafeArea="true">
? ? ? ? ? ?"filterText"
? ? ? ? ? ? ? ? ? ? ? ?HeightRequest="40"
? ? ? ? ? ? ? ? ? ? ? ?Text="{Binding SearchText}"
? ? ? ? ? ? ? ? ? ? ? SearchCommand="{Binding RaiseSearchCommand}"/>
? ? ? ? ? ?"{Binding FilteredContacts}"
? ? ? ? ? ? ? ? ? ? ? ?HasUnevenRows="True">
? ? ? ? ? ? ? ? ? ? ? ? ? ?"10"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Orientation="Horizontal">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"{Binding Image}"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?VerticalOptions="Center"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x:Name="image"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Aspect="AspectFit"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?HeightRequest="60"/>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"Center">
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"{Binding Name}"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FontAttributes="Bold"/>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"{Binding PhoneNumbers[0]}"/>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"{Binding Emails[0]}"/>
三、源碼獲取
1.完整源碼:https://github.com/dotnet9/TerminalMACS
2.Android客戶端可成功取得通訊錄數據,并可查詢;
已編譯的Android客戶端:https://terminalmacs.com/terminalmacs-clients-app-android
3.iOS讀取通訊錄功能代碼也已添加,但由于本人沒有iOS測試環境,所以未驗證,有條件的朋友可以測試下iOS的通訊錄讀取功能,如果代碼不起作用,可參考本文參考的文章檢查iOS代碼。
四、參考資料
Getting phone contacts in Xamarin Forms:https://www.xamboy.com/2019/10/10/getting-phone-contacts-in-xamarin-forms/
參考文章末尾有源代碼鏈接。
五、后面計劃
Xamarin.Forms客戶端基本信息獲取,比如IMEI、IMSI、本機號碼、Mac地址等。
總結
以上是生活随笔為你收集整理的android 获取通讯录全选反选_Xamarin.Forms读取并展示Android和iOS通讯录 TerminalMACS客户端...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言 assert 函数 - C语言零
- 下一篇: 图片的拖动布局