android通讯录代码_Xamarin.Forms读取并展示Android和iOS通讯录 TerminalMACS客户端

本文同步更新地址:

  • https://dotnet9.com/11520.html

  • https://terminalmacs.com/861.html

阅读导航:

  • 一、功能说明

  • 二、代码实现

  • 三、源码获取

  • 四、参考资料

  • 五、后面计划

一、功能说明

1e50fe30e908d0d9bd12958a40ef3135.png

完整思维导图:https://github.com/dotnet9/TerminalMACS/blob/master/docs/TerminalMACS.xmind 

本文介绍图中右侧画红圈处的功能,即使用Xamarin.Forms获取和展示Android和iOS的通讯录信息,下面是最终效果,由于使用的是真实手机,所以联系人姓名及电话号码打码显示。

77fd953d40568fe67112422ee411a99c.png

并简单的进行了搜索功能处理,之所以说简单,是因为通讯录列表是全部读取出来了,搜索是直接从此列表进行过滤的。

下图来自:https://www.xamboy.com/2019/10/10/getting-phone-contacts-in-xamarin-forms/,本功能是参考此文所写,所以直接引用文中的图片。

1e9dabef28ca944f86c7b2eac804930f.gif

7187111680777dbe2a2cb7f4633f80cf.png

二、代码实现

1、共享库工程创建联系人实体类:Contacts.cs

  1. namespace TerminalMACS.Clients.App.Models

  2. {

  3.   ///

  4.   /// 通讯录

  5.   ///

  6.    public class Contact

  7.    {

  8.       ///

  9.       /// 获取或者设置名称

  10.       ///

  11.        public string Name { get; set; }

  12.       ///

  13.       /// 获取或者设置 头像

  14.       ///

  15.        public string Image { get; set; }

  16.       ///

  17.       /// 获取或者设置 邮箱地址

  18.       ///

  19.        public string[] Emails { get; set; }

  20.       ///

  21.       /// 获取或者设置 手机号码

  22.       ///

  23.        public string[] PhoneNumbers { get; set; }

  24.    }

  25. }

2、共享库创建通讯录服务接口:IContactsService.cs

包括:

  • 一个通讯录获取请求接口:RetrieveContactsAsync

  • 一个读取一条通讯结果通知事件:OnContactLoaded

  1. using System;

  2. using System.Collections.Generic;

  3. using System.Threading;

  4. using System.Threading.Tasks;

  5. using TerminalMACS.Clients.App.Models;

  6. namespace TerminalMACS.Clients.App.Services

  7. {

  8.   ///

  9.   /// 通讯录事件参数

  10.   ///

  11.    public class ContactEventArgs:EventArgs

  12.    {

  13.        public Contact Contact { get; }

  14.        public ContactEventArgs(Contact contact)

  15.        {

  16.            Contact = contact;

  17.        }

  18.    }

  19.   ///

  20.   /// 通讯录服务接口,android和iOS终端具体的通讯录获取服务需要继承此接口

  21.   ///

  22.    public interface IContactsService

  23.    {

  24.       ///

  25.       /// 读取一条数据通知

  26.       ///

  27.        event EventHandler OnContactLoaded;

  28.       ///

  29.       /// 是否正在加载

  30.       ///

  31.        bool IsLoading { get; }

  32.       ///

  33.       /// 尝试获取所有通讯录

  34.       ///

  35.       ///

  36.       ///

  37.        Task> RetrieveContactsAsync(CancellationToken? token = null);

  38.    }

  39. }

