Контакты и контакты в Xamarin.iOS
В этой статье рассматривается работа с новыми платформами пользовательского интерфейса контактов и контактов в приложении Xamarin.iOS. Эти платформы заменяют существующий пользовательский интерфейс адресной книги и адресной книги, используемый в предыдущих версиях iOS.
С введением iOS 9 Apple выпустила две новые платформы, Contacts
и ContactsUI
, заменив существующие платформы адресной книги и пользовательского интерфейса адресной книги, используемые iOS 8 и более ранними версиями.
Две новые платформы содержат следующие функции:
Контакты — предоставляет доступ к данным списка контактов пользователя. Так как большинству приложений требуется только доступ только для чтения, эта платформа оптимизирована для безопасного потока, доступ только для чтения.
ContactsUI — предоставляет элементы пользовательского интерфейса Xamarin.iOS для отображения, изменения, выбора и создания контактов на устройствах iOS.
Внимание
Существующие AddressBook
и AddressBookUI
платформы, используемые iOS 8 (и более поздней версии), устарели в iOS 9 и должны быть заменены новыми Contacts
и ContactsUI
платформами как можно скорее для любого существующего приложения Xamarin.iOS. Новые приложения должны быть написаны на новых платформах.
В следующих разделах мы рассмотрим эти новые платформы и как реализовать их в приложении Xamarin.iOS.
Платформа контактов
Платформа контактов предоставляет Xamarin.iOS доступ к контактным данным пользователя. Так как большинству приложений требуется только доступ только для чтения, эта платформа оптимизирована для безопасного потока, доступ только для чтения.
Объекты контакта
Класс CNContact
предоставляет потокобезопасный доступ только для чтения к свойствам контакта, таким как имя, адрес или номера Телефон. CNContact
функции, такие как и NSDictionary
содержат несколько, доступных только для чтения коллекций свойств (например, адресов или номеров телефонов):
Для любого свойства, которое может иметь несколько значений (например, адрес электронной почты или номера телефона), они будут представлены в виде массива NSLabeledValue
объектов. NSLabeledValue
— это потокобезопасный кортеж, состоящий из набора меток только для чтения и значений, где метка определяет значение для пользователя (например, домашняя или рабочая почта). Платформа контактов предоставляет выбор предопределенных меток (с помощью CNLabelKey
и CNLabelPhoneNumberKey
статических классов), которые можно использовать в приложении или вы можете определить пользовательские метки для ваших потребностей.
Для любого приложения Xamarin.iOS, необходимого для настройки значений существующего контакта (или создания новых), используйте NSMutableContact
версию класса и его подклассы (например CNMutablePostalAddress
).
Например, следующий код создаст новый контакт и добавит его в коллекцию контактов пользователя:
// Create a new Mutable Contact (read/write)
var contact = new CNMutableContact();
// Set standard properties
contact.GivenName = "John";
contact.FamilyName = "Appleseed";
// Add email addresses
var homeEmail = new CNLabeledValue<NSString>(CNLabelKey.Home, new NSString("john.appleseed@mac.com"));
var workEmail = new CNLabeledValue<NSString>(CNLabelKey.Work, new NSString("john.appleseed@apple.com"));
contact.EmailAddresses = new CNLabeledValue<NSString>[] { homeEmail, workEmail };
// Add phone numbers
var cellPhone = new CNLabeledValue<CNPhoneNumber>(CNLabelPhoneNumberKey.iPhone, new CNPhoneNumber("713-555-1212"));
var workPhone = new CNLabeledValue<CNPhoneNumber>("Work", new CNPhoneNumber("408-555-1212"));
contact.PhoneNumbers = new CNLabeledValue<CNPhoneNumber>[] { cellPhone, workPhone };
// Add work address
var workAddress = new CNMutablePostalAddress()
{
Street = "1 Infinite Loop",
City = "Cupertino",
State = "CA",
PostalCode = "95014"
};
contact.PostalAddresses = new CNLabeledValue<CNPostalAddress>[] { new CNLabeledValue<CNPostalAddress>(CNLabelKey.Work, workAddress) };
// Add birthday
var birthday = new NSDateComponents()
{
Day = 1,
Month = 4,
Year = 1984
};
contact.Birthday = birthday;
// Save new contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, store.DefaultContainerIdentifier);
// Attempt to save changes
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error))
{
Console.WriteLine("New contact saved");
}
else
{
Console.WriteLine("Save error: {0}", error);
}
Если этот код выполняется на устройстве iOS 9, новый контакт будет добавлен в коллекцию пользователя. Например:
Форматирование контактов и локализация
Платформа "Контакты" содержит несколько объектов и методов, которые помогают форматировать и локализовать содержимое для отображения пользователю. Например, следующий код будет правильно форматировать имя контактов и адрес рассылки для отображения:
Console.WriteLine(CNContactFormatter.GetStringFrom(contact, CNContactFormatterStyle.FullName));
Console.WriteLine(CNPostalAddressFormatter.GetStringFrom(workAddress, CNPostalAddressFormatterStyle.MailingAddress));
Для меток свойств, отображаемых в пользовательском интерфейсе приложения, платформа Contact имеет методы локализации этих строк. Опять же, это основано на текущем языковом стандарте устройства iOS, на который выполняется приложение. Например:
// Localized properties
Console.WriteLine(CNContact.LocalizeProperty(CNContactOptions.Nickname));
Console.WriteLine(CNLabeledValue<NSString>.LocalizeLabel(CNLabelKey.Home));
Извлечение существующих контактов
Используя экземпляр CNContactStore
класса, можно получить контактные данные из базы данных контактов пользователя. Содержит CNContactStore
все методы, необходимые для получения или обновления контактов и групп из базы данных. Так как эти методы синхронны, рекомендуется запускать их в фоновом потоке, чтобы не блокировать пользовательский интерфейс.
Используя предикаты (созданные из CNContact
класса), можно фильтровать результаты, возвращаемые при получении контактов из базы данных. Чтобы получить только контакты, содержащие строку Appleseed
, используйте следующий код:
// Create predicate to locate requested contact
var predicate = CNContact.GetPredicateForContacts("Appleseed");
Внимание
Универсальные и составные предикаты не поддерживаются платформой контактов.
Например, чтобы ограничить получение только свойствами GivenName и FamilyName контакта, используйте следующий код:
// Define fields to be searched
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName};
Наконец, чтобы искать базу данных и возвращать результаты, используйте следующий код:
// Grab matching contacts
var store = new CNContactStore();
NSError error;
var contacts = store.GetUnifiedContacts(predicate, fetchKeys, out error);
Если этот код был запущен после примера, созданного в приведенном выше разделе "Объекты контактов", он вернет только что созданный контакт John Appleseed.
Конфиденциальность контактов
Так как конечные пользователи могут предоставить или запретить доступ к контактным данным на основе каждого приложения, при первом вызове в CNContactStore
приложение появится диалоговое окно с просьбой разрешить им доступ к приложению.
Запрос на разрешение будет представлен только один раз, при первом запуске приложения и последующих запусках или вызовах для CNContactStore
использования разрешения, выбранного пользователем в то время.
Вы должны разработать приложение таким образом, чтобы он корректно обрабатывал пользователя, отказывающего в доступе к базе данных контактов.
Получение частичных контактов
Частичный контакт — это контакт , для которых извлекается только часть доступных свойств из хранилища контактов. Если вы пытаетесь получить доступ к свойству, которое ранее не было возвращено, это приведет к исключению.
Вы можете легко проверка, чтобы узнать, имеет ли данный контакт требуемое свойство с помощью либо IsKeyAvailable
AreKeysAvailable
методов экземпляраCNContact
. Например:
// Does the contact contain the requested key?
if (!contact.IsKeyAvailable(CNContactOption.PostalAddresses)) {
// No, re-request to pull required info
var fetchKeys = new NSString[] {CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.PostalAddresses};
var store = new CNContactStore();
NSError error;
contact = store.GetUnifiedContact(contact.Identifier, fetchKeys, out error);
}
Внимание
GetUnifiedContacts
Методы CNContactStore
GetUnifiedContact
класса возвращают только частичный контакт, ограниченный свойствами, запрашиваемыми из предоставленных ключей получения.
Объединенные контакты
У пользователя могут быть разные источники контактных данных для одного человека в базе данных контактов (например, iCloud, Facebook или Google Mail). В приложениях iOS и OS X эти контактные данные автоматически будут связаны и отображаются пользователю в виде единого единого контакта:
Этот единый контакт — это временное представление контактных данных ссылки в памяти, которое будет присвоено собственному уникальному идентификатору (которое должно использоваться для ссылки при необходимости). По умолчанию платформа "Контакты" возвращает единый контакт по возможности.
Создание и обновление контактов
Как мы видели в приведенном выше разделе "Объекты контактов", вы используете CNContactStore
и экземпляр CNMutableContact
объекта для создания новых контактов, которые затем записываются в базу данных контактов пользователя с помощью CNSaveRequest
:
// Create a new Mutable Contact (read/write)
var contact = new CNMutableContact();
// Set standard properties
contact.GivenName = "John";
contact.FamilyName = "Appleseed";
// Save new contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, store.DefaultContainerIdentifier);
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error)) {
Console.WriteLine("New contact saved");
} else {
Console.WriteLine("Save error: {0}", error);
}
Можно CNSaveRequest
также использовать для кэширования нескольких изменений контактов и групп в одну операцию и пакетировать эти изменения CNContactStore
.
Чтобы обновить неизменяемый контакт, полученный из операции получения, необходимо сначала запросить изменяемую копию, которую затем изменить и сохранить обратно в хранилище контактов. Например:
// Get mutable copy of contact
var mutable = contact.MutableCopy() as CNMutableContact;
var newEmail = new CNLabeledValue<NSString>(CNLabelKey.Home, new NSString("john.appleseed@xamarin.com"));
// Append new email
var emails = new NSObject[mutable.EmailAddresses.Length+1];
mutable.EmailAddresses.CopyTo(emails,0);
emails[mutable.EmailAddresses.Length+1] = newEmail;
mutable.EmailAddresses = emails;
// Update contact
var store = new CNContactStore();
var saveRequest = new CNSaveRequest();
saveRequest.UpdateContact(mutable);
NSError error;
if (store.ExecuteSaveRequest(saveRequest, out error)) {
Console.WriteLine("Contact updated.");
} else {
Console.WriteLine("Update error: {0}", error);
}
Уведомления об изменениях контактов
Всякий раз, когда контакт изменяется, хранилище контактов публикует в CNContactStoreDidChangeNotification
Центре уведомлений по умолчанию. Если вы кэшировали или отображают какие-либо контакты, необходимо обновить эти объекты из хранилища контактов (CNContactStore
).
Контейнеры и группы
Контакты пользователя могут существовать локально на устройстве пользователя или как контакты, синхронизированные с устройством из одной или нескольких учетных записей сервера (например, Facebook или Google). Каждый пул контактов имеет собственный контейнер , и данный контакт может существовать только в одном контейнере.
Некоторые контейнеры позволяют упорядочивать контакты в одну или несколько групп или подгрупп. Это поведение зависит от резервного хранилища для данного контейнера. Например, iCloud имеет только один контейнер, но может иметь множество групп (но не подгрупп). С другой стороны, Microsoft Exchange не поддерживает группы, но может иметь несколько контейнеров (по одному для каждой папки Exchange).
Платформа ContactsUI
В ситуациях, когда приложению не требуется представить пользовательский интерфейс, можно использовать платформу ContactsUI для отображения, редактирования, выбора и создания контактов в приложении Xamarin.iOS.
Используя встроенные элементы управления Apple, вы не только сокращаете объем кода, который необходимо создать для поддержки контактов в приложении Xamarin.iOS, но и представляет согласованный интерфейс для пользователей приложения.
Контроллер представления средства выбора контактов
Контроллер представления выбора контактов (CNContactPickerViewController
) управляет стандартным представлением выбора контактов, которое позволяет пользователю выбирать контакт или свойство Contact из базы данных контактов пользователя. Пользователь может выбрать один или несколько контактов (на основе его использования), а контроллер представления выбора контактов не запрашивает разрешение перед отображением средства выбора.
Перед вызовом CNContactPickerViewController
класса вы определите свойства, которые пользователь может выбрать и определить предикаты для управления отображением и выбором свойств контакта.
Используйте экземпляр класса, наследуемого от CNContactPickerDelegate
ответа на взаимодействие пользователя с средством выбора. Например:
using System;
using System.Linq;
using UIKit;
using Foundation;
using Contacts;
using ContactsUI;
namespace iOS9Contacts
{
public class ContactPickerDelegate: CNContactPickerDelegate
{
#region Constructors
public ContactPickerDelegate ()
{
}
public ContactPickerDelegate (IntPtr handle) : base (handle)
{
}
#endregion
#region Override Methods
public override void ContactPickerDidCancel (CNContactPickerViewController picker)
{
Console.WriteLine ("User canceled picker");
}
public override void DidSelectContact (CNContactPickerViewController picker, CNContact contact)
{
Console.WriteLine ("Selected: {0}", contact);
}
public override void DidSelectContactProperty (CNContactPickerViewController picker, CNContactProperty contactProperty)
{
Console.WriteLine ("Selected Property: {0}", contactProperty);
}
#endregion
}
}
Чтобы разрешить пользователю выбрать адрес электронной почты из контактов в базе данных, можно использовать следующий код:
// Create a new picker
var picker = new CNContactPickerViewController();
// Select property to pick
picker.DisplayedPropertyKeys = new NSString[] {CNContactKey.EmailAddresses};
picker.PredicateForEnablingContact = NSPredicate.FromFormat("emailAddresses.@count > 0");
picker.PredicateForSelectionOfContact = NSPredicate.FromFormat("emailAddresses.@count == 1");
// Respond to selection
picker.Delegate = new ContactPickerDelegate();
// Display picker
PresentViewController(picker,true,null);
Контроллер представления контактов
Класс "КонтроллерCNContactViewController
представления контактов" предоставляет контроллеру для представления стандартного представления контактов конечному пользователю. Представление контакта может отображать новые, неизвестные или существующие контакты, а тип должен быть указан перед отображением представления путем вызова правильного статического конструктора (FromNewContact
, FromUnknownContact
, ). FromContact
Пример:
// Create a new contact view
var view = CNContactViewController.FromContact(contact);
// Display the view
PresentViewController(view, true, null);
Итоги
В этой статье подробно рассматривается работа с платформами пользовательского интерфейса контактов и контактов в приложении Xamarin.iOS. Во-первых, он охватывал различные типы объектов, которые предоставляет платформа Contact и как они используются для создания новых или доступа к существующим контактам. Она также изучила платформу пользовательского интерфейса контактов, чтобы выбрать существующие контакты и отобразить контактные данные.