Содержание
При разработке приложения Blazor Hybrid, для работы с контактами в Android предназначен интерфейс IContacts
, содержащийся в пространстве имен Microsoft.Maui.ApplicationModel.Communication
.
Определение необходимых разрешений
Для работы с контактами в Android приложение должно иметь разрешение
android.permission.READ_CONTACTS
Создадим новое приложение Blazor Hybrid и добавим новое разрешение в файл Platform/Android/MainApplication.cs, используя атрибут сборки
using Android.App; using Android.Runtime; [assembly: UsesPermission(Android.Manifest.Permission.ReadContacts)] //добавляем необходимое разрешение namespace BlazorContacts { [Application] public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } }
Теперь мы можем воспользоваться функцией чтения контактов на устройстве Android.
Интерфейс IContacts и класс Contact
Интерфейс IContacts
достаточно простой и предоставляет нам всего два метода:
Метод | Описание |
Get |
Возвращает коллекцию всех контактов на устройстве. |
Pick |
Открывает пользовательский интерфейс операционной системы по умолчанию для выбора контакта с устройства. |
Реализация этого интерфейса доступна нам с использованием свойства Default
статического класса Contacts
. Когда мы запрашиваем отдельный контакт или весь список контактов с устройства, то мы получаем один или несколько объектов Contact, у которого определены следующие свойства:
Свойство | Описание |
Display |
Отображаемое имя контакта. |
Emails |
Коллекция адресов электронной почты контакта. |
Family |
Фамилия контакта. |
Given |
Имя контакта. |
Id |
Идентификатор контакта. |
Middle |
Отчество контакта. |
Name |
Префикс имени контакта. |
Name |
Суффикс имени контакта. |
Phones |
Коллекция номеров телефонов контакта. |
Вернемся к нашему приложению и посмотрим на работу с контактами в Android.
Получение всего списка контактов
Перепишем код компонента Home
следующим образом:
@page "/" @using Microsoft.Maui.ApplicationModel.Communication <h1>Список контактов</h1> @if (list == null) { <p><em>Загружаем...</em></p> } else { <table class="table"> <thead> <tr> <th>DisplayName</th> <th>GivenName</th> <th>MiddleName</th> <th>FamilyName</th> <th>Email</th> <th>Phone</th> </tr> </thead> <tbody> @foreach (var contact in list) { <tr> <td>@contact.DisplayName</td> <td>@contact.GivenName</td> <td>@contact.MiddleName</td> <td>@contact.FamilyName</td> <td> @if (contact.Emails.Count > 1) { <text>@contact.Emails[0] и ещё @contact.Emails.Count-1 </text> } else { if (contact.Emails.Count == 1) { <text>@contact.Emails[0]</text> } } </td> <td> @if (contact.Phones.Count > 1) { <text>@contact.Phones[0] и ещё @contact.Phones.Count-1 </text> } else { if (contact.Phones.Count == 1) { <text>@contact.Phones[0]</text> } } </td> </tr> } </tbody> </table> } <button @onclick="LoadAll">Получить список контактов</button> @code{ IContacts MyContacts = Contacts.Default; IEnumerable<Contact> list; public async Task<PermissionStatus> CheckAndRequestContactsPermission() { PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.ContactsRead>(); if (status == PermissionStatus.Granted) return status; status = await Permissions.RequestAsync<Permissions.ContactsRead>(); return status; } public async Task LoadAll() { if (await CheckAndRequestContactsPermission() == PermissionStatus.Granted) list = await MyContacts.GetAllAsync(); } }
Рассмотрим этот код более подробно. Первое, что мы сделали — это подключили необходимое нам пространство имен:
@using Microsoft.Maui.ApplicationModel.Communication
Далее, в коде C# компонента мы объявили два поля
IContacts MyContacts = Contacts.Default; IEnumerable<Contact> list;
здесь MyContacts
предоставляет нам реализацию интерфейса IContacts
по умолчанию, а list
служит для хранения списка контактов. Сам список контактов загружается в методе LoadAll()
:
public async Task LoadAll() { if (await CheckAndRequestContactsPermission() == PermissionStatus.Granted) list = await MyContacts.GetAllAsync(); }
и здесь мы сталкиваемся с вызовом еще одного метода CheckAndRequestContactsPermission()
в котором используется класс Permissions
:
public async Task<PermissionStatus> CheckAndRequestContactsPermission() { PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.ContactsRead>(); if (status == PermissionStatus.Granted) return status; status = await Permissions.RequestAsync<Permissions.ContactsRead>(); return status; }
Класс Permissions
используется для проверки и, при необходимости, запроса разрешений у пользователя на выполнение каких-либо операций. Дело в том, что в Android все разрешения делятся на обычные и опасные (dangerous
). Обычные разрешения, например, для доступа к заряду батареи, получаются непосредственно при установке приложения. Что касается опасных разрешений, то такие разрешения получаются при доступе к конфиденциальной информации и к информации, использование которой может повлиять на безопасность устройства. Опасные разрешения необходимо запрашивать у пользователя непосредственно при работе приложения. Это помогает снизить риск утечки конфиденциальной информации или взлома устройства. Согласитесь, что если условное приложение «Фонарик» запросит у вас доступ к чтению контактов или SMS, то такое поведение приложение вас насторожит?
Так вот в методе CheckAndRequestContactsPermission()
мы и производим ровно две операции:
1. Проверяем получено ли у пользователя разрешение. Для этого мы выполняем метод
PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.ContactsRead>();
PermissionStatus
— это перечисление, в котором определены следующие значения, которые мы можем использовать в Android:
Unknown
— разрешение находится в неизвестном состоянии.Denied
— пользователь отказался от запроса на разрешение.Disabled
— эта функция отключена на устройстве.Granted
— пользователь предоставил разрешение или автоматически предоставляется.Restricted
— в ограниченном состоянии.
В нашем случае, мы проверяем значение Granted
. Если разрешение получено, то мы возвращаем статус, иначе — пытаемся запросить разрешение у пользователя:
status = await Permissions.RequestAsync<Permissions.ContactsRead>();
и вне зависимости от результата возвращаем полученное значение. В методе LoadAll()
проверяется статус разрешения и загружается список контактов, если разрешение получено:
if (await CheckAndRequestContactsPermission() == PermissionStatus.Granted) list = await MyContacts.GetAllAsync();
И, наконец, в разметке компонента мы выводим обычную таблицу с контактами. В запущенном приложении это будет выглядеть следующим образом:
сразу после запуска приложения:
Запрос на разрешение после нажатия кнопки «Получить список контактов»
После успешного получения разрешения вы увидите через некоторое время список всех контактов с устройства:
Выбор контакта из адресной книги
Метод интерфейса IContacts
PickContactAsync()
позволяет выбрать для просмотра контакт из адресной книги. Чтобы продемонстрировать его работу, перепишем компонент Home
следующим образом:
@page "/" @using Microsoft.Maui.ApplicationModel.Communication <h1>Список контактов</h1> @if (Contact == null) { <p><em>Загружаем...</em></p> } else { <p>@Contact.DisplayName</p> <p>@Contact.GivenName</p> <p>@Contact.MiddleName</p> <p>@Contact.FamilyName</p> <p>Адреса электронной почты</p> <li> @foreach (var email in Contact.Emails) { <ul>@email</ul> } </li> <p>Телефоны</p> <li> @foreach (var phone in Contact.Phones) { <ul>@phone</ul> } </li> } <button @onclick="LoadAll">Получить контакт</button> @code{ IContacts MyContacts = Contacts.Default; Contact? Contact; public async Task<PermissionStatus> CheckAndRequestContactsPermission() { PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.ContactsRead>(); if (status == PermissionStatus.Granted) return status; status = await Permissions.RequestAsync<Permissions.ContactsRead>(); return status; } public async Task LoadAll() { if (await CheckAndRequestContactsPermission() == PermissionStatus.Granted) Contact = await MyContacts.PickContactAsync(); } }
Принципиально, этот код не сильно отличается от предыдущего — мы изменили разметку компонента, чтобы вывести информацию по конкретному контакту, а также немного изменили код компонента — завели новое поле для контакта:
Contact? Contact;
И заменили вызов метода IContacts
:
if (await CheckAndRequestContactsPermission() == PermissionStatus.Granted) Contact = await MyContacts.PickContactAsync();
Отличие заключается в работе приложения — после того как разрешение на просмотр контактов будет получена откроется или сразу приложение «Контакты» на устройстве Android или операционная система предложит выбрать одно из приложений для просмотра контактов (если у вас их установлено несколько). После выбора контакта информация о нем будет показана на экране:
Итого
Для чтения контактов в Android используется интерфейс IContacts
у которого определено два метода — для чтения всего списка контактов и выбора контакта из адресной книги. Запись контактов на момент написания этой статьи не поддерживалась. Перед получением доступа к контактам на устройстве Android необходимо явно получить разрешение на такое действие.