В этом руководстве мы собираемся изучить различные способы интеграции нашего приложения с функциями, предлагаемыми платформой Windows Phone. Мы рассмотрим варианты запуска и выбора, узнаем, как взаимодействовать с контактами и встречами, а также узнаем, как воспользоваться преимуществами Kid’s Corner — инновационной функции, которая позволяет детям безопасно пользоваться телефоном.
Пусковые установки и Выбор
Когда мы обсуждали хранилище ранее в этой серии, мы ввели понятие изолированных приложений. Точно так же, как хранилище изолировано так, что вы не можете получить доступ к данным, хранящимся в другом приложении, само приложение изолировано от операционной системы.
Самым большим преимуществом этого подхода является безопасность. Даже если вредоносное приложение сможет пройти процесс сертификации, оно не сможет нанести значительный ущерб, поскольку не имеет прямого доступа к операционной системе. Но рано или поздно вам придется взаимодействовать с одной из многих функций Windows Phone, таких как отправка сообщения, телефонный звонок, воспроизведение песни и т. Д.
Для всех этих сценариев платформа представила средства запуска и выбора, которые представляют собой наборы API, которые требуют конкретной задачи от операционной системы. Как только задача завершена, управление возвращается приложению.
Пусковые установки — это API «запускай и забывай». Вы требуете операции и ничего не ожидаете взамен — например, телефонный звонок или воспроизведение видео.
Средства выбора используются для получения данных из собственного приложения, например контактов из People Hub, и их импорта в ваше приложение.
Все средства запуска и выбора доступны в пространстве имен Microsoft.Phone.Tasks
и имеют одинаковое поведение:
- Каждый модуль запуска и выбора представлен конкретным классом.
- При необходимости вы устанавливаете некоторые свойства, которые используются для определения настроек программы запуска или выбора.
- С помощью выбора вы должны подписаться на событие
Completed
, которое срабатывает после завершения операции. - Метод
Show()
вызывается для выполнения задачи.
Примечание. Средства запуска и выбора не могут использоваться для переопределения встроенного механизма безопасности Windows Phone, поэтому вы не сможете выполнять операции без явного разрешения пользователя.
В следующем примере вы можете увидеть средство запуска, которое отправляет электронное письмо с EmailComposeTask
класса EmailComposeTask
:
01
02
03
04
05
06
07
08
09
10
11
|
private void OnComposeMailClicked(object sender, RoutedEventArgs e)
{
EmailComposeTask mailTask = new EmailComposeTask();
mailTask.To = “[email protected]”;
mailTask.Cc = “[email protected]”;
mailTask.Subject = “Subject”;
mailTask.Body = “Body”;
mailTask.Show();
}
|
В следующем примере показано, как использовать селектор. Мы собираемся сохранить новый контакт в People Hub с SaveContactTask
класса SaveContactTask
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private void OnSaveContactClicked(object sender, RoutedEventArgs e)
{
SaveContactTask task = new SaveContactTask();
task.Completed += task_Completed;
task.FirstName = “John”;
task.LastName = “Doe”;
task.MobilePhone = “1234567890”;
task.Show();
}
void task_Completed(object sender, SaveContactResult e)
{
if (e.TaskResult == TaskResult.OK)
{
MessageBox.Show(“The contact has been saved successfully”);
}
}
|
Каждый chooser возвращает свойство TaskResult
со статусом операции. Важно убедиться, что статус TaskResult.OK
прежде чем двигаться дальше, потому что пользователь мог отменить операцию.
Ниже приведен список всех доступных пусковых установок:
-
MapsDirectionTask
используется для открытия собственного приложения Map и вычисления пути между двумя местами. -
MapsTask
используется для открытия собственного приложения Map с центром в определенном месте. -
MapDownloaderTask
используется для управления поддержкой автономных карт, новой для Windows Phone 8. С помощью этой задачи вы сможете открыть страницу настроек, используемую для управления загруженными картами. -
MapUpdaterTask
используется для перенаправления пользователя на определенную страницу настроек для проверки наличия обновлений автономных карт. -
ConnectionSettingsTask
используется для быстрого доступа к различным страницам настроек для управления различными доступными соединениями, такими как Wi-Fi, сотовая связь или Bluetooth. -
EmailComposeTask
используется для подготовки электронного письма и его отправки. -
MarketplaceDetailTask
используется для отображения страницы сведений о приложении в Магазине Windows Phone. Если вы не предоставите идентификатор приложения, откроется страница сведений о текущем приложении. -
MarketplaceHubTask
используется для открытия магазина определенной категории. -
MarketplaceReviewTask
используется для открытия страницы в Магазине Windows Phone, где пользователь может оставить отзыв о текущем приложении. -
MarketplaceSearchTask
используется для запуска поиска по определенному ключевому слову в Магазине. -
MediaPlayerLauncher
используется для воспроизведения аудио или видео с помощью внутреннего проигрывателя Windows Phone. Он может воспроизводить как файлы, встроенные в проект Visual Studio, так и файлы, сохраненные в локальном хранилище. -
PhoneCallTask
используется для начала телефонного звонка. -
ShareLinkTask
используется дляShareLinkTask
ссылки в социальной сети с помощью встроенных социальных функций Windows Phone. -
ShareStatusTask
используется для обмена пользовательским текстом статуса в социальной сети. -
ShareMediaTask
используется, чтобы поделиться одной из картинок из Photos Hub в социальной сети. -
SmsComposeTask
используется для подготовки текстового сообщения и его отправки. -
WebBrowserTask
используется для открытия URI в Internet Explorer для Windows Phone. -
SaveAppointmentTask
используется для сохранения встречи в собственном приложении Календарь.
Ниже приведен список доступных селекторов:
-
AddressChooserTask
используется для импорта адреса контакта. -
CameraCaptureTask
используется для съемки с помощью встроенной камеры и импорта ее в приложение. -
EmailAddressChooserTask
используется для импорта адреса электронной почты контакта. -
PhoneNumberChooserTask
используется для импорта номера телефона контакта. -
PhotoChooserTask
используется для импорта фотографии из центра фотографий. -
SaveContactTask
используется для сохранения нового контакта в People Hub. Селектор просто возвращает, была ли операция успешно завершена. -
SaveEmailAddressTask
используется для добавления нового адреса электронной почты к существующему или новому контакту. Селектор просто возвращает, была ли операция успешно завершена. -
SavePhoneNumberTask
используется для добавления нового номера телефона к существующему контакту. Селектор просто возвращает, была ли операция успешно завершена. -
SaveRingtoneTask
используется для сохранения новой мелодии звонка (которая может быть частью проекта или храниться в локальном хранилище). Возвращает, была ли операция успешно завершена.
Получение контактов и встреч
Средства запуска уже предоставляют базовый способ взаимодействия с People Hub, но они всегда требуют взаимодействия с пользователем. Они открывают People Hub, и пользователь должен выбрать, какой контакт импортировать.
Однако в определенных сценариях вам нужна возможность программно получать контакты и встречи для данных. Windows Phone 7.5 представила несколько новых API для удовлетворения этого требования. Вам просто нужно помнить, что для соблюдения ограничений безопасности Windows Phone эти API работают только в режиме только для чтения; вы сможете получать данные, но не сохраняете их (далее в этой статье мы увидим, что в Windows Phone 8 появился способ переопределить это ограничение).
В следующей таблице вы можете увидеть, к каким данным вы можете получить доступ в зависимости от того, где сохранены контакты.
поставщик |
Контактное лицо |
Изображение контакта |
Дополнительная информация |
Календарь назначений |
устройство |
да |
да |
да |
да |
Outlook.com |
да |
да |
да |
да |
обмен |
да |
да |
да |
да |
SIM |
да |
да |
да |
нет |
|
да |
да |
да |
нет |
Другие социальные сети |
нет |
нет |
нет |
нет |
Чтобы узнать, откуда поступают данные, вы можете использовать свойство « Accounts
, которое представляет собой набор учетных записей, в которых хранится информация. Фактически, вы можете располагать информацией об одних и тех же данных в разных учетных записях.
Работа с контактами
Каждый контакт представлен классом Contact
, который содержит всю информацию о контакте, такую как DisplayName
, Addresses
, EmailAddresses
, EmailAddresses
Birthdays
и т. Д. (В основном, вся информация, которую вы можете редактировать при создании нового контакта в People Hub) ,
Примечание. Для доступа к контактам необходимо включить параметр ID_CAP_CONTACTS
в файле манифеста.
Взаимодействие с контактами начинается с класса « Contacts
», который можно использовать для поиска с помощью SearchAsync()
. Метод требует два параметра: ключевое слово и фильтр для применения. Есть два способа начать поиск:
- Общий поиск: ключевое слово не требуется, так как вы просто получите все контакты, которые соответствуют выбранному фильтру. Этот тип поиска может быть реализован с помощью двух типов фильтров:
FilterKind.PinnedToStart
который возвращает только контакты, которые пользовательFilterKind.None
на начальном экране, иFilterKind.None
который просто возвращает все доступные контакты. - Поиск определенного поля. В этом случае ключевое слово поиска будет применяться на основе выбранного фильтра. Доступные фильтры:
DisplayName
,EmailAddress
иPhoneNumber
.
Метод SearchAsync()
использует метод обратного вызова; По завершении поиска вызывается событие SearchCompleted
.
В следующем примере вы можете найти поиск, который ищет все контакты, которых зовут Джон. Коллекция возвращенных контактов представляется пользователю с помощью ListBox
управления ListBox
.
01
02
03
04
05
06
07
08
09
10
11
|
private void OnStartSearchClicked(object sender, RoutedEventArgs e)
{
Contacts contacts = new Contacts();
contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
contacts.SearchAsync(«John», FilterKind.DisplayName, null);
}
void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
Contacts.ItemsSource = e.Results;
}
|
Совет: если вы хотите начать поиск другого поля, которое не включено в доступные фильтры, вам нужно получить список всех доступных контактов с помощью параметра FilterKind.None
и применить фильтр с помощью запроса LINQ. Разница в том, что встроенные фильтры оптимизированы для повышения производительности, поэтому используйте подход LINQ только в том случае, если вам нужно найти поле, отличное от имени, адреса электронной почты или номера телефона.
Работа с назначениями
Получение данных из календаря работает очень схожим образом: каждое назначение идентифицируется классом « Appointment
», который имеет такие свойства, как « Subject
, « Status
, « Location
, « EndTime
и « EndTime
.
Чтобы взаимодействовать с календарем, вам нужно использовать класс Appointments
который, как и класс Contacts
, использует метод SearchAsync()
для запуска поиска и событие SearchCompleted
для возврата результатов.
Для выполнения поиска требуются только два параметра: дата начала и дата окончания. Вы получите взамен все встречи в течение этого времени. При желании вы также можете установить максимальное количество результатов для возврата или ограничить поиск конкретной учетной записью.
В следующем примере мы извлекаем все встречи, которые происходят между текущей датой и днем ранее, и отображаем их с помощью ListBox
управления ListBox
.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
private void OnStartSearchClicked(object sender, RoutedEventArgs e)
{
Appointments calendar = new Appointments();
calendar.SearchCompleted += calendar_SearchCompleted;
DateTime start = DateTime.Now.AddMonths(-1);
DateTime end = DateTime.Now;
calendar.SearchAsync(start, end, null);
}
void calendar_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
{
Calendar.ItemsSource = e.Results;
}
|
Совет: Единственный способ отфильтровать результаты по дате начала и дате окончания. Если вам необходимо применить дополнительные фильтры, вам нужно будет выполнить LINQ-запросы к результатам, возвращаемым операцией поиска.
Частный магазин контактов для приложений
Самое большое ограничение API контактов, которое мы видели до сих пор, это то, что мы можем только читать данные, а не записывать их. В некоторых ситуациях требуется добавить контакты в People Hub без запроса разрешения пользователя, например приложение социальной сети, которое хочет добавить своих друзей в список контактов, или клиент синхронизации, который необходимо сохранить. информация из стороннего облачного сервиса в вашей контактной книге.
В Windows Phone 8 появился новый класс ContactStore
, представляющий личную книгу контактов для приложения. С точки зрения пользователя, он ведет себя как обычный источник контактов (например, Outlook.com, Facebook или Gmail). Пользователь сможет видеть контакты в People Hub, смешанные со всеми другими обычными контактами.
С точки зрения разработчика, магазин принадлежит приложению; Вы можете свободно читать и записывать данные, но каждый созданный вами контакт будет частью вашей личной контактной книги, а не списка контактов телефона. Это означает, что если приложение будет удалено, все контакты будут потеряны.
Класс ContactStore
принадлежит пространству имен Windows.Phone.PersonalInformation
и предлагает метод с именем CreateOrOpenAsync()
. Метод должен вызываться каждый раз, когда вам нужно взаимодействовать с личной книгой контактов. Если он не существует, он будет создан; в противном случае он будет просто открыт.
При создании ContactStore
вы можете указать, как операционная система должна предоставлять к нему доступ:
- Тип первого параметра —
ContactStoreSystemAccessMode
, и он используется для выбора того, сможет ли приложение редактировать только контакты, принадлежащие частному хранилищу (ReadOnly
), или пользователь также сможет редактировать информацию с помощью People Hub (ReadWrite
). - Тип второго параметра —
ContactStoreApplicationAccessMode
, и он используется для выбора того, смогут ли другие сторонние приложения получить доступ ко всей информации о наших контактах (ReadOnly
) или только к наиболее важным, таким как имя и изображение (LimitedReadOnly
).
В следующем примере показан код, необходимый для создания нового частного хранилища:
1
2
3
4
|
private async void OnCreateStoreClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
}
|
Совет: После создания частного хранилища вы не можете изменить определенные вами разрешения, поэтому вам всегда нужно вызывать метод CreateOrOpenAsync()
с теми же параметрами.
Создание контактов
Контакт определяется классом StoredContact
, который немного отличается от класса Contact
мы видели ранее. В этом случае единственными доступными свойствами являются GivenName
и FamilyName
. Доступ ко всем остальным свойствам можно получить, вызвав метод GetPropertiesAsync()
класса StoredContact
, который возвращает коллекцию типа Dictionary<string, object>
.
Каждый элемент коллекции идентифицируется ключом (имя свойства контакта) и объектом (значение). Чтобы помочь разработчикам получить доступ к свойствам, все доступные ключи хранятся в объекте enum с именем KnownContactProperties
. В следующем примере мы используем ключ KnowContactProperties.Email
для хранения адреса электронной почты пользователя.
01
02
03
04
05
06
07
08
09
10
11
12
|
private async void OnCreateStoreClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
StoredContact contact = new StoredContact(store);
contact.GivenName = «Matteo»;
contact.FamilyName = «Pagani»;
IDictionary<string, object> properties = await contact.GetPropertiesAsync();
properties.Add(KnownContactProperties.Email, «[email protected]»);
await contact.SaveAsync();
}
|
Совет: поскольку ContactStore
является словарем, два значения не могут иметь одинаковый ключ. Прежде чем добавить новое свойство в контакт, вы должны убедиться, что оно еще не существует; в противном случае вам нужно обновить существующий.
Класс StoredContact
также поддерживает способ хранения пользовательской информации путем доступа к расширенным свойствам с помощью GetExtendedPropertiesAsync()
. Он работает как стандартные свойства, за исключением того, что ключ свойства полностью настраиваемый. Такие свойства не будут отображаться в People Hub, поскольку Windows Phone не знает, как с ними обращаться, но они могут использоваться вашим приложением.
В следующем примере мы добавляем новую пользовательскую информацию под названием MVP Category
:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
private async void OnCreateStoreClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
StoredContact contact = new StoredContact(store);
contact.GivenName = «Matteo»;
contact.FamilyName = «Pagani»;
IDictionary<string, object> extendedProperties = await contact.GetExtendedPropertiesAsync();
extendedProperties.Add(«MVP Category», «Windows Phone Development»);
await contact.SaveAsync();
}
|
Поиск контактов
Поиск контактов в личной книге контактов немного сложен, потому что нет прямого способа поиска контакта по определенному полю.
Поиск выполняется с использованием класса ContactQueryResult
, который создается путем вызова метода CreateContactQuery()
объекта ContactStore
. Единственными доступными операциями являются GetContactsAsync()
, которая возвращает все контакты, и GetContactCountAsync()
, который возвращает количество доступных контактов.
Вы также можете заранее определить, с какими полями вы собираетесь работать, но вам все равно придется использовать метод GetPropertiesAsync()
для извлечения правильных значений. Давайте посмотрим, как это работает в следующем примере, в котором мы ищем контакт, адрес электронной почты которого является [email protected]
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private async void OnSearchContactClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
ContactQueryOptions options = new ContactQueryOptions();
options.DesiredFields.Add(KnownContactProperties.Email);
ContactQueryResult result = store.CreateContactQuery(options);
IReadOnlyList<StoredContact> contactList = await result.GetContactsAsync();
foreach (StoredContact contact in contactList)
{
IDictionary<string, object> properties = await contact.GetPropertiesAsync();
if (properties.ContainsKey(KnownContactProperties.Email) &&
properties[KnownContactProperties.Email].ToString() == «[email protected]»)
{
MessageBox.Show(«Contact found!»);
}
}
}
|
Вы можете определить, какие поля вас интересуют, создав новый объект ContactQueryOptions
и добавив его в коллекцию DesiredFields
. Затем вы можете передать объект ContactQueryOptions
в качестве параметра при создании ContactQueryResult
. Как видите, определения полей недостаточно для получения желаемого результата. Нам все еще нужно запросить каждый контакт, используя метод GetPropertiesAsync()
чтобы узнать, является ли значение информации искомым.
Цель класса ContactQueryOptions
— подготовить следующие операции запроса, чтобы они могли выполняться быстрее.
Обновление и удаление контактов
Обновление контакта осуществляется так же, как и создание нового: после того, как вы получили контакт, который хотите изменить, вам нужно изменить необходимую информацию и снова вызвать метод SaveAsync()
, как в следующем примере:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
private async void OnSearchContactClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
ContactQueryOptions options = new ContactQueryOptions();
options.DesiredFields.Add(KnownContactProperties.Email);
ContactQueryResult result = store.CreateContactQuery(options);
IReadOnlyList<StoredContact> contactList = await result.GetContactsAsync();
foreach (StoredContact contact in contactList)
{
IDictionary<string, object> properties = await contact.GetPropertiesAsync();
if (properties.ContainsKey(KnownContactProperties.Email) &&
properties[KnownContactProperties.Email].ToString() == «[email protected]»)
{
properties[KnownContactProperties.Email] = «[email protected]»;
await contact.SaveAsync();
}
}
}
|
После того, как мы [email protected]
пользователя, чей адрес электронной почты — [email protected]
, мы изменили его на [email protected]
и сохранили его.
Удаление работает аналогичным образом, за исключением того, что вам придется иметь дело с идентификатором контакта, который является уникальным идентификатором, который автоматически присваивается магазином (вы не можете установить его; вы можете только прочитать его). Получив контакт, который вы хотите удалить, вы должны вызвать метод ContactStore
объекта ContactStore
, передав в качестве параметра идентификатор контакта, который хранится в свойстве Id
класса StoredContact
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private async void OnSearchContactClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
ContactQueryOptions options = new ContactQueryOptions();
options.DesiredFields.Add(KnownContactProperties.Email);
ContactQueryResult result = store.CreateContactQuery(options);
IReadOnlyList<StoredContact> contactList = await result.GetContactsAsync();
foreach (StoredContact contact in contactList)
{
IDictionary<string, object> properties = await contact.GetPropertiesAsync();
if (properties.ContainsKey(KnownContactProperties.Email) &&
properties[KnownContactProperties.Email].ToString() == «[email protected]»)
{
await store.DeleteContactAsync(contact.Id);
}
}
}
|
В предыдущем примере, после того как мы [email protected]
контакт с адресом электронной почты [email protected]
, мы удаляем его, используя его уникальный идентификатор.
Работа с удаленной синхронизацией
При работе с настраиваемыми источниками контактов мы обычно не просто управляем локальными контактами, а используем данные, которые синхронизируются с удаленной службой. В этом сценарии вы должны отслеживать удаленный идентификатор контакта, который будет отличаться от локального, поскольку, как упоминалось ранее, он генерируется автоматически и не может быть установлен.
Для этого сценария класс StoredContact
предлагает свойство RemoteId
для хранения такой информации. Наличие RemoteId
также упрощает операции поиска, которые мы видели ранее. ContactStore
класс ContactStore
предлагает метод FindContactByRemoteIdAsync()
, который может извлекать определенный контакт на основе удаленного идентификатора, как показано в следующем примере:
01
02
03
04
05
06
07
08
09
10
|
private async void OnFindButtonClicked(object sender, RoutedEventArgs e)
{
ContactStore store = await ContactStore.CreateOrOpenAsync(ContactStoreSystemAccessMode.ReadWrite, ContactStoreApplicationAccessMode.ReadOnly);
string myRemoteId = «2918»;
RemoteIdHelper remoteHelper = new RemoteIdHelper();
string taggedRemoteId = await remoteHelper.GetTaggedRemoteId(store, myRemoteId);
StoredContact contact = await store.FindContactByRemoteIdAsync(taggedRemoteId);
}
|
RemoteId
помнить одно важное требование: RemoteId
свойства RemoteId
должно быть уникальным для любого приложения, установленного на телефоне и использующего личную книгу контактов; в противном случае вы получите исключение.
В этой статье, опубликованной Microsoft, вы можете увидеть реализацию класса RemoteIdHelper
который предлагает несколько методов для добавления случайной информации к удаленному идентификатору (с использованием GUID), чтобы убедиться, что он уникален.
Воспользовавшись Детским уголком
Детский уголок — это интересная и инновационная функция, представленная в Windows Phone 8, которая особенно полезна для родителей маленьких детей. По сути, это песочница, которую мы можем настроить. Мы можем решить, какие приложения, игры, картинки, видео и музыка могут быть доступны.
Как разработчики, мы можем знать, когда приложение работает в режиме «Детский уголок». Таким образом, мы можем настроить взаимодействие с пользователем, чтобы избежать предоставления нежелательного контента, такого как обмен функциями.
Воспользоваться этой функцией легко; мы просто проверяем свойство Modes
класса ApplicationProfile
, который принадлежит пространству имен Windows.Phone.ApplicationModel
. Когда установлено значение « Default
, приложение работает нормально. Если он установлен на Alternate
, он работает в режиме детского угла.
01
02
03
04
05
06
07
08
09
10
11
|
private void OnCheckStatusClicked(object sender, RoutedEventArgs e)
{
if (ApplicationProfile.Modes == ApplicationProfileModes.Default)
{
MessageBox.Show(«The app is running in normal mode.»);
}
else
{
MessageBox.Show(«The app is running in Kid’s Corner mode.»);
}
}
|
API речи: поговорим с приложением
Речевые API являются одной из самых интересных новых функций, добавленных в Windows Phone 8. С точки зрения пользователя, голосовые функции управляются на странице настроек. Раздел «Речь» позволяет пользователям настраивать все основные параметры, такие как тип голоса, но, прежде всего, он используется для настройки языка, который они хотят использовать для речевых служб. Как правило, он установлен на том же языке пользовательского интерфейса, и пользователи могут изменить его, загрузив и установив новый голосовой пакет. Важно понимать, как настроены речевые сервисы, потому что в вашем приложении вы сможете использовать распознавание речи только для языков, которые были установлены пользователем.
Целью речевых сервисов является добавление поддержки распознавания голоса в ваши приложения следующими способами:
- Предоставьте пользователям возможность произносить команды для взаимодействия с приложением, например открывать его и выполнять задачу.
- Включите функции преобразования текста в речь, чтобы приложение могло читать текст пользователям.
- Включите распознавание текста, чтобы пользователи могли вводить текст, диктуя его, а не вводя его.
В этом разделе мы рассмотрим основные требования для реализации всех трех режимов в вашем приложении.
Голосовые команды
Голосовые команды — это способ запустить ваше приложение и выполнить определенную задачу независимо от того, что делает пользователь. Они активируются нажатием и удержанием кнопки «Пуск». Windows Phone предлагает встроенную поддержку многих голосовых команд, таких как запуск телефонного звонка, диктовка электронной почты, поиск через Bing и многое другое.
Пользователь просто должен произнести команду; если оно успешно распознано, приложение будет открыто, и, как разработчики, мы получим некоторую информацию, чтобы понять, какая команда была введена, чтобы мы могли перенаправить пользователя на соответствующую страницу или выполнить определенную операцию.
Голосовые команды основаны на файлах VCD, которые являются файлами XML, которые включены в ваш проект. Используя специальный синтаксис, вы сможете определить все команды, которые вы хотите поддерживать в своем приложении, и то, как приложение должно вести себя, когда они используются. Эти файлы изначально поддерживаются Visual Studio. Если вы щелкнете правой кнопкой мыши по своему проекту и выберете Добавить новый элемент , вы найдете шаблон под названием VoiceCommandDefinition
в разделе Windows Phone.
Следующий пример кода представляет собой файл VCD:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<?xml version=»1.0″ encoding=»utf-8″?>
<VoiceCommands xmlns=»http://schemas.microsoft.com/voicecommands/1.0″>
<CommandSet xml:lang=»it» Name=»NotesCommandSet»>
<CommandPrefix>My notes</CommandPrefix>
<Example> Open my notes and add a new note </Example>
<Command Name=»AddNote»>
<Example> add a new note </Example>
<ListenFor> [and] add [a] new note </ListenFor>
<ListenFor> [and] create [a] new note </ListenFor>
<Feedback> I’m adding a new note… </Feedback>
<Navigate Target=»/AddNote.xaml» />
</Command>
</CommandSet>
</VoiceCommands>
|
Файл VCD может содержать один или несколько узлов CommandSet
, которые идентифицируются по Name
и определенному языку (атрибут xml:lang
). Второй атрибут является наиболее важным. Ваше приложение будет поддерживать голосовые команды только для языков, которые вы включили в CommandSet
в файле VCD (язык голосовых команд определяется пользователями на странице настроек). Вы можете иметь несколько узлов CommandSet
для поддержки нескольких языков.
Каждый CommandSet
может иметь CommandPrefix
— текст, который должен произносить пользователь, чтобы начать отправку команд нашему приложению. Если он не указан, будет автоматически использовано имя приложения. Это свойство полезно, если вы хотите локализовать команду или если заголовок вашего приложения слишком сложен для произнесения. Вы также можете добавить тег « Example
, который содержит текст, отображаемый в диалоговом окне Windows Phone, чтобы помочь пользователям понять, какие команды они могут использовать.
Затем внутри CommandSet
вы можете добавить до 100 команд, идентифицированных тегом Command
. Каждая команда имеет следующие характеристики:
- Уникальное имя, которое задается в атрибуте
Name
. - Тег
Example
показывает пользователям образец текста для текущей команды. -
ListenFor
содержит текст, который необходимо произнести, чтобы активировать команду. ДляListenFor
можно указать до десяти теговListenFor
чтобы охватить варианты текста. Вы также можете добавить дополнительные слова в квадратных скобках. В предыдущем примере командуAddNote
можно активировать, произнеся «добавить новую заметку» или «и добавить новую заметку». -
Feedback
— это текст, который произносит Windows Phone, чтобы уведомить пользователей, что он понял команду и обрабатывает ее. -
NavigateTarget
можно использовать для настройки потока навигации приложения. Если мы не установим его, по умолчанию приложение откроется на главной странице. В противном случае, как и в предыдущем примере, мы можем перенаправить пользователя на определенную страницу. Конечно, в обоих случаях мы получим информацию о голосовой команде; мы увидим, как бороться с ними позже.
После того, как мы завершили определение VCD, мы готовы использовать его в нашем приложении.
Примечание. Чтобы использовать речевые службы, вам нужно включить опцию ID_CAP_SPEECH_RECOGNITION
в файле манифеста.
Команды внедряются в приложение Windows Phone с помощью класса VoiceCommandService
, который принадлежит пространству имен Windows.Phone.Speech.VoiceCommands
. Этот статический класс предоставляет метод InstallCommandSetFromFileAsync()
, который требует путь к только что созданному VCD-файлу.
1
2
3
4
|
private async void OnInitVoiceClicked(object sender, RoutedEventArgs e)
{
await VoiceCommandService.InstallCommandSetsFromFileAsync(new Uri(«ms-appx:///VoiceCommands.xml»));
}
|
Путь к файлу выражается с помощью Uri
который должен начинаться с префикса ms-appx:///
. Этот Uri
относится к структуре проекта Visual Studio, начиная с корня.
Списки фраз
Файл VCD также может содержать список фраз, как в следующем примере:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?xml version=»1.0″ encoding=»utf-8″?>
<VoiceCommands xmlns=»http://schemas.microsoft.com/voicecommands/1.0″>
<CommandSet xml:lang=»en» Name=»NotesCommandSet»>
<CommandPrefix>My notes</CommandPrefix>
<Example> Open my notes and add a new note </Example>
<Command Name=»OpenNote»>
<Example> open the note </Example>
<ListenFor> open the note {number} </ListenFor>
<Feedback> I’m opening the note… </Feedback>
<Navigate />
</Command>
<PhraseList Label=»number»>
<Item> 1 </Item>
<Item> 2 </Item>
<Item> 3 </Item>
</PhraseList>
</CommandSet>
</VoiceCommands>
|
Списки фраз используются для управления параметрами, которые могут быть добавлены к фразе с помощью фигурных скобок. Каждый узел PhraseList
идентифицируется атрибутом Label
, который является ключевым словом для включения в фигурные скобки внутри узла ListenFor
. В предыдущем примере пользователи могут произносить фразу «открыть заметку», за которой следует любое из чисел, указанных с помощью тега Item
в PhraseList
. Вы можете иметь до 2000 элементов в одном списке.
Предыдущий пример полезен для понимания того, как работает эта функция, но он не очень реалистичен; часто список параметров не является статичным, но динамически обновляется во время выполнения приложения. Возьмем предыдущий сценарий в качестве примера: в приложении заметок список заметок не является фиксированным, поскольку пользователи могут создавать неограниченное количество заметок.
API предлагают способ динамически обновлять PhraseList
, как показано в следующем примере:
1
2
3
4
5
|
private async void OnUpdatePhraseListClicked(object sender, RoutedEventArgs e)
{
VoiceCommandSet commandSet = VoiceCommandService.InstalledCommandSets[«NotesCommandSet»];
await commandSet.UpdatePhraseListAsync(«number», new string[] { «1», «2», «3», «4», «5» });
}
|
Сначала вы должны получить ссылку на текущий набор команд с помощью коллекции VoiceCommandService.InstalledCommandSets
. В качестве индекса вы должны использовать имя набора, который вы определили в файле VCD (атрибут Name
тега CommandSet
). Получив ссылку на набор, вы можете вызвать UpdatePhraseListAsync()
чтобы обновить список, передав два параметра:
- имя
PhraseList
(задается с помощью атрибутаLabel
) - коллекция новинок, как массив строк
Важно помнить, что метод UpdatePhraseListAsync()
переопределяет текущие элементы в PhraseList
, поэтому вам придется каждый раз добавлять все доступные элементы, а не только новые.
Перехват запрашиваемой команды
Команда, вызванная пользователем, отправляется в ваше приложение с механизмом строки запроса, описанным ранее в этой серии . Когда приложение открывается командой, пользователь перенаправляется на страницу, указанную в узле Navigate
файла VCD. Ниже приведен пример URI:
1
|
/MainPage.xaml?voiceCommandName=AddNote&reco=My%20notes%20create%20a%20new%20note
|
Параметр voiceCommandName
содержит voiceCommandName
команду, а параметр reco
содержит полный текст, который был распознан Windows Phone.
Если команда поддерживает список фраз, вы получите другой параметр с тем же именем PhraseList
и произносимым элементом в качестве значения.Следующий код представляет собой пример URI на основе предыдущего примера заметки, где пользователь может открыть конкретную заметку с помощью OpenNote
команды:
1
|
/MainPage.xaml?voiceCommandName=OpenNote&reco=My%20notes%20open%20a%20new%20note&number=2 |
Используя API, которые мы видели ранее в этой серии, легко извлечь необходимую информацию из параметров строки запроса и использовать их для наших целей, как в следующем примере:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
protected override void OnNavigatedTo(NavigationEventArgs e) {
if (NavigationContext.QueryString.ContainsKey( "voiceCommandName" )) {
string commandName = NavigationContext.QueryString[ "voiceCommandName" ]; switch (commandName) {
case "AddNote" : //Create a new note. break;
case "OpenNote" : if (NavigationContext.QueryString.ContainsKey( "number" )) {
int selectedNote = int .Parse(NavigationContext.QueryString[ "number" ]); //Load the selected note. }
break;
}
}
}
|
Мы используем switch
оператор для управления различными поддерживаемыми командами, которые доступны в NavigationContext.QueryString
коллекции. Если пользователь пытается открыть заметку, мы также получаем значение number
параметра.
Работа с распознаванием речи
В начале этого раздела мы говорили о том, как распознавать команды, которые произносит пользователь, чтобы открыть приложение. Теперь пришло время узнать, как сделать то же самое в самом приложении, распознавать команды и разрешать пользователям диктовать текст, а не вводить его (полезная функция для обеспечения громкой связи).
Есть два способа начать распознавание речи: предоставить пользовательский интерфейс или работать в фоновом режиме.
В первом случае вы можете предоставить пользователям визуальный диалог, аналогичный тому, который используется операционной системой при удерживании кнопки «Пуск». Это идеальное решение для управления голосовыми командами, потому что вы сможете предоставлять пользователям визуальную и голосовую обратную связь.
Это достигается с помощью SpeechRecognizerUI
класса, который предлагает четыре ключевых свойства для настройки визуального диалога:
-
ListenText
это большой, жирный текст, который объясняет пользователям, что ожидает приложение. -
Example
Это дополнительный текст, который отображается ниже,ListenText
чтобы помочь пользователям лучше понять, какую речь ожидает приложение. -
ReadoutEnabled
являетсяBoolean
собственностью; если установлено значение true, Windows Phone будет читать распознанный текст пользователям в качестве подтверждения. -
ShowConfirmation
другаяBoolean
собственность; если для этого параметра установлено значение true, пользователи смогут отменить операцию после завершения процесса распознавания.
В следующем примере показано, как эта функция используется, чтобы позволить пользователям диктовать заметку. Мы просим пользователей ввести текст заметки, а затем, если операция прошла успешно, мы отображаем распознанный текст.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
private async void OnStartRecordingClicked( object sender, RoutedEventArgs e) {
SpeechRecognizerUI sr = new SpeechRecognizerUI(); sr.Settings.ListenText = "Start dictating the note" ; sr.Settings.ExampleText = "dictate the note" ; sr.Settings.ReadoutEnabled = false ; sr.Settings.ShowConfirmation = true ; SpeechRecognitionUIResult result = await sr.RecognizeWithUIAsync(); if (result.ResultStatus == SpeechRecognitionUIStatus.Succeeded) {
RecordedText.Text = result.RecognitionResult.Text; }
}
|
Обратите внимание, как начинается процесс распознавания, вызывая RecognizeWithUIAsync()
метод, который возвращает SpeechRecognitionUIResult
объект, который содержит всю информацию об операции.
Для автоматического распознавания текста требуется меньше кода, поскольку доступно меньше параметров, чем было использовано для диалога. Нам просто нужно начать слушать текст и понять его. Мы можем сделать это, вызвав RecognizeAsync()
метод SpeechRecognizer
класса. Результат распознавания будет сохранен в SpeechRecognitionResult
объекте, который является тем же, который был возвращен в RecognitionResult
свойстве RecognizeWithUIAsync()
методом, который мы использовали ранее.
Использование пользовательских грамматик
Код, который мы видели до сих пор, используется для распознавания практически любого слова в словаре. По этой причине речевые службы будут работать только в том случае, если телефон подключен к Интернету, поскольку эта функция использует онлайновые службы Microsoft для анализа результатов.
Этот подход полезен, когда пользователи говорят с приложением, чтобы диктовать текст, как в предыдущих примерах с приложением заметки. Но если нужно управлять только несколькими командами, доступ ко всем словам в словаре не требуется. Напротив, полный доступ может вызвать проблемы, потому что приложение может понимать слова, которые не связаны ни с одной из поддерживаемых команд.
Для этого сценария API речи предоставляют возможность использовать пользовательскую грамматику и ограничивают количество слов, которые поддерживаются в процессе распознавания. Есть три способа установить пользовательскую грамматику:
- используя только доступные стандартные наборы
- добавление списка поддерживаемых слов вручную
- хранение слов во внешнем файле
Опять же, отправной точкой является SpeechRecognizer
класс, который предлагает свойство с именем Grammars
.
Чтобы загрузить одну из предопределенных грамматик, используйте AddGrammarFromPredefinedType()
метод, который принимает в качестве параметров строку для ее идентификации (вы можете выбрать любое значение) и тип используемой грамматики. Существует два набора грамматик: стандартная SpeechPredefinedGrammar.Dictation
и SpeechPredefinedGrammar.WebSearch
оптимизированная для веб-задач.
В следующем примере мы распознаем речь с помощью WebSearch
грамматики:
1
2
3
4
5
6
7
|
private async void OnStartRecordingWithoutUIClicked( object sender, RoutedEventArgs e) {
SpeechRecognizer recognizer = new SpeechRecognizer(); recognizer.Grammars.AddGrammarFromPredefinedType( "WebSearch" , SpeechPredefinedGrammar.WebSearch); SpeechRecognitionResult result = await recognizer.RecognizeAsync(); RecordedText.Text = result.Text; }
|
Еще более полезной является возможность позволить процессу распознавания понимать только несколько выбранных слов. Мы можем использовать AddGrammarFromList()
метод, предлагаемый Grammars
свойством, который требует обычного идентификационного ключа, за которым следует набор поддерживаемых слов.
В следующем примере мы установили для SpeechRecognizer
класса понимание только слов «сохранить» и «отменить».
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
private async void OnStartRecordingClicked( object sender, RoutedEventArgs e) {
SpeechRecognizer recognizer = new SpeechRecognizer(); string [] commands = new [] { "save" , "cancel" }; recognizer.Grammars.AddGrammarFromList( "customCommands" , commands); SpeechRecognitionResult result = await recognizer.RecognizeAsync(); if (result.Text == "save" ) {
//Saving }
else if (result.Text == "cancel" ) {
//Cancelling the operation }
else
{
MessageBox.Show( "Command not recognized" ); }
}
|
Если пользователь произносит слово, которое не включено в пользовательскую грамматику, Text
свойство SpeechRecognitionResult
объекта будет пустым. Самым большим преимуществом этого подхода является то, что он не требует подключения к Интернету, поскольку грамматика хранится локально.
Третий и последний способ загрузки грамматики — использование другого определения XML Speech Recognition Grammar Specification (SRGS)
. Вы можете прочитать больше о поддерживаемых тегах в официальной документации W3C.
В следующем примере показан файл пользовательской грамматики:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<? xml version = "1.0" encoding = "utf-8" ?> < grammar version = "1.0" xml:lang = "en" root = "rootRule" tag-format = "semantics/1.0" < rule id = "openAction" > < one-of > < item >open</ item > < item >load</ item > </ one-of > </rule>
< rule id = "fileWords" > < one-of > < item > note </ item > < item > reminder </ item > </ one-of > </rule>
< rule id = "rootRule" > < ruleref uri = "#openAction" /> < one-of > < item >the</ item > < item >a</ item > </ one-of > < ruleref uri = "#fileWords" /> </rule>
</ grammar > |
Файл описывает как поддерживаемые слова, так и правильный порядок, который следует использовать. В предыдущем примере показаны поддерживаемые команды для управления заметками в приложении, например «Открыть заметку» или «Загрузить напоминание», в то время как такая команда, как «Напоминание открыть», не распознается.
Visual Studio 2012 предлагает встроенную поддержку для этих файлов с определенным шаблоном, SRGS Grammar
который доступен, когда вы щелкаете правой кнопкой мыши по своему проекту и выбираете Добавить новый элемент .
Как только файл станет частью вашего проекта, вы можете загрузить его, используя AddGrammarFromUri()
метод SpeechRecognizer
класса, который принимает в качестве параметра путь к файлу, выраженный как Uri
, точно так же, как мы видели для файлов VCD. Отныне процесс распознавания будет использовать грамматику, определенную в файле, вместо стандартной, как показано в следующем примере:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
private async void OnStartRecordingWithCustomFile( object sender, RoutedEventArgs e) {
SpeechRecognizer recognizer = new SpeechRecognizer(); SpeechRecognitionResult result = await recognizer.RecognizeAsync(); if (result.Text != string .Empty) {
RecordedText.Text = result.Text; }
else
{
MessageBox.Show( "Not recognized" ); }
}
|
Использование преобразования текста в речь (TTS)
Преобразование текста в речь — это технология, которая способна читать текст пользователям синтезированным голосом. Его можно использовать для создания диалога с пользователями, чтобы им не приходилось смотреть на экран для взаимодействия с приложением.
Основное использование этой функции действительно просто. Базовый класс для взаимодействия со службами TTS — SpeechSynthesizer
это метод, который называется SpeakTextAsync()
. Вам просто нужно передать методу текст, который вы хотите прочитать, как показано в следующем примере:
1
2
3
4
5
|
private async void OnSpeakClicked( object sender, RoutedEventArgs e) {
SpeechSynthesizer synth = new SpeechSynthesizer(); await synth.SpeakTextAsync( "This is a sample text" ); }
|
Кроме того, можно настроить способ произношения текста с помощью стандартного языка под названием Synthesis Markup Language (SSML) , который основан на стандарте XML. Этот стандарт предоставляет серию тегов XML, которые определяют, как слово или часть текста должны произноситься. Например, можно изменить скорость, язык, пол голоса и многое другое.
В следующем примере приведен пример файла SSML:
01
02
03
04
05
06
07
08
09
10
11
|
<?xml version=»1.0″?>
xmlns:dc=»http://purl.org/dc/elements/1.1/»
xml:lang="en" version="1.0"> < voice age = "5" >This text is read by a child</ voice > < break /> < prosody rate = "x-slow" > This text is read very slowly</ prosody > </ speak > |
Этот код содержит три примера тегов SSML: voice
для имитации возраста голоса, break
для добавления паузы и prosody
для установки скорости чтения с помощью rate
атрибута.
Есть два способа использовать определение SSML в вашем приложении. Первый — создать внешний файл, добавив новый XML-файл в ваш проект. Затем вы можете загрузить его, передав путь к файлу SpeakSsmlFromUriAsync()
методу SpeechSynthesizer
класса, аналогично тому, как мы загружали файл VCD.
1
2
3
4
5
|
private async void OnSpeakClicked( object sender, RoutedEventArgs e) {
SpeechSynthesizer synth = new SpeechSynthesizer(); }
|
Другой способ — определить текст, который будет читаться непосредственно в коде, создав строку, содержащую теги SSML. В этом случае мы можем использовать SpeakSsmlAsync()
метод, который принимает строку для чтения в качестве параметра. В следующем примере показано то же определение SSML, которое мы использовали, но оно хранится в строке вместо внешнего файла.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
private async void OnSpeakClicked( object sender, RoutedEventArgs e) {
SpeechSynthesizer synth = new SpeechSynthesizer(); StringBuilder textToRead = new StringBuilder(); textToRead.AppendLine( "<speak version=\"1.0\"" ); textToRead.AppendLine( " xml:lang=\"en\">" ); textToRead.AppendLine( " <voice age=\"5\">This text is read by a child</voice>" ); textToRead.AppendLine( "<prosody rate=\"x-slow\"> This text is read very slowly</prosody>" ); textToRead.AppendLine( "</speak>" ); await synth.SpeakSsmlAsync(textToRead.ToString()); }
|
Вы можете узнать больше об определении SSML и доступных тегах в официальной документации, предоставленной W3C.
Обмен данными
Совместное использование данных — это новая функция, представленная в Windows Phone 8, которая может использоваться для обмена данными между различными приложениями, в том числе сторонними.
Существует два способа управления совместным использованием данных:
- Общий доступ к файлам : приложение регистрирует расширение, такое как
.log
. Он сможет управлять любым файлом с зарегистрированным расширением, открытым другим приложением (например, почтовым вложением). - Совместное использование протокола : приложение регистрирует протокол, такой как
log:
. Другие приложения смогут использовать его для отправки простых данных, таких как строки или числа.
В обоих случаях пользовательский опыт похож:
- Если на устройстве нет приложения для управления запрошенным расширением или протоколом, пользователям будет задан вопрос, хотят ли они найти в Магазине то, которое может.
- Если для запрошенного расширения или протокола зарегистрировано только одно приложение, оно будет автоматически открыто.
- Если для одного расширения или протокола зарегистрировано несколько приложений, пользователи смогут выбрать, какое из них использовать.
Давайте обсудим, как поддержать оба сценария в нашем приложении.
Примечание. Существует несколько типов файлов и протоколов, которые регистрируются системой, например файлы Office, изображения, почтовые протоколы и т. Д. Вы не можете их переопределить; только Windows Phone может управлять ими. Вы можете увидеть полный список зарезервированных типов в документации MSDN .
Обмен файлами
Совместное использование файлов поддерживается добавлением нового определения в файл манифеста, который уведомляет операционную систему о том, какими расширениями может управлять приложение. Как и во многих других сценариях, которые мы видели ранее, эта модификация не поддерживается визуальным редактором, поэтому нам нужно щелкнуть правой кнопкой мыши файл манифеста и выбрать параметр « Просмотреть код» .
Расширение добавлено в Extensions
раздел, который должен быть определен под Token
одним:
01
02
03
04
05
06
07
08
09
10
11
12
|
< Extensions > < FileTypeAssociation Name = "LogFile" TaskID = "_default" NavUriFragment = "fileToken=%s" > < Logos > < Logo Size = "small" >log-33x33.png</ Logo > < Logo Size = "medium" >log-69x69.png</ Logo > < Logo Size = "large" >log-176x176.png</ Logo > </ Logos > < SupportedFileTypes > < FileType ContentType = "text/plain" >.log</ FileType > </ SupportedFileTypes > </ FileTypeAssociation > </ Extensions > |
Каждый поддерживаемый тип файла имеет свой собственный FileTypeAssociation
тег, который идентифицируется Name
атрибутом (который должен быть уникальным). Внутри этого узла находятся два вложенных раздела:
-
Logos
не является обязательным и используется для поддержки значка для визуальной идентификации типа файла. Требуются три разных изображения, каждое с разным разрешением: 33 × 33, 69 × 69 и 176 × 176. Значки используются в различных контекстах, например, когда файл принимается в качестве вложения электронной почты. -
SupportedFileTypes
требуется, потому что он содержит расширения, которые будут поддерживаться для текущего типа файла. Можно добавить несколько расширений.
Предыдущий пример используется для управления .log
расширением файла в нашем приложении.
Когда другое приложение пытается открыть файл, который мы поддерживаем, наше приложение открывается с помощью специального URI:
1
|
/FileTypeAssociation ?fileToken=89819279-4fe0-9f57-d633f0949a19 |
fileToken
Параметр представляет собой GUID , который однозначно идентифицирует файл-мы будем использовать его позже.
Чтобы управлять входящим URI, нам нужно представить UriMapper
класс, о котором мы говорили ранее в этой серии . Когда мы идентифицируем этот специальный URI, мы собираемся перенаправить пользователя на определенную страницу приложения, которая может взаимодействовать с файлом.
Следующий пример показывает, как UriMapper
выглядит:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class UriMapper: UriMapperBase {
public override Uri MapUri(Uri uri) {
string tempUri = HttpUtility.UrlDecode(uri.ToString()); if (tempUri.Contains( "/FileTypeAssociation" )) {
int fileIdIndex = tempUri.IndexOf( "fileToken=" ) + 10; string fileId = tempUri.Substring(fileIdIndex); string incomingFileName = SharedStorageAccessManager.GetSharedFileName(fileId); string incomingFileType = System.IO.Path.GetExtension(incomingFileName); switch (incomingFileType) {
case ".log" : return new Uri( "/LogPage.xaml?fileToken=" + fileId, UriKind.Relative); default:
return new Uri( "/MainPage.xaml" , UriKind.Relative); }
}
return uri; }
}
|
Если в начале Uri
содержится FileTypeAssociation
ключевое слово, это означает, что приложение было открыто из-за запроса на обмен файлами. В этом случае нам нужно определить расширение открытого файла. Мы извлечь fileToken
параметр и, используя GetSharedFileName()
в SharedAccessManager
классе (который принадлежит к Windows.Phone.Storage
пространству имен), мы получаем исходное имя файла.
Читая имя, мы можем определить расширение и выполнить соответствующее перенаправление. В предыдущем примере, если расширение есть .log
, мы перенаправляем пользователя на определенную страницу приложения LogPage.xaml
. Очень важно , чтобы добавить к Uri
в fileToken
параметре в виде строки запроса; мы собираемся использовать его на странице для эффективного извлечения файла. Не забудьте зарегистрировать UriMapper
в App.xaml.cs
файле, как описано ранее в этой серии.
Совет. Предыдущий UriMapper
пример показывает полный пример, который работает, когда приложение поддерживает несколько типов файлов. Если ваше приложение поддерживает только одно расширение, вам не нужно извлекать имя файла и определять тип файла. Поскольку приложение можно открыть с помощью специального URI только в сценарии совместного использования файлов, вы можете сразу же перенаправить пользователя на выделенную страницу.
Теперь пришло время взаимодействовать с файлом, который мы получили из другого приложения. Мы сделаем это на странице, которую мы создали для этой цели (в предыдущем примере кода она называется LogPage.xaml
).
Мы видели, что когда другое приложение пытается открыть .log
файл, пользователь перенаправляется на LogPage.xaml
страницу с fileToken
параметром, добавленным в строку запроса. Мы собираемся использовать OnNavigatedTo
событие для управления этим сценарием:
01
02
03
04
05
06
07
08
09
10
|
protected override async void OnNavigatedTo(NavigationEventArgs e) {
if (NavigationContext.QueryString.ContainsKey(“fileToken”)) {
await SharedStorageAccessManager.CopySharedFileAsync(ApplicationData.Current.LocalFolder, “file.log”, NameCollisionOption.ReplaceExisting, NavigationContext.QueryString[“fileToken”]); }
}
|
Мы снова используем SharedStorageAccessManager
класс, на этот раз вызывая CopySharedFileAsync()
метод. Его цель — скопировать полученный файл в локальное хранилище, чтобы мы могли с ним работать.
Обязательные параметры:
StorageFolder
Объект, который представляет собой локальную папку хранения , в котором необходимо сохранить файл (в предыдущем примере, мы сохраняем его в корне).- Название файла.
- Поведение, применяемое в случае, если файл с таким именем уже существует (с использованием одного из значений
NameCollisionOption
перечислителя). - GUID, который идентифицирует файл, который мы получаем из
fileToken
параметра строки запроса.
После завершения операции новый файл с именем file.log
будет доступен в локальном хранилище приложения, и мы можем начать с ним играть. Например, мы можем отобразить его содержимое на текущей странице.
Как открыть файл
До сих пор мы видели, как управлять открытым файлом в нашем приложении, но нам еще предстоит обсудить, как эффективно открыть файл.
Задача легко решается с помощью LaunchFileAsync()
метода, предлагаемого Launcher
классом (который принадлежит Windows.System
пространству имен). В StorageFile
качестве параметра требуется объект, представляющий файл, который вы хотите открыть.
В следующем примере вы можете увидеть, как открыть файл журнала, включенный в проект Visual Studio:
1
2
3
4
5
|
private async void OnOpenFileClicked(object sender, RoutedEventArgs e) {
StorageFile storageFile = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(“file.log”); Windows.System.Launcher.LaunchFileAsync(storageFile); }
|
Протокол обмена
Совместное использование протокола работает аналогично совместному использованию файлов. Мы собираемся зарегистрировать новое расширение в файле манифеста, и мы будем иметь дело со специальным URI, который используется для запуска приложения.
Начнем с манифеста.Также и в этом случае нам придется добавить новый элемент в Extensions
раздел, к которому можно получить доступ, отредактировав файл вручную с помощью этой View code
опции.
1
2
3
|
<Extensions> <Protocol Name=“log” NavUriFragment=“encodedLaunchUri=%s” TaskID=“_default” /> </Extensions> |
Самый важный атрибут Name
, который определяет протокол, который мы собираемся поддерживать. Два других атрибута исправлены.
Приложение, которое поддерживает совместное использование протокола, открывается со следующим URI:
1
|
/Protocol?encodedLaunchUri=log:ShowLog?LogId=1 |
Лучший способ управлять им — это использовать UriMapper
класс, как мы делали для обмена файлами. Разница в том, что на этот раз мы будем искать encodedLaunchUri
параметр. Однако результат будет таким же: мы перенаправим пользователя на страницу, которая может управлять входящей информацией.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class UriMapper : UriMapperBase {
public override Uri MapUri(Uri uri) {
string tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString()); if (tempUri.Contains(“Protocol”)) {
int logIdIndex = tempUri.IndexOf(“LogId=“) + 6; string logId = tempUri.Substring(logIdIndex); return new Uri(“/LogPage.xaml?LogId=“ + logId, UriKind.Relative); }
return uri; }
}
|
В этом случае операция проще. Мы извлекаем значение параметра LogId
и передаем его на LogPage.xaml
страницу. Кроме того, у нас меньше работы на целевой странице; нам просто нужно извлечь значение параметра, используя OnNavigatedTo
событие, и использовать его для загрузки необходимых данных, как показано в следующем примере:
1
2
3
4
5
6
7
8
|
protected override void OnNavigatedTo(NavigationEventArgs e) {
if (NavigationContext.QueryString.ContainsKey(“LogId”)) {
string logId = NavigationContext.QueryString[“LogId”]; MessageBox.Show(logId); }
}
|
Как открыть URI
Подобно обмену файлами, другие приложения могут взаимодействовать с нашими, используя функцию общего доступа к протоколу и Launcher
класс, принадлежащий Windows.System
пространству имен.
Разница в том, что нам нужно использовать LaunchUriAsync()
метод, как показано в следующем примере:
1
2
3
4
5
|
private async void OnOpenUriClicked(object sender, RoutedEventArgs e) {
Uri uri = new Uri(“log:ShowLog?LogId=1”); await Windows.System.Launcher.LaunchUriAsync(uri); }
|
Вывод
В этом руководстве мы рассмотрели различные способы интеграции нашего приложения с функциями, предлагаемыми платформой Windows Phone:
- Мы начали с простейшей интеграции: средства запуска и выбора, которые используются для запроса операции от операционной системы и, в конечном итоге, для получения некоторых данных.
- Мы рассмотрели, как взаимодействовать с контактами и встречами пользователей: сначала в режиме «только чтение», предлагаемом новым набором API-интерфейсов, представленным в Windows Phone 7.5, а затем в личной книге контактов, которая является хранилищем контактов, принадлежащим приложению. но можно интегрировать с родным People Hub.
- Мы вкратце поговорили о том, как воспользоваться преимуществами Kid’s Corner — инновационной функции, которая позволяет детям безопасно пользоваться телефоном без доступа к приложениям, которые им не подходят.
- Мы узнали, как использовать один из самых мощных новых API, добавленных в Windows Phone 8: Speech API, для взаимодействия с нашим приложением с помощью голосовых команд.
- Мы ввели обмен данными, который является еще одной новой функцией, используемой для обмена данными между различными приложениями, и мы можем управлять расширениями файлов и протоколами.
Это руководство представляет собой главу из Windows Phone 8 Succinctly , бесплатной электронной книги от команды Syncfusion.