Передача в Xamarin.iOS
В этой статье рассматривается работа с handoff в приложении Xamarin.iOS для передачи действий пользователей между приложениями, работающими на других устройствах пользователя.
Apple представила Handoff в iOS 8 и OS X Yosemite (10.10), чтобы обеспечить общий механизм передачи действий, запущенных на одном из своих устройств, на другое устройство под управлением того же приложения или другого приложения, которое поддерживает то же действие.
В этой статье вы узнаете, как включить общий доступ к действиям в приложении Xamarin.iOS и подробно охватить платформу Handoff:
Передача (также известная как Непрерывность) была представлена Apple в iOS 8 и OS X Yosemite (10.10) в качестве способа запуска действия на одном из своих устройств (iOS или Mac) и продолжайте то же действие на других своих устройствах (как определено учетной записью iCloud пользователя).
Раздатка была расширена в iOS 9, чтобы также поддерживать новые расширенные возможности поиска. Дополнительные сведения см. в нашей документации по улучшению поиска.
Например, пользователь может запустить сообщение электронной почты в i Телефон и без проблем продолжить электронную почту на компьютере Mac с одинаковыми сведениями о сообщении, заполненными и курсором в том же расположении, что они оставили его в iOS.
Любой из приложений, которым предоставляется один и тот же идентификатор команды, имеет право использовать handoff для продолжения действий пользователей в приложениях, если эти приложения доставляются через iTunes App Store или подписаны зарегистрированным разработчиком (для Mac, Enterprise или Ad Hoc).
Все NSDocument
приложения или UIDocument
приложения на основе автоматически поддерживают поддержку Handoff и требуют минимальных изменений для поддержки Handoff.
Класс NSUserActivity
(а также некоторые небольшие изменения UIKit
и AppKit
) обеспечивает поддержку определения действия пользователя, которое может быть продолжено на других устройствах пользователя.
Чтобы действие было передано другому устройству пользователя, оно должно быть инкапсулировано в экземпляре NSUserActivity
, помеченном как текущее действие, имеет набор полезных данных (данные, используемые для продолжения), а затем действие должно быть передано на это устройство.
Передача передает минимальный объем информации, чтобы определить действие, которое необходимо продолжить, с более крупными пакетами данных, синхронизируемых через iCloud.
На принимающем устройстве пользователь получит уведомление о том, что действие доступно для продолжения. Если пользователь решит продолжить действие на новом устройстве, то указанное приложение запускается (если оно еще не запущено) и полезные данные из нее NSUserActivity
используются для перезапуска действия.
Только приложения, использующие один и тот же идентификатор команды разработчика и отвечающие на заданный тип действия, могут продолжаться. Приложение определяет типы действий, поддерживаемые NSUserActivityTypes
в ключе файла Info.plist . Учитывая это, продолжающееся устройство выбирает приложение для выполнения продолжения на основе идентификатора команды, типа действия и при необходимости заголовка действия.
Принимающее приложение использует сведения из NSUserActivity
UserInfo
словаря, чтобы настроить пользовательский интерфейс и восстановить состояние заданного действия, чтобы переход отображалось просто для конечного пользователя.
Если продолжение требует больше информации, чем можно эффективно отправлять с помощью NSUserActivity
приложения, возобновление приложения может отправить вызов исходному приложению и установить один или несколько потоков для передачи необходимых данных. Например, если действие редактировало большой текстовый документ с несколькими изображениями, потоковая передача потребуется для передачи информации, необходимой для продолжения действия на принимающем устройстве. Дополнительные сведения см. в разделе "Поддержка продолжения" Потоки ниже.
Как указано выше, NSDocument
или UIDocument
приложения на основе автоматически поддерживают поддержку Handoff. Дополнительные сведения см. в разделе "Вспомогательные передачи" в приложениях на основе документов ниже.
Класс NSUserActivity
является основным объектом в обмене Handoff и используется для инкапсулации состояния действия пользователя, доступного для продолжения. Приложение создаст копию NSUserActivity
любого действия, которое он поддерживает и хочет продолжить на другом устройстве. Например, редактор документов создаст действие для каждого открытого документа. Однако только самый передний документ (отображаемый в самом переднем окне или вкладке) является текущим действием и доступен для продолжения.
Экземпляр NSUserActivity
определяется как его ActivityType
, так и Title
свойствами. Свойство UserInfo
словаря используется для передачи сведений о состоянии действия. NeedsSave
Задайте для свойства значениеtrue
, если требуется отложенная загрузка сведений о состоянии с помощью NSUserActivity
делегата. AddUserInfoEntries
Используйте метод для объединения новых данных из других клиентов в UserInfo
словарь, как это необходимо для сохранения состояния действия.
Используется NSUserActivityDelegate
для хранения сведений в NSUserActivity
UserInfo
словаре и синхронизации с текущим состоянием действия. Если системе требуется обновить сведения в действии (например, перед продолжением на другом устройстве), он вызывает UserActivityWillSave
метод делегата.
Необходимо реализовать UserActivityWillSave
метод и внести изменения NSUserActivity
в (напримерUserInfo
Title
, и т. д.), чтобы убедиться, что он по-прежнему отражает состояние текущего действия. Когда система вызывает UserActivityWillSave
метод, NeedsSave
флаг будет снят. Если изменить какие-либо свойства данных действия, вам потребуется снова задать NeedsSave
значение true
.
Вместо использования метода, представленного UserActivityWillSave
выше, вы можете автоматически иметь UIKit
или AppKit
управлять действием пользователя. Для этого задайте свойство объекта UserActivity
ответа и реализуйте UpdateUserActivityState
метод. Дополнительные сведения см. в разделе "Вспомогательный раздатчик" в ответах ниже.
Как UIKit
(iOS), так и AppKit
(OS X) обеспечивают встроенную поддержку Handoff в NSDocument
, ответчике (NSResponder
UIResponder
/) и AppDelegate
классах. Хотя каждая ОС реализует handoff немного по-разному, базовый механизм и ИНТЕРФЕЙСы API одинаковы.
Приложения iOS и OS X на основе документов автоматически поддерживают функцию Handoff. Чтобы активировать эту поддержку, необходимо добавить NSUbiquitousDocumentUserActivityType
ключ и значение для каждой CFBundleDocumentTypes
записи в файле Info.plist приложения.
Если этот ключ присутствует, оба NSDocument
и UIDocument
автоматически создают NSUserActivity
экземпляры для документов на основе iCloud указанного типа. Необходимо предоставить тип действия для каждого типа документа, который поддерживает приложение, и несколько типов документов могут использовать один и тот же тип действия. UIDocument
Оба NSDocument
и автоматически заполняют UserInfo
свойство NSUserActivity
значения их FileURL
свойства.
В ОС X NSUserActivity
управляемый AppKit
и связанный с ответчиками автоматически становится текущим действием, когда окно документа становится главным окном. В iOS для NSUserActivity
объектов, управляемых с помощью UIKit
, необходимо явно вызвать BecomeCurrent
метод или установить свойство документа UserActivity
на UIViewController
переднем плане.
AppKit
автоматически восстановит любое UserActivity
свойство, созданное таким образом в OS X. Это происходит, если ContinueUserActivity
метод возвращается или если он неуправляем false
. В этой ситуации документ открывается с OpenDocument
помощью метода NSDocumentController
, после чего он получит RestoreUserActivityState
вызов метода.
Дополнительные сведения см. в разделе "Вспомогательный раздаток" в приложениях на основе документов.
Оба UIKit
и AppKit
могут автоматически управлять действием пользователя, если вы задали его в качестве свойства объекта UserActivity
ответа. Если состояние было изменено, необходимо задать NeedsSave
для свойства ответчика UserActivity
true
значение . Система автоматически сохранит необходимые UserActivity
значения после предоставления времени отклика для обновления состояния путем вызова метода UpdateUserActivityState
.
Если несколько респондентов совместно используют один NSUserActivity
экземпляр, они получают обратный UpdateUserActivityState
вызов, когда система обновляет объект действия пользователя. Ответитель должен вызвать AddUserInfoEntries
метод, чтобы обновить NSUserActivity
UserInfo
словарь, чтобы отразить текущее состояние действия на этом этапе. Словарь UserInfo
очищается перед каждым UpdateUserActivityState
вызовом.
Чтобы отсоединить себя от действия, ответчик может задать для него свойство UserActivity
null
. Если управляемый NSUserActivity
экземпляр платформы приложений больше не связан с ответами или документами, он автоматически недопустим.
Дополнительные сведения см. в разделе "Вспомогательный раздатчик" в ответах ниже.
AppDelegate
Приложение является его основной точкой входа при обработке продолжения handoff. Когда пользователь отвечает на уведомление handoff, запускается соответствующее приложение (если оно еще не запущено) и WillContinueUserActivityWithType
вызывается метод вызова AppDelegate
. На этом этапе приложение должно сообщить пользователю, что продолжение начинается.
Экземпляр NSUserActivity
доставляется при AppDelegate
ContinueUserActivity
вызове метода. На этом этапе необходимо настроить пользовательский интерфейс приложения и продолжить данное действие.
Дополнительные сведения см. в разделе "Реализация передачи ".
Из-за требований безопасности, введенных Handoff, приложение Xamarin.iOS, использующее платформу Handoff, должно быть правильно настроено как на портале разработчика Apple, так и в файле проекта Xamarin.iOS.
Выполните следующие действия.
Войдите на портал разработчика Apple.
Щелкните сертификаты, идентификаторы и профили.
Если вы еще этого не сделали, щелкните идентификаторы и создайте идентификатор приложения (например
com.company.appname
, в противном случае измените существующий идентификатор).Убедитесь, что служба iCloud была проверка для заданного идентификатора:
Сохранение изменений.
Щелкните "Разработка профилей> подготовки" и создайте новый профиль подготовки разработки для приложения:
Скачайте и установите новый профиль подготовки или используйте Xcode для скачивания и установки профиля.
Измените параметры проекта Xamarin.iOS и убедитесь, что вы используете только что созданный профиль подготовки:
Затем измените файл Info.plist и убедитесь, что вы используете идентификатор приложения, который использовался для создания профиля подготовки:
Прокрутите страницу до раздела фоновых режимов и проверка следующие элементы:
Сохраните изменения во всех файлах.
С помощью этих параметров приложение теперь готово к доступу к API-интерфейсам Handoff Framework. Подробные сведения о подготовке см. в руководствах по подготовке устройств и подготовке приложения .
Действия пользователей можно продолжить среди приложений, подписанных с одним идентификатором группы разработчиков, и поддерживать один и тот же тип действия. Реализация передачи в приложении Xamarin.iOS требует создания объекта действия пользователя (в UIKit
или AppKit
), обновления состояния объекта для отслеживания действия и продолжения действия на принимающем устройстве.
Первым шагом в реализации handoff является определение типов действий пользователей, поддерживаемых приложением, и просмотр того, какие из этих действий являются хорошими кандидатами на продолжение на другом устройстве. Например, приложение ToDo может поддерживать редактирование элементов в качестве одного типа действия пользователя и поддерживать просмотр списка доступных элементов как другого.
Приложение может создавать столько типов действий пользователей, сколько требуется, для любой функции, которую предоставляет приложение. Для каждого типа действия пользователя приложение будет необходимо отслеживать, когда действие типа начинается и заканчивается, и необходимо поддерживать актуальные сведения о состоянии, чтобы продолжить эту задачу на другом устройстве.
Действия пользователей можно продолжать в любом приложении, подписанном с одним и тем же идентификатором команды, без сопоставления "один к одному" между отправкой и получением приложений. Например, данное приложение может создать четыре различных типа действий, которые используются различными отдельными приложениями на другом устройстве. Это обычное вхождение между версией приложения Mac (которая может иметь множество функций и функций) и приложений iOS, где каждое приложение меньше и ориентировано на определенную задачу.
Идентификатор типа действия — это короткая строка, добавленная в NSUserActivityTypes
массив файла Info.plist приложения, используемого для уникального определения заданного типа действия пользователя. В массиве будет одна запись для каждого действия, которое поддерживает приложение. Apple предлагает использовать нотацию обратного стиля DNS для идентификатора типа действия, чтобы избежать конфликтов. Например, com.company-name.appname.activity
для определенных действий на основе приложений или com.company-name.activity
действий, которые могут выполняться в нескольких приложениях.
Идентификатор типа действия используется при создании NSUserActivity
экземпляра для определения типа действия. При продолжении действия на другом устройстве тип действия (вместе с идентификатором команды приложения) определяет, какое приложение будет запускаться для продолжения действия.
Например, мы создадим пример приложения с именем MonkeyBrowser. Это приложение будет представлять четыре вкладки, каждый из которых имеет другой URL-адрес, открытый в представлении веб-браузера. Пользователь сможет продолжить любую вкладку на другом устройстве iOS под управлением приложения.
Чтобы создать необходимые идентификаторы типов действий для поддержки этого поведения, измените файл Info.plist и перейдите в представление источника . NSUserActivityTypes
Добавьте ключ и создайте следующие идентификаторы:
Мы создали четыре новых идентификатора типа действия, по одному для каждой вкладки в примере приложения MonkeyBrowser . При создании собственных приложений замените содержимое NSUserActivityTypes
массива идентификаторами типов действий, характерными для действий, поддерживаемых приложением.
При создании нового экземпляра NSUserActivity
класса мы укажем NSUserActivityDelegate
экземпляр для отслеживания изменений состояния действия. Например, следующий код можно использовать для отслеживания изменений состояния:
using System;
using CoreGraphics;
using Foundation;
using UIKit;
namespace MonkeyBrowse
{
public class UserActivityDelegate : NSUserActivityDelegate
{
#region Constructors
public UserActivityDelegate ()
{
}
#endregion
#region Override Methods
public override void UserActivityReceivedData (NSUserActivity userActivity, NSInputStream inputStream, NSOutputStream outputStream)
{
// Log
Console.WriteLine ("User Activity Received Data: {0}", userActivity.Title);
}
public override void UserActivityWasContinued (NSUserActivity userActivity)
{
Console.WriteLine ("User Activity Was Continued: {0}", userActivity.Title);
}
public override void UserActivityWillSave (NSUserActivity userActivity)
{
Console.WriteLine ("User Activity will be Saved: {0}", userActivity.Title);
}
#endregion
}
}
Метод UserActivityReceivedData
вызывается, когда поток продолжения получил данные от отправляемого устройства. Дополнительные сведения см. в разделе "Поддержка продолжения" Потоки ниже.
Метод UserActivityWasContinued
вызывается, когда другое устройство взяло действие с текущего устройства. В зависимости от типа действия, например добавления нового элемента в список ToDo, приложению может потребоваться прерывание действия на устройстве отправки.
Метод UserActivityWillSave
вызывается до сохранения и синхронизации любых изменений действия на локально доступных устройствах. Этот метод можно использовать для внесения изменений в свойство экземпляра NSUserActivity
в последнюю минуту UserInfo
перед отправкой.
Каждое действие, которое приложение хочет предоставить возможность продолжения на другом устройстве, должно быть инкапсулировано в NSUserActivity
экземпляре. Приложение может создавать столько действий, сколько требуется, и характер этих действий зависит от функциональных возможностей и функций приложения, о которых идет речь. Например, почтовое приложение может создать одно действие для создания нового сообщения, а другое — для чтения сообщения.
В нашем примере приложение создается каждый раз, NSUserActivity
когда пользователь вводит новый URL-адрес в одном из представлений веб-браузера с вкладками. Следующий код сохраняет состояние заданной вкладки:
public NSString UserActivityTab1 = new NSString ("com.xamarin.monkeybrowser.tab1");
public NSUserActivity UserActivity { get; set; }
...
UserActivity = new NSUserActivity (UserActivityTab1);
UserActivity.Title = "Weather Tab";
UserActivity.Delegate = new UserActivityDelegate ();
// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);
// Inform Activity that it has been updated
UserActivity.BecomeCurrent ();
Он создает новый NSUserActivity
с помощью одного из типов действий пользователя, созданных выше, и предоставляет удобочитаемое имя действия. Он подключается к экземпляру созданного выше экземпляра NSUserActivityDelegate
для отслеживания изменений состояния и сообщает iOS, что это действие пользователя является текущим действием.
Как мы видели выше, свойство NSUserActivity
класса представляет собой NSDictionary
пары "ключ-значение", UserInfo
используемые для определения состояния заданного действия. Значения, хранящиеся вUserInfo
, должны быть одним из следующих типов: NSArray
, NSData
, NSDictionary
NSDate
, NSNull
, NSNumber
, NSString
NSSet
или NSURL
. NSURL
Значения данных, указывающие на документы iCloud, автоматически настраиваются таким образом, чтобы они указывали на те же документы на принимающем устройстве.
В приведенном выше примере мы создали NSMutableDictionary
объект и заполните его одним ключом, предоставляющим URL-адрес, который пользователь в настоящее время просматривал на данной вкладке. Метод AddUserInfoEntries
действия пользователя использовался для обновления действия с данными, которые будут использоваться для восстановления действия на принимающем устройстве:
// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);
Apple предлагает сохранить информацию, отправляемую на самый широкий минимум, чтобы убедиться, что действие отправляется своевременно на принимающее устройство. Если требуется большая информация, например изображение, присоединенное к документу, необходимо отправить, следует использовать продолжение Потоки. Дополнительные сведения см. в разделе "Поддержка продолжения" Потоки ниже.
Передача автоматически сообщает локальным устройствам iOS и OS X, которые находятся в физическом расположении к исходному устройству и вошли в ту же учетную запись iCloud, о доступности неуместных действий пользователей. Если пользователь решит продолжить действие на новом устройстве, система запустит соответствующее приложение (на основе идентификатора команды и типа действия) и сведения о том, что продолжение AppDelegate
должно произойти.
Во-первых, метод вызывается так, WillContinueUserActivityWithType
что приложение может сообщить пользователю о том, что продолжение начнется. Мы используем следующий код в файле AppDelegate.cs примера приложения для обработки продолжения запуска:
public NSString UserActivityTab1 = new NSString ("com.xamarin.monkeybrowser.tab1");
public NSString UserActivityTab2 = new NSString ("com.xamarin.monkeybrowser.tab2");
public NSString UserActivityTab3 = new NSString ("com.xamarin.monkeybrowser.tab3");
public NSString UserActivityTab4 = new NSString ("com.xamarin.monkeybrowser.tab4");
...
public FirstViewController Tab1 { get; set; }
public SecondViewController Tab2 { get; set;}
public ThirdViewController Tab3 { get; set; }
public FourthViewController Tab4 { get; set; }
...
public override bool WillContinueUserActivity (UIApplication application, string userActivityType)
{
// Report Activity
Console.WriteLine ("Will Continue Activity: {0}", userActivityType);
// Take action based on the user activity type
switch (userActivityType) {
case "com.xamarin.monkeybrowser.tab1":
// Inform view that it's going to be modified
Tab1.PreparingToHandoff ();
break;
case "com.xamarin.monkeybrowser.tab2":
// Inform view that it's going to be modified
Tab2.PreparingToHandoff ();
break;
case "com.xamarin.monkeybrowser.tab3":
// Inform view that it's going to be modified
Tab3.PreparingToHandoff ();
break;
case "com.xamarin.monkeybrowser.tab4":
// Inform view that it's going to be modified
Tab4.PreparingToHandoff ();
break;
}
// Inform system we handled this
return true;
}
В приведенном выше примере каждый контроллер представления регистрируется в AppDelegate
PreparingToHandoff
общедоступном методе, который отображает индикатор активности и сообщение, позволяющее пользователю знать, что действие будет передано текущему устройству. Пример:
private void ShowBusy(string reason) {
// Display reason
BusyText.Text = reason;
//Define Animation
UIView.BeginAnimations("Show");
UIView.SetAnimationDuration(1.0f);
Handoff.Alpha = 0.5f;
//Execute Animation
UIView.CommitAnimations();
}
...
public void PreparingToHandoff() {
// Inform caller
ShowBusy ("Continuing Activity...");
}
AppDelegate
Вызов ContinueUserActivity
будет вызываться для фактического продолжения заданного действия. Опять же, из нашего примера приложения:
public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
// Report Activity
Console.WriteLine ("Continuing User Activity: {0}", userActivity.ToString());
// Get input and output streams from the Activity
userActivity.GetContinuationStreams ((NSInputStream arg1, NSOutputStream arg2, NSError arg3) => {
// Send required data via the streams
// ...
});
// Take action based on the Activity type
switch (userActivity.ActivityType) {
case "com.xamarin.monkeybrowser.tab1":
// Preform handoff
Tab1.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab1});
break;
case "com.xamarin.monkeybrowser.tab2":
// Preform handoff
Tab2.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab2});
break;
case "com.xamarin.monkeybrowser.tab3":
// Preform handoff
Tab3.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab3});
break;
case "com.xamarin.monkeybrowser.tab4":
// Preform handoff
Tab4.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab4});
break;
}
// Inform system we handled this
return true;
}
Общедоступный PerformHandoff
метод каждого контроллера представления фактически преобразовывает передачу и восстанавливает действие на текущем устройстве. В примере отображается тот же URL-адрес на заданной вкладке, что пользователь просматривал другое устройство. Пример:
private void HideBusy() {
//Define Animation
UIView.BeginAnimations("Hide");
UIView.SetAnimationDuration(1.0f);
Handoff.Alpha = 0f;
//Execute Animation
UIView.CommitAnimations();
}
...
public void PerformHandoff(NSUserActivity activity) {
// Hide busy indicator
HideBusy ();
// Extract URL from dictionary
var url = activity.UserInfo ["Url"].ToString ();
// Display value
URL.Text = url;
// Display the give webpage
WebView.LoadRequest(new NSUrlRequest(NSUrl.FromString(url)));
// Save activity
UserActivity = activity;
UserActivity.BecomeCurrent ();
}
Этот ContinueUserActivity
метод включает в UIApplicationRestorationHandler
себя вызов для возобновления действия на основе документа или ответа. При вызове необходимо передать NSArray
или восстанавливаемые объекты обработчику восстановления. Например:
completionHandler (new NSObject[]{Tab4});
Для каждого переданного объекта вызывается его RestoreUserActivityState
метод. Затем каждый объект может использовать данные в UserInfo
словаре для восстановления собственного состояния. Например:
public override void RestoreUserActivityState (NSUserActivity activity)
{
base.RestoreUserActivityState (activity);
// Log activity
Console.WriteLine ("Restoring Activity {0}", activity.Title);
}
Для приложений на основе документов, если вы не реализуете ContinueUserActivity
метод или возвращаете false
его или AppKit
UIKit
автоматически возобновляете действие. Дополнительные сведения см. в разделе "Вспомогательный раздаток" в приложениях на основе документов.
Так как Handoff зависит от передачи информации между коллекцией слабо подключенных устройств iOS и OS X, процесс передачи иногда может завершиться ошибкой. Вы должны разработать приложение для обработки этих сбоев корректно и сообщить пользователю о любых возникающих ситуациях.
В случае сбоя DidFailToContinueUserActivitiy
вызывается метод.AppDelegate
Например:
public override void DidFailToContinueUserActivitiy (UIApplication application, string userActivityType, NSError error)
{
// Log information about the failure
Console.WriteLine ("User Activity {0} failed to continue. Error: {1}", userActivityType, error.LocalizedDescription);
}
Необходимо использовать предоставленный NSError
для предоставления пользователю сведений о сбое.
Пользователь может продолжить действие без установки соответствующего собственного приложения на нужном устройстве. В некоторых ситуациях веб-интерфейс может предоставить необходимые функциональные возможности, и действие по-прежнему может быть продолжено. Например, учетная запись электронной почты пользователя может предоставить веб-базовый пользовательский интерфейс для создания и чтения сообщений.
Если исходное приложение знает URL-адрес веб-интерфейса (и обязательный синтаксис для идентификации данного элемента, продолжающегося), он может закодировать эти сведения в WebpageURL
свойстве NSUserActivity
экземпляра. Если на принимающем устройстве нет соответствующего собственного приложения, установленного для обработки продолжения, можно вызвать предоставленный веб-интерфейс.
Если пользователь использовал веб-интерфейс на исходном устройстве, а собственное приложение на принимающем устройстве утверждает доменную часть WebpageURL
свойства, система будет использовать это приложение, которое обрабатывает продолжение. Новое устройство получит NSUserActivity
экземпляр, который помечает тип действия как BrowsingWeb
и WebpageURL
будет содержать URL-адрес, который пользователь посетил, UserInfo
словарь будет пустым.
Чтобы приложение участвовало в этом типе handoff, оно должно претендовать на домен в com.apple.developer.associated-domains
праве с форматом <service>:<fully qualified domain name>
(например: activity continuation:company.com
).
Если указанный домен соответствует WebpageURL
значению свойства, Handoff скачивает список утвержденных идентификаторов приложений с веб-сайта на этом домене. Веб-сайт должен предоставить список утвержденных идентификаторов в подписанном JSON-файле с именем apple-app-site-association (например, https://company.com/apple-app-site-association
).
Этот JSON-файл содержит словарь, указывающий список идентификаторов приложений в форме <team identifier>.<bundle identifier>
. Например:
{
"activitycontinuation": {
"apps": [ "YWBN8XTPBJ.com.company.FirstApp",
"YWBN8XTPBJ.com.company.SecondApp" ]
}
}
Чтобы подписать JSON-файл (чтобы он был правильным Content-Type
application/pkcs7-mime
), используйте приложение терминала и команду с сертификатом и openssl
ключом, выданным центром сертификации, доверенным iOS (см https://support.apple.com/kb/ht5012 . список). Например:
echo '{"activitycontinuation":{"apps":["YWBN8XTPBJ.com.company.FirstApp",
"YWBN8XTPBJ.com.company.SecondApp"]}}' > json.txt
cat json.txt | openssl smime -sign -inkey company.com.key
-signer company.com.pem
-certfile intermediate.pem
-noattr -nodetach
-outform DER > apple-app-site-association
Команда openssl
выводит подписанный JSON-файл, который вы размещаете на веб-сайте по URL-адресу связи apple-app-site-association . Например:
https://example.com/apple-app-site-association.
Приложение получит любое действие, домен которого WebpageURL
находится в своем com.apple.developer.associated-domains
праве. http
https
Поддерживаются только протоколы, любой другой протокол вызовет исключение.
Как указано выше, в iOS и OS X приложения на основе документов автоматически поддерживают передачу документов на основе iCloud, если файл Info.plist приложения содержит CFBundleDocumentTypes
ключNSUbiquitousDocumentUserActivityType
. Например:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>NSRTFDPboardType</string>
. . .
<key>LSItemContentTypes</key>
<array>
<string>com.myCompany.rtfd</string>
</array>
. . .
<key>NSUbiquitousDocumentUserActivityType</key>
<string>com.myCompany.myEditor.editing</string>
</dict>
</array>
В этом примере строка представляет собой конструктор приложения обратного DNS с именем добавленного действия. Если этот способ введен, записи типа действия не нужно повторять в массиве NSUserActivityTypes
файла Info.plist .
Автоматически созданный объект действия пользователя (доступный через свойство документа UserActivity
) можно ссылаться на другие объекты в приложении и использовать для восстановления состояния продолжения. Например, для отслеживания выделения элементов и положения документа. Это свойство действий NeedsSave
необходимо задать для true
каждого изменения состояния и обновления UserInfo
словаря в методе UpdateUserActivityState
.
Свойство UserActivity
можно использовать из любого потока и соответствует протоколу наблюдения за ключевым значением (KVO), поэтому его можно использовать для синхронизации документа при перемещении и выходе из iCloud. Свойство UserActivity
будет недопустимо при закрытии документа.
Дополнительные сведения см. в документации по поддержке действий пользователей Apple в документации по приложениям на основе документов.
Вы можете связать ответчиков (наследуемых от UIResponder
iOS или NSResponder
OS X) к действиям, задав их UserActivity
свойства. Система автоматически сохраняет UserActivity
свойство в соответствующее время, вызывая метод ответа UpdateUserActivityState
для добавления текущих данных в объект действия пользователя с помощью AddUserInfoEntriesFromDictionary
метода.
Возможны ситуации, когда объем информации, необходимой для продолжения действия, не может быть эффективно передан начальной полезных данных передачи. В этих ситуациях принимающее приложение может установить один или несколько потоков между собой и исходное приложение для передачи данных.
Исходное приложение присвоит SupportsContinuationStreams
свойству экземпляра true
NSUserActivity
значение . Например:
// Create a new user Activity to support this tab
UserActivity = new NSUserActivity (ThisApp.UserActivityTab1){
Title = "Weather Tab",
SupportsContinuationStreams = true
};
UserActivity.Delegate = new UserActivityDelegate ();
// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);
// Inform Activity that it has been updated
UserActivity.BecomeCurrent ();
Затем принимающее приложение может вызвать GetContinuationStreams
метод NSUserActivity
в ней AppDelegate
, чтобы установить поток. Например:
public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
// Report Activity
Console.WriteLine ("Continuing User Activity: {0}", userActivity.ToString());
// Get input and output streams from the Activity
userActivity.GetContinuationStreams ((NSInputStream arg1, NSOutputStream arg2, NSError arg3) => {
// Send required data via the streams
// ...
});
// Take action based on the Activity type
switch (userActivity.ActivityType) {
case "com.xamarin.monkeybrowser.tab1":
// Preform handoff
Tab1.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab1});
break;
case "com.xamarin.monkeybrowser.tab2":
// Preform handoff
Tab2.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab2});
break;
case "com.xamarin.monkeybrowser.tab3":
// Preform handoff
Tab3.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab3});
break;
case "com.xamarin.monkeybrowser.tab4":
// Preform handoff
Tab4.PerformHandoff (userActivity);
completionHandler (new NSObject[]{Tab4});
break;
}
// Inform system we handled this
return true;
}
На исходном устройстве делегат действия пользователя получает потоки, вызывая его DidReceiveInputStream
метод, чтобы предоставить данные, запрошенные для продолжения действия пользователя на устройстве возобновления.
Вы будете NSInputStream
использовать для предоставления доступа только для чтения для потоковых данных и NSOutputStream
предоставления доступа только для записи. Потоки должны использоваться в запросе и ответе, где принимающее приложение запрашивает больше данных, и исходное приложение предоставляет его. Таким образом, данные, записанные в выходной поток на исходном устройстве, считываются из входного потока на продолжающемся устройстве и наоборот.
Даже в ситуациях, когда требуется поток продолжения, между двумя приложениями должно быть минимальное взаимодействие между двумя приложениями.
Дополнительные сведения см. в документации по использованию продолжения apple Потоки.
Успешная реализация бесшовного продолжения действия пользователя через handoff требует тщательного проектирования из-за всех связанных компонентов. Apple предлагает принять следующие рекомендации для приложений с поддержкой Handoff:
- Создайте действия пользователя, чтобы требовать наименьших полезных данных, которые могут быть связаны с состоянием действия, которое необходимо продолжить. Чем больше полезные данные, тем дольше требуется продолжение.
- Если необходимо передать большие объемы данных для успешного продолжения, учитывайте затраты, связанные с конфигурацией и сетевыми издержками.
- Обычно для большого приложения Mac создается действия пользователей, которые обрабатываются несколькими, небольшими приложениями для конкретных задач на устройствах iOS. Различные версии приложений и ОС должны быть разработаны для эффективной работы или сбой.
- При указании типов действий используйте обратную нотацию DNS, чтобы избежать конфликтов. Если действие относится к заданному приложению, его имя должно быть включено в определение типа (например
com.myCompany.myEditor.editing
). Если действие может работать в нескольких приложениях, удалите имя приложения из определения (напримерcom.myCompany.editing
). - Если приложению необходимо обновить состояние действия пользователя (
NSUserActivity
) задайтеNeedsSave
для свойстваtrue
значение . В соответствующее время Handoff вызовет метод делегатаUserActivityWillSave
, чтобы можно было обновитьUserInfo
словарь по мере необходимости. - Так как процесс передачи может не инициализировать мгновенно на принимающем устройстве, необходимо реализовать
AppDelegate
"sWillContinueUserActivity
" и сообщить пользователю о том, что продолжение будет запущено.
Пример использования Handoff в приложении Xamarin.iOS — это пример приложения MonkeyBrowser . Приложение имеет четыре вкладки, которые пользователь может использовать для просмотра в Интернете, каждый из которых имеет заданный тип действия: Погода, Избранное, Кофе-перерыв и работа.
На любой вкладке, когда пользователь вводит новый URL-адрес и нажимает кнопку Go , для этой вкладки создается новая NSUserActivity
вкладка, содержащая URL-адрес, который пользователь в настоящее время просматривает:
Если у другого устройства пользователя установлено приложение MonkeyBrowser , войдите в iCloud с помощью той же учетной записи пользователя, находится в той же сети и в близком расположении к приведенному выше устройству, действие передачи будет отображаться на начальном экране (в нижнем левом углу):
Если пользователь перетаскивает вверх по значку handoff, приложение будет запущено, а действие пользователя, указанное в NSUserActivity
этом элементе, будет продолжено на новом устройстве:
Когда действие пользователя успешно отправлено другому устройству Apple, отправляющее устройство NSUserActivity
получит вызов UserActivityWasContinued
метода на своем NSUserActivityDelegate
устройстве, чтобы сообщить ему, что действие пользователя успешно передано другому устройству.
В этой статье приведены общие сведения о платформе handoff, используемой для продолжения действия пользователей между несколькими устройствами Apple пользователя. Далее он показал, как включить и реализовать Handoff в приложении Xamarin.iOS. Наконец, он обсудил различные типы продолжений Handoff, доступные и рекомендации handoff.