Содержание
При разработке приложения 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 необходимо явно получить разрешение на такое действие.


