Содержание
Для выполнения различных операций в Android наше приложение .NET MAUI должно взаимодействовать с другими приложениями. Например, для выбора контакта и набора телефонного номера наше приложение должно вначале открыть приложение «Контакты», чтобы пользователь выбрал необходимый контакт, а затем — открыть приложение «Телефон» с набранным номером контакта. В этой части мы рассмотрим как мы можем взаимодействовать с другими приложениями в Android на примере приложения .NET MAUI «Выбор контакта и набор телефонного номера».
Выбор контакта в Android. Интерфейс IContacts
Интерфейс IContacts содержит методы для работы с контактами:
| Метод | Описание |
public Task<IEnumerable<Contact>> GetAllAsync(CancellationToken cancellationToken = default); |
Возвращает список всех контактов на устройстве |
public Task<Contact?> PickContactAsync(); |
Открывает приложение Android по умолчанию для выбора контакта с устройства |
Реализация интерфейса по умолчанию содержится в свойстве Default класса Contacts. Воспользуемся этими методами в приложении .NET MAUI. Создадим новый проект с названием MauiPhone.
Определение необходимых разрешений
Для того, чтобы наше приложение могло считывать данные о контактах, необходимо запросить разрешение android.permission.READ_CONTACTS одним из известных нам способов. Например, добавим в MauiApplication.cs атрибут сборки:
using Android.App;
using Android.Runtime;
[assembly: UsesPermission(Android.Manifest.Permission.ReadContacts)]
namespace MauiPhone;
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
Вывод списка контактов
Создадим в проекте новую папку ViewModels и добавим в неё класс ContactsViewModel со следующим содержимым:
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace MauiPhone.ViewModels
{
public class ContactsViewModel
{
public ObservableCollection<Contact> ContactList { get; set; } = [];
public ICommand ReadContacts { get; set; }
public ContactsViewModel()
{
ReadContacts = new Command(async () =>
{
if (await CheckPermissionStatus() == PermissionStatus.Granted)
{
foreach (var contact in await Microsoft.Maui.ApplicationModel.Communication.Contacts.Default.GetAllAsync())
{
ContactList.Add(contact);
}
}
});
}
public async Task<PermissionStatus> CheckPermissionStatus()
{
var currentStatus = await Permissions.CheckStatusAsync<Permissions.ContactsRead>();
if (currentStatus != PermissionStatus.Granted)
{
currentStatus = await Permissions.RequestAsync<Permissions.ContactsRead>();
}
return currentStatus;
}
}
}
Здесь мы определили свойство ContactList, которое будет содержать список всех контактов
public ObservableCollection<Contact> ContactList { get; set; } = [];
а также команду ReadContacts для получения списка контактов:
public ICommand ReadContacts { get; set; }
...
ReadContacts = new Command(async () =>
{
if (await CheckPermissionStatus() == PermissionStatus.Granted)
{
foreach (var contact in await Microsoft.Maui.ApplicationModel.Communication.Contacts.Default.GetAllAsync())
{
ContactList.Add(contact);
}
}
});
Здесь мы вначале проверяем статус разрешения на чтение контактов, используя метод CheckPermissionStatus():
public async Task<PermissionStatus> CheckPermissionStatus()
{
var currentStatus = await Permissions.CheckStatusAsync<Permissions.ContactsRead>();
if (currentStatus != PermissionStatus.Granted)
{
currentStatus = await Permissions.RequestAsync<Permissions.ContactsRead>();
}
return currentStatus;
}
и затем, если разрешение было получено, считываем список всех контактов на устройстве. Используем нашу модель представления на главной странице приложения. Вначале изменим код MainPage.xaml.cs, передав в качестве контекста модель представления:
using MauiPhone.ViewModels;
namespace MauiPhone
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new ContactsViewModel();
}
}
}
Теперь изменим XAML-код страницы MainPage.xaml следующим образом:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiPhone.ViewModels"
xmlns:model="clr-namespace:Microsoft.Maui.ApplicationModel.Communication;assembly=Microsoft.Maui.Essentials"
x:Class="MauiPhone.MainPage"
x:DataType="local:ContactsViewModel">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Button Text="Посмотреть контакты" Command="{Binding ReadContacts}" />
<Picker ItemsSource="{Binding ContactList, Mode=TwoWay}"
ItemDisplayBinding="{Binding DisplayName}" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Клик по кнопке запускает команду на получение всего списка контактов, которые после загрузки отобразятся в выпадающем списке Picker. При этом, в списке мы будем отображать свойство DisplayName контакта. Запустим приложение и посмотрим на результат:
При этом при первой попытке загрузки списка контактов, приложение попросит разрешение на доступ к контактам. С первой частью работы с контактами мы справились — научились загружать и показывать список контактов. Теперь необходимо научиться выбирать контакт и показывать по нему информацию
Выбор контакта из списка и отображение свойств контакта
Каждый элемент списка ContactList нашей модели представления содержит объект типа Contact. Класс Contact предоставляет нам следующую информацию по контакту:
| Свойство | Тип | Описание |
Id |
string |
Идентификатор контакта |
GivenName |
string |
Имя контакта |
MiddleName |
string |
Отчество контакта |
FamilyName |
string |
Фамилия контакта |
DisplayName |
string |
Отображаемое имя (Ф.И.О.) |
NamePrefix |
string |
Префикс имени контакта |
NameSuffix |
string |
Суффикс имени контакта |
Phones |
List<ContactPhone> |
Список телефонных номеров |
Emails |
List<ContactEmail> |
Список адресов Email |
Допишем модель представления следующим образом:
public class ContactsViewModel: INotifyPropertyChanged
{
public ObservableCollection<Contact> ContactList { get; set; } = [];
private Contact selectedContact;
public Contact SelectedContact {
get => selectedContact;
set
{
if (value != selectedContact)
{
selectedContact = value;
OnPropertyChanged();
}
}
}
private ContactPhone selectedPhone;
public ContactPhone SelectedPhone {
get => selectedPhone;
set
{
if (value != selectedPhone)
{
selectedPhone = value;
OnPropertyChanged();
}
}
}
private ContactEmail selectedEmail;
public ContactEmail SelectedEmail
{
get => selectedEmail;
set
{
if (value != selectedEmail)
{
selectedEmail = value;
OnPropertyChanged();
}
}
}
public ICommand ReadContacts { get; set; }
public ContactsViewModel()
{
ReadContacts = new Command(async () =>
{
if (await CheckPermissionStatus() == PermissionStatus.Granted)
{
foreach (var contact in await Microsoft.Maui.ApplicationModel.Communication.Contacts.Default.GetAllAsync())
{
ContactList.Add(contact);
}
if (ContactList.Count > 0)
{
SelectedContact = ContactList[0];
OnPropertyChanged(nameof(SelectedContact));
}
}
});
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
public async Task<PermissionStatus> CheckPermissionStatus()
{
var currentStatus = await Permissions.CheckStatusAsync<Permissions.ContactsRead>();
if (currentStatus != PermissionStatus.Granted)
{
currentStatus = await Permissions.RequestAsync<Permissions.ContactsRead>();
}
return currentStatus;
}
}
Здесь мы добавили три новых свойства:
Выбранный контакт
private Contact selectedContact;
public Contact SelectedContact {
get => selectedContact;
set
{
if (value != selectedContact)
{
selectedContact = value;
OnPropertyChanged();
}
}
}
Выбранный у контакта номер телефона
private ContactPhone selectedPhone;
public ContactPhone SelectedPhone {
get => selectedPhone;
set
{
if (value != selectedPhone)
{
selectedPhone = value;
OnPropertyChanged();
}
}
}
Выбранный у контакта адрес Email
private ContactEmail selectedEmail;
public ContactEmail SelectedEmail
{
get => selectedEmail;
set
{
if (value != selectedEmail)
{
selectedEmail = value;
OnPropertyChanged();
}
}
}
Для того, чтобы мы могли отслеживать изменения этих свойств, мы реализовали интерфейс INotifyPropertyChanged.
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
Теперь используем эти свойства для привязки. Изменим XAML-код страницы следующим образом:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiPhone.ViewModels"
xmlns:model="clr-namespace:Microsoft.Maui.ApplicationModel.Communication;assembly=Microsoft.Maui.Essentials"
x:Class="MauiPhone.MainPage"
x:DataType="local:ContactsViewModel">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Button Text="Посмотреть контакты" Command="{Binding ReadContacts}" />
<Picker ItemsSource="{Binding ContactList, Mode=TwoWay}"
ItemDisplayBinding="{Binding DisplayName}"
SelectedItem="{Binding SelectedContact, Mode=TwoWay}"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Text="Отображаемое имя" Grid.Row="0" Grid.Column="0"/>
<Label Text="Имя" Grid.Row="1" Grid.Column="0"/>
<Label Text="Отчество" Grid.Row="2" Grid.Column="0"/>
<Label Text="Фамилия" Grid.Row="3" Grid.Column="0"/>
<Label Text="Список телефонов" Grid.Row="4" Grid.Column="0" VerticalOptions="Center"/>
<Label Text="Список Email" Grid.Row="5" Grid.Column="0" VerticalOptions="Center"/>
<Label Text="{Binding SelectedContact.DisplayName, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" />
<Label Text="{Binding SelectedContact.GivenName, Mode=TwoWay}" Grid.Row="1" Grid.Column="1"/>
<Label Text="{Binding SelectedContact.MiddleName, Mode=TwoWay}" Grid.Row="2" Grid.Column="1"/>
<Label Text="{Binding SelectedContact.FamilyName, Mode=TwoWay}" Grid.Row="3" Grid.Column="1"/>
<Picker ItemsSource="{Binding SelectedContact.Phones, Mode=TwoWay}" SelectedItem="{Binding SelectedPhone}" Grid.Row="4" Grid.Column="1"/>
<Picker ItemsSource="{Binding SelectedContact.Emails, Mode=TwoWay}" SelectedItem="{Binding SelectedEmail}" Grid.Row="5" Grid.Column="1"/>
</Grid>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Здесь мы привязываем визуальные компоненты Label и Picker к свойствам контакта. Теперь при выборе контакта в первом списке мы должны увидеть основные свойства выбранного контакта.
Запустим приложение, загрузим список контактов и выберем какой-нибудь контакт в списке:

Если у контакта есть список телефонов или адресов электронной почты, то они отобразятся в соответствующих списках.
Выбор контакта методом PickContactAsync()
Если вам не требуется загружать весь список контактов в своё приложение, а достаточно просто открыть адресную книгу и выбрать в ней конкретный контакт, то можно воспользоваться методом PickContactAsync(). Добавим в модель представления ещё одну команду:
public ICommand PickContact { get; set; }
public ContactsViewModel()
{
PickContact = new Command(async () =>
{
var contact = await Microsoft.Maui.ApplicationModel.Communication.Contacts.Default.PickContactAsync();
if (contact != null)
{
SelectedContact = contact;
}
});
...
}
Здесь мы вызываем метод PickContactAsync() и, если результатом будет не null, то выбранный контакт будет присвоен свойству SelectedContact, что приведен к отображению свойств контакта в приложении.
Добавим на страницу MainPage новую кнопку и сделаем необходимую привязку к команде:
<Button Text="Выбрать контакт из адресной книги" Command="{Binding PickContact}" />
Запустим приложение и проверим результат. При нажатии на кнопку «Выбрать контакт из адресной книги» операционная система предложит выбор приложения для контактов (если на устройстве таких приложений несколько):
После выбора, откроется соответствующее приложение с контактами. Если контакт будет выбран, то в приложении вы увидите его свойства также, как и на рисунке выше.
Итого
Для выбора контактов в Android используется интерфейс IContacts, реализация по умолчанию которого содержится в свойстве Default статического класса Contacts. При этом мы можем как загрузить весь список контактов в приложение, так и выбрать конкретный контакт, воспользовавшись методом PickContactAsync()