3、iOS工程中添加通讯录服务,实现IContactsService接口:

  1. using Contacts;

  2. using Foundation;

  3. using System;

  4. using System.Collections.Generic;

  5. using System.IO;

  6. using System.Linq;

  7. using System.Threading;

  8. using System.Threading.Tasks;

  9. using TerminalMACS.Clients.App.Models;

  10. using TerminalMACS.Clients.App.Services;

  11. namespace TerminalMACS.Clients.App.iOS.Services

  12. {

  13.   ///

  14.   /// 通讯录获取服务

  15.   ///

  16.    public class ContactsService : NSObject, IContactsService

  17.    {

  18.        const string ThumbnailPrefix = "thumb";

  19.        bool requestStop = false;

  20.        public event EventHandler OnContactLoaded;

  21.        bool _isLoading = false;

  22.        public bool IsLoading => _isLoading;

  23.       ///

  24.       /// 异步请求权限

  25.       ///

  26.       ///

  27.        public async Task<bool> RequestPermissionAsync()

  28.        {

  29.            var status = CNContactStore.GetAuthorizationStatus(CNEntityType.Contacts);

  30.            Tuple<bool, NSError> authotization = new Tuple<bool, NSError>(status == CNAuthorizationStatus.Authorized, null);

  31.            if (status == CNAuthorizationStatus.NotDetermined)

  32.            {

  33.                using (var store = new CNContactStore())

  34.                {

  35.                    authotization = await store.RequestAccessAsync(CNEntityType.Contacts);

  36.                }

  37.            }

  38.            return authotization.Item1;

  39.        }

  40.       ///

  41.       /// 异步请求通讯录,此方法由界面真正调用

  42.       ///

  43.       ///

  44.       ///

  45.        public async Task> RetrieveContactsAsync(CancellationToken? cancelToken = null)

  46.        {

  47.            requestStop = false;

  48.            if (!cancelToken.HasValue)

  49.                cancelToken = CancellationToken.None;

  50.           // 我们创建了一个十进制的TaskCompletionSource

  51.            var taskCompletionSource = new TaskCompletionSource>();

  52.           // 在cancellationToken中注册lambda

  53.            cancelToken.Value.Register(() =>

  54.            {

  55.               // 我们收到一条取消消息,取消TaskCompletionSource.Task

  56.                requestStop = true;

  57.                taskCompletionSource.TrySetCanceled();

  58.            });

  59.            _isLoading = true;

  60.            var task = LoadContactsAsync();

  61.           // 等待两个任务中的第一个任务完成

  62.            var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);

  63.            _isLoading = false;

  64.            return await completedTask;

  65.        }

  66.       ///

  67.       /// 异步加载通讯录,具体的通讯录读取方法

  68.       ///

  69.       ///

  70.        async Task> LoadContactsAsync()

  71.        {

  72.            IList contacts = new List();

  73.            var hasPermission = await RequestPermissionAsync();

  74.            if (hasPermission)

  75.            {

  76.                NSError error = null;

  77.                var keysToFetch = new[] { CNContactKey.PhoneNumbers, CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.EmailAddresses, CNContactKey.ImageDataAvailable, CNContactKey.ThumbnailImageData };

  78.                var request = new CNContactFetchRequest(keysToFetch: keysToFetch);

  79.                request.SortOrder = CNContactSortOrder.GivenName;

  80.                using (var store = new CNContactStore())

  81.                {

  82.                    var result = store.EnumerateContacts(request, out error, new CNContactStoreListContactsHandler((CNContact c, ref bool stop) =>

  83.                    {

  84.                        string path = null;

  85.                        if (c.ImageDataAvailable)

  86.                        {

  87.                            path = path = Path.Combine(Path.GetTempPath(), $"{ThumbnailPrefix}-{Guid.NewGuid()}");

  88.                            if (!File.Exists(path))

  89.                            {

  90.                                var imageData = c.ThumbnailImageData;

  91.                                imageData?.Save(path, true);

  92.                            }

  93.                        }

  94.                        var contact = new Contact()

  95.                        {

  96.                            Name = string.IsNullOrEmpty(c.FamilyName) ? c.GivenName : $"{c.GivenName} {c.FamilyName}",

  97.                            Image = path,

  98.                            PhoneNumbers = c.PhoneNumbers?.Select(p => p?.Value?.StringValue).ToArray(),

  99.                            Emails = c.EmailAddresses?.Select(p => p?.Value?.ToString()).ToArray(),

  100.                        };

  101.                        if (!string.IsNullOrWhiteSpace(contact.Name))

  102.                        {

  103.                            OnContactLoaded?.Invoke(this, new ContactEventArgs(contact));

  104.                            contacts.Add(contact);

  105.                        }

  106.                        stop = requestStop;

  107.                    }));

  108.                }

  109.            }

  110.            return contacts;

  111.        }

  112.    }

  113. }

4、在iOS工程中的Info.plist文件添加通讯录权限使用说明

80691718eb07e7834cd6555bcf4dbf2b.png

5、在Android工程中添加读取通讯录权限配置:AndroidManifest.xml

  1. android:name="android.permission.READ_CONTACTS"/>

完整权限配置如下

  1. xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.terminalmacs.clients.app">

  2.   android:minSdkVersion="21" android:targetSdkVersion="28" />

  3.   android:label="TerminalMACS.Clients.App.Android">

  4.   android:name="android.permission.ACCESS_NETWORK_STATE" />

  5.   android:name="android.permission.READ_CONTACTS"/>

  6.   android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

6、在Android工程中添加通讯录服务,实现IContactServer接口:ContactsService.cs

  1. using Acr.UserDialogs;

  2. using Android;

  3. using Android.App;

  4. using Android.Content;

  5. using Android.Content.PM;

  6. using Android.Database;

  7. using Android.Provider;

  8. using Android.Runtime;

  9. using Android.Support.V4.App;

  10. using Plugin.CurrentActivity;

  11. using System;

  12. using System.Collections.Generic;

  13. using System.IO;

  14. using System.Linq;

  15. using System.Threading;

  16. using System.Threading.Tasks;

  17. using TerminalMACS.Clients.App.Models;

  18. using TerminalMACS.Clients.App.Services;

  19. namespace TerminalMACS.Clients.App.Droid.Services

  20. {

  21.   ///

  22.   /// 通讯录获取服务

  23.   ///

  24.    public class ContactsService : IContactsService

  25.    {

  26.        const string ThumbnailPrefix = "thumb";

  27.        bool stopLoad = false;

  28.        static TaskCompletionSource<bool> contactPermissionTcs;

  29.        public string TAG

  30.        {

  31.            get

  32.            {

  33.                return "MainActivity";

  34.            }

  35.        }

  36.        bool _isLoading = false;

  37.        public bool IsLoading => _isLoading;

  38.       //权限请求状态码

  39.        public const int RequestContacts = 1239;

  40.       ///

  41.       /// 获取通讯录需要的请求权限

  42.       ///

  43.        static string[] PermissionsContact = {

  44.            Manifest.Permission.ReadContacts

  45.        };

  46.        public event EventHandler OnContactLoaded;

  47.       ///

  48.       /// 异步请求通讯录权限

  49.       ///

  50.        async void RequestContactsPermissions()

  51.        {

  52.           //检查是否可以弹出申请读、写通讯录权限

  53.            if (ActivityCompat.ShouldShowRequestPermissionRationale(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts)

  54.                || ActivityCompat.ShouldShowRequestPermissionRationale(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts))

  55.            {

  56.               // 如果未授予许可,请向用户提供其他理由用户将从使用权限的附加上下文中受益。

  57.               // 例如,如果请求先前被拒绝。

  58.                await UserDialogs.Instance.AlertAsync("通讯录权限", "此操作需要“通讯录”权限", "确定");

  59.            }

  60.            else

  61.            {

  62.               // 尚未授予通讯录权限。直接请求这些权限。

  63.                ActivityCompat.RequestPermissions(CrossCurrentActivity.Current.Activity, PermissionsContact, RequestContacts);

  64.            }

  65.        }

  66.       ///

  67.       /// 收到用户响应请求权限操作后的结果

  68.       ///

  69.       ///

  70.       ///

  71.       ///

  72.        public static void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)

  73.        {

  74.            if (requestCode == RequestContacts)

  75.            {

  76.               // 我们请求了多个通讯录权限,因此需要检查相关的所有权限

  77.                if (PermissionUtil.VerifyPermissions(grantResults))

  78.                {

  79.                   // 已授予所有必需的权限,显示联系人片段。

  80.                    contactPermissionTcs.TrySetResult(true);

  81.                }

  82.                else

  83.                {

  84.                    contactPermissionTcs.TrySetResult(false);

  85.                }

  86.            }

  87.        }

  88.       ///

  89.       /// 异步请求权限

  90.       ///

  91.       ///

  92.        public async Task<bool> RequestPermissionAsync()

  93.        {

  94.            contactPermissionTcs = new TaskCompletionSource<bool>();

  95.           // 验证是否已授予所有必需的通讯录权限。

  96.            if (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts) != (int)Permission.Granted

  97.                || Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts) != (int)Permission.Granted)

  98.            {

  99.               // 尚未授予通讯录权限。

  100.                RequestContactsPermissions();

  101.            }

  102.            else

  103.            {

  104.               // 已授予通讯录权限。

  105.                contactPermissionTcs.TrySetResult(true);

  106.            }

  107.            return await contactPermissionTcs.Task;

  108.        }

  109.       ///

  110.       /// 异步请求通讯录,此方法由界面真正调用

  111.       ///

  112.       ///

  113.       ///

  114.        public async Task> RetrieveContactsAsync(CancellationToken? cancelToken = null)

  115.        {

  116.            stopLoad = false;

  117.            if (!cancelToken.HasValue)

  118.                cancelToken = CancellationToken.None;

  119.           // 我们创建了一个十进制的TaskCompletionSource

  120.            var taskCompletionSource = new TaskCompletionSource>();

  121.           // 在cancellationToken中注册lambda

  122.            cancelToken.Value.Register(() =>

  123.            {

  124.               // 我们收到一条取消消息,取消TaskCompletionSource.Task

  125.                stopLoad = true;

  126.                taskCompletionSource.TrySetCanceled();

  127.            });

  128.            _isLoading = true;

  129.            var task = LoadContactsAsync();

  130.           // 等待两个任务中的第一个任务完成

  131.            var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);

  132.            _isLoading = false;

  133.            return await completedTask;

  134.        }

  135.       ///

  136.       /// 异步加载通讯录,具体的通讯录读取方法

  137.       ///

  138.       ///

  139.        async Task> LoadContactsAsync()

  140.        {

  141.            IList contacts = new List();

  142.            var hasPermission = await RequestPermissionAsync();

  143.            if (!hasPermission)

  144.            {

  145.                return contacts;

  146.            }

  147.            var uri = ContactsContract.Contacts.ContentUri;

  148.            var ctx = Application.Context;

  149.            await Task.Run(() =>

  150.            {

  151.               // 暂时只请求通讯录Id、DisplayName、PhotoThumbnailUri,可以扩展

  152.                var cursor = ctx.ApplicationContext.ContentResolver.Query(uri, new string[]

  153.                {

  154.                        ContactsContract.Contacts.InterfaceConsts.Id,

  155.                        ContactsContract.Contacts.InterfaceConsts.DisplayName,

  156.                        ContactsContract.Contacts.InterfaceConsts.PhotoThumbnailUri

  157.                }, null, null, $"{ContactsContract.Contacts.InterfaceConsts.DisplayName} ASC");

  158.                if (cursor.Count > 0)

  159.                {

  160.                    while (cursor.MoveToNext())

  161.                    {

  162.                        var contact = CreateContact(cursor, ctx);

  163.                        if (!string.IsNullOrWhiteSpace(contact.Name))

  164.                        {

  165.                           // 读取出一条,即通知界面展示

  166.                            OnContactLoaded?.Invoke(this, new ContactEventArgs(contact));

  167.                            contacts.Add(contact);

  168.                        }

  169.                        if (stopLoad)

  170.                            break;

  171.                    }

  172.                }

  173.            });

  174.            return contacts;

  175.        }

  176.       ///

  177.       /// 读取一条通讯录数据

  178.       ///

  179.       ///

  180.       ///

  181.       ///

  182.        Contact CreateContact(ICursor cursor, Context ctx)

  183.        {

  184.            var contactId = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.Id);

  185.            var numbers = GetNumbers(ctx, contactId);

  186.            var emails = GetEmails(ctx, contactId);

  187.            var uri = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.PhotoThumbnailUri);

  188.            string path = null;

  189.            if (!string.IsNullOrEmpty(uri))

  190.            {

  191.                try

  192.                {

  193.                    using (var stream = Android.App.Application.Context.ContentResolver.OpenInputStream(Android.Net.Uri.Parse(uri)))

  194.                    {

  195.                        path = Path.Combine(Path.GetTempPath(), $"{ThumbnailPrefix}-{Guid.NewGuid()}");

  196.                        using (var fstream = new FileStream(path, FileMode.Create))

  197.                        {

  198.                            stream.CopyTo(fstream);

  199.                            fstream.Close();

  200.                        }

  201.                        stream.Close();

  202.                    }

  203.                }

  204.                catch (Exception ex)

  205.                {

  206.                    System.Diagnostics.Debug.WriteLine(ex);

  207.                }

  208.            }

  209.            var contact = new Contact

  210.            {

  211.                Name = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.DisplayName),

  212.                Emails = emails,

  213.                Image = path,

  214.                PhoneNumbers = numbers,

  215.            };

  216.            return contact;

  217.        }

  218.       ///

  219.       /// 读取联系人电话号码

  220.       ///

  221.       ///

  222.       ///

  223.       ///

  224.        string[] GetNumbers(Context ctx, string contactId)

  225.        {

  226.            var key = ContactsContract.CommonDataKinds.Phone.Number;

  227.            var cursor = ctx.ApplicationContext.ContentResolver.Query(

  228.                ContactsContract.CommonDataKinds.Phone.ContentUri,

  229.                null,

  230.                ContactsContract.CommonDataKinds.Phone.InterfaceConsts.ContactId + " = ?",

  231.                new[] { contactId },

  232.                null

  233.            );

  234.            return ReadCursorItems(cursor, key)?.ToArray();

  235.        }

  236.       ///

  237.       /// 读取联系人邮箱地址

  238.       ///

  239.       ///

  240.       ///

  241.       ///

  242.        string[] GetEmails(Context ctx, string contactId)

  243.        {

  244.            var key = ContactsContract.CommonDataKinds.Email.InterfaceConsts.Data;

  245.            var cursor = ctx.ApplicationContext.ContentResolver.Query(

  246.                ContactsContract.CommonDataKinds.Email.ContentUri,

  247.                null,

  248.                ContactsContract.CommonDataKinds.Email.InterfaceConsts.ContactId + " = ?",

  249.                new[] { contactId },

  250.                null);

  251.            return ReadCursorItems(cursor, key)?.ToArray();

  252.        }

  253.        IEnumerable<string> ReadCursorItems(ICursor cursor, string key)

  254.        {

  255.            while (cursor.MoveToNext())

  256.            {

  257.                var value = GetString(cursor, key);

  258.                yield return value;

  259.            }

  260.            cursor.Close();

  261.        }

  262.        string GetString(ICursor cursor, string key)

  263.        {

  264.            return cursor.GetString(cursor.GetColumnIndex(key));

  265.        }

  266.    }

  267. }

需要添加 Plugin.CurrentActivity 和 Acr.UserDialogs 包。

7、Android工程添加权限处理判断类

Permission.Util.cs

  1. using Android.Content.PM;

  2. namespace TerminalMACS.Clients.App.Droid

  3. {

  4.    public static class PermissionUtil

  5.    {

  6.        /**

  7.    * 通过验证给定数组中的每个条目的值是否为Permission.Granted,检查是否已授予所有给定权限。

  8.    *

  9.    * See Activity#onRequestPermissionsResult (int, String[], int[])

  10.    */

  11.        public static bool VerifyPermissions(Permission[] grantResults)

  12.        {

  13.           // 必须至少检查一个结果.

  14.            if (grantResults.Length < 1)

  15.                return false;

  16.           // 验证是否已授予每个必需的权限,否则返回false.

  17.            foreach (Permission result in grantResults)

  18.            {

  19.                if (result != Permission.Granted)

  20.                {

  21.                    return false;

  22.                }

  23.            }

  24.            return true;

  25.        }

  26.    }

  27. }

MainActivity.OnRequestPermissionResult是权限申请结果处理函数,在此函数中调用ContactsService.OnRequestPermissionsResult通知通讯录服务权限处理结果。

MainActivity.cs

  1. using Acr.UserDialogs;

  2. using Android.App;

  3. using Android.Content.PM;

  4. using Android.OS;

  5. using Android.Runtime;

  6. using TerminalMACS.Clients.App.Droid.Services;

  7. using TerminalMACS.Clients.App.Services;

  8. namespace TerminalMACS.Clients.App.Droid

  9. {

  10.    [Activity(Label = "TerminalMACS.Clients.App", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]

  11.    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity

  12.    {

  13.        IContactsService contactsService = new ContactsService();

  14.        protected override void OnCreate(Bundle savedInstanceState)

  15.        {

  16.            TabLayoutResource = Resource.Layout.Tabbar;

  17.            ToolbarResource = Resource.Layout.Toolbar;

  18.            base.OnCreate(savedInstanceState);

  19.            Xamarin.Essentials.Platform.Init(this, savedInstanceState);

  20.            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

  21.            UserDialogs.Init(() => this);

  22.           // 将通讯录服务实例传递给共享库,由共享库使用读取通讯录接口

  23.            LoadApplication(new App(contactsService));

  24.        }

  25.        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)

  26.        {

  27.            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

  28.           // 通讯录服务处理权限请求结果

  29.            ContactsService.OnRequestPermissionsResult(requestCode, permissions, grantResults);

  30.            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);

  31.        }

  32.    }

  33. }

8、创建通讯录ViewModel,并使用通讯录服务

  1. using System;

  2. using System.Collections;

  3. using System.Collections.Generic;

  4. using System.Collections.ObjectModel;

  5. using System.Linq;

  6. using System.Threading.Tasks;

  7. using System.Windows.Input;

  8. using TerminalMACS.Clients.App.Models;

  9. using TerminalMACS.Clients.App.Services;

  10. using Xamarin.Forms;

  11. namespace TerminalMACS.Clients.App.ViewModels

  12. {

  13.   ///

  14.   /// 通讯录ViewModel

  15.   ///

  16.    public class ContactViewModel : BaseViewModel

  17.    {

  18.       ///

  19.       /// 通讯录服务接口

  20.       ///

  21.        IContactsService _contactService;

  22.       ///

  23.       /// 标题

  24.       ///

  25.        public new string Title => "通讯录";

  26.        private string _SearchText;

  27.       ///

  28.       /// 搜索关键字

  29.       ///

  30.        public string SearchText

  31.        {

  32.            get { return _SearchText; }

  33.            set

  34.            {

  35.                SetProperty(ref _SearchText, value);

  36.            }

  37.        }

  38.       ///

  39.       /// 通讯录搜索命令

  40.       ///

  41.        public ICommand RaiseSearchCommand { get; }

  42.       ///

  43.       /// 通讯录列表

  44.       ///

  45.        public ObservableCollection Contacts { get; set; }

  46.        private List _FilteredContacts;

  47.       ///

  48.       /// 通讯录过滤列表

  49.       ///

  50.        public List FilteredContacts

  51.        {

  52.            get { return _FilteredContacts; }

  53.            set

  54.            {

  55.                SetProperty(ref _FilteredContacts, value);

  56.            }

  57.        }

  58.        public ContactViewModel(IContactsService contactService)

  59.        {

  60.            _contactService = contactService;

  61.            Contacts = new ObservableCollection();

  62.            Xamarin.Forms.BindingBase.EnableCollectionSynchronization(Contacts, null, ObservableCollectionCallback);

  63.            _contactService.OnContactLoaded += OnContactLoaded;

  64.            LoadContacts();

  65.            RaiseSearchCommand = new Command(RaiseSearchHandle);

  66.        }

  67.       ///

  68.       /// 过滤通讯录

  69.       ///

  70.        void RaiseSearchHandle()

  71.        {

  72.            if (string.IsNullOrEmpty(SearchText))

  73.            {

  74.                FilteredContacts = Contacts.ToList();

  75.                return;

  76.            }

  77.            Funcbool> checkContact = (s) =>

  78.            {

  79.                if (!string.IsNullOrWhiteSpace(s.Name) && s.Name.ToLower().Contains(SearchText.ToLower()))

  80.                {

  81.                    return true;

  82.                }

  83.                else if (s.PhoneNumbers.Length > 0 && s.PhoneNumbers.ToList().Exists(cu => cu.ToString().Contains(SearchText)))

  84.                {

  85.                    return true;

  86.                }

  87.                return false;

  88.            };

  89.            FilteredContacts = Contacts.ToList().Where(checkContact).ToList();

  90.        }

  91.       ///

  92.       /// BindingBase.EnableCollectionSynchronization 为集合启用跨线程更新

  93.       ///

  94.       ///

  95.       ///

  96.       ///

  97.       ///

  98.        void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)

  99.        {

  100.           // `lock` ensures that only one thread access the collection at a time

  101.            lock (collection)

  102.            {

  103.                accessMethod?.Invoke();

  104.            }

  105.        }

  106.       ///

  107.       /// 收到事件通知,读取一条通讯录信息

  108.       ///

  109.       ///

  110.       ///

  111.        private void OnContactLoaded(object sender, ContactEventArgs e)

  112.        {

  113.            Contacts.Add(e.Contact);

  114.            RaiseSearchHandle();

  115.        }

  116.       ///

  117.       /// 异步读取终端通讯录

  118.       ///

  119.       ///

  120.        async Task LoadContacts()

  121.        {

  122.            try

  123.            {

  124.                await _contactService.RetrieveContactsAsync();

  125.            }

  126.            catch (TaskCanceledException)

  127.            {

  128.                Console.WriteLine("任务已经取消");

  129.            }

  130.        }

  131.    }

  132. }

9、添加通讯录页面展示通讯录数据

  1. <?xml version="1.0" encoding="utf-8" ?>

  2. "http://xamarin.com/schemas/2014/forms"

  3.             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

  4.             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

  5.             xmlns:d="http://xamarin.com/schemas/2014/forms/design"

  6.             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"

  7.             mc:Ignorable="d"

  8.             Title="{Binding Title}"

  9.             x:Class="TerminalMACS.Clients.App.Views.ContactPage"

  10.             ios:Page.UseSafeArea="true">

  11.            "filterText"

  12.                        HeightRequest="40"

  13.                        Text="{Binding SearchText}"

  14.                       SearchCommand="{Binding RaiseSearchCommand}"/>

  15.            "{Binding FilteredContacts}"

  16.                        HasUnevenRows="True">

  17.                            "10"

  18.                                         Orientation="Horizontal">

  19.                                "{Binding Image}"

  20.                                        VerticalOptions="Center"

  21.                                        x:Name="image"

  22.                                        Aspect="AspectFit"

  23.                                        HeightRequest="60"/>

  24.                                "Center">

  25.                                    "{Binding Name}"

  26.                                       FontAttributes="Bold"/>

  27.                                    "{Binding PhoneNumbers[0]}"/>

  28.                                    "{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地址等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值