Передача в Xamarin.iOS

В этой статье рассматривается работа с handoff в приложении Xamarin.iOS для передачи действий пользователей между приложениями, работающими на других устройствах пользователя.

Apple представила Handoff в iOS 8 и OS X Yosemite (10.10), чтобы обеспечить общий механизм передачи действий, запущенных на одном из своих устройств, на другое устройство под управлением того же приложения или другого приложения, которое поддерживает то же действие.

An example of performing a Handoff operation

В этой статье вы узнаете, как включить общий доступ к действиям в приложении Xamarin.iOS и подробно охватить платформу Handoff:

О 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 используются для перезапуска действия.

An overview of Continuing User Activities

Только приложения, использующие один и тот же идентификатор команды разработчика и отвечающие на заданный тип действия, могут продолжаться. Приложение определяет типы действий, поддерживаемые NSUserActivityTypes в ключе файла Info.plist . Учитывая это, продолжающееся устройство выбирает приложение для выполнения продолжения на основе идентификатора команды, типа действия и при необходимости заголовка действия.

Принимающее приложение использует сведения из NSUserActivityUserInfo словаря, чтобы настроить пользовательский интерфейс и восстановить состояние заданного действия, чтобы переход отображалось просто для конечного пользователя.

Если продолжение требует больше информации, чем можно эффективно отправлять с помощью NSUserActivityприложения, возобновление приложения может отправить вызов исходному приложению и установить один или несколько потоков для передачи необходимых данных. Например, если действие редактировало большой текстовый документ с несколькими изображениями, потоковая передача потребуется для передачи информации, необходимой для продолжения действия на принимающем устройстве. Дополнительные сведения см. в разделе "Поддержка продолжения" Потоки ниже.

Как указано выше, NSDocument или UIDocument приложения на основе автоматически поддерживают поддержку Handoff. Дополнительные сведения см. в разделе "Вспомогательные передачи" в приложениях на основе документов ниже.

Класс NSUserActivity

Класс NSUserActivity является основным объектом в обмене Handoff и используется для инкапсулации состояния действия пользователя, доступного для продолжения. Приложение создаст копию NSUserActivity любого действия, которое он поддерживает и хочет продолжить на другом устройстве. Например, редактор документов создаст действие для каждого открытого документа. Однако только самый передний документ (отображаемый в самом переднем окне или вкладке) является текущим действием и доступен для продолжения.

Экземпляр NSUserActivity определяется как его ActivityType , так и Title свойствами. Свойство UserInfo словаря используется для передачи сведений о состоянии действия. NeedsSave Задайте для свойства значениеtrue, если требуется отложенная загрузка сведений о состоянии с помощью NSUserActivityделегата. AddUserInfoEntries Используйте метод для объединения новых данных из других клиентов в UserInfo словарь, как это необходимо для сохранения состояния действия.

Класс NSUserActivityDelegate

Используется NSUserActivityDelegate для хранения сведений в NSUserActivityUserInfo словаре и синхронизации с текущим состоянием действия. Если системе требуется обновить сведения в действии (например, перед продолжением на другом устройстве), он вызывает UserActivityWillSave метод делегата.

Необходимо реализовать UserActivityWillSave метод и внести изменения NSUserActivity в (напримерUserInfoTitle, и т. д.), чтобы убедиться, что он по-прежнему отражает состояние текущего действия. Когда система вызывает UserActivityWillSave метод, NeedsSave флаг будет снят. Если изменить какие-либо свойства данных действия, вам потребуется снова задать NeedsSave значение true .

Вместо использования метода, представленного UserActivityWillSave выше, вы можете автоматически иметь UIKit или AppKit управлять действием пользователя. Для этого задайте свойство объекта UserActivity ответа и реализуйте UpdateUserActivityState метод. Дополнительные сведения см. в разделе "Вспомогательный раздатчик" в ответах ниже.

Поддержка Платформы приложений

Как UIKit (iOS), так и AppKit (OS X) обеспечивают встроенную поддержку Handoff в NSDocument, ответчике (NSResponderUIResponder/) и 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 для свойства ответчика UserActivitytrueзначение . Система автоматически сохранит необходимые UserActivity значения после предоставления времени отклика для обновления состояния путем вызова метода UpdateUserActivityState .

Если несколько респондентов совместно используют один NSUserActivity экземпляр, они получают обратный UpdateUserActivityState вызов, когда система обновляет объект действия пользователя. Ответитель должен вызвать AddUserInfoEntries метод, чтобы обновить NSUserActivityUserInfo словарь, чтобы отразить текущее состояние действия на этом этапе. Словарь UserInfo очищается перед каждым UpdateUserActivityState вызовом.

Чтобы отсоединить себя от действия, ответчик может задать для него свойство UserActivitynull. Если управляемый NSUserActivity экземпляр платформы приложений больше не связан с ответами или документами, он автоматически недопустим.

Дополнительные сведения см. в разделе "Вспомогательный раздатчик" в ответах ниже.

Действия пользователей и AppDelegate

AppDelegate Приложение является его основной точкой входа при обработке продолжения handoff. Когда пользователь отвечает на уведомление handoff, запускается соответствующее приложение (если оно еще не запущено) и WillContinueUserActivityWithType вызывается метод вызова AppDelegate . На этом этапе приложение должно сообщить пользователю, что продолжение начинается.

Экземпляр NSUserActivity доставляется при AppDelegateContinueUserActivity вызове метода. На этом этапе необходимо настроить пользовательский интерфейс приложения и продолжить данное действие.

Дополнительные сведения см. в разделе "Реализация передачи ".

Включение передачи в приложении Xamarin

Из-за требований безопасности, введенных Handoff, приложение Xamarin.iOS, использующее платформу Handoff, должно быть правильно настроено как на портале разработчика Apple, так и в файле проекта Xamarin.iOS.

Выполните следующие действия.

  1. Войдите на портал разработчика Apple.

  2. Щелкните сертификаты, идентификаторы и профили.

  3. Если вы еще этого не сделали, щелкните идентификаторы и создайте идентификатор приложения (например com.company.appname, в противном случае измените существующий идентификатор).

  4. Убедитесь, что служба iCloud была проверка для заданного идентификатора:

    Enable the iCloud service for the given ID

  5. Сохранение изменений.

  6. Щелкните "Разработка профилей> подготовки" и создайте новый профиль подготовки разработки для приложения:

    Create a new development provisioning profile for the app

  7. Скачайте и установите новый профиль подготовки или используйте Xcode для скачивания и установки профиля.

  8. Измените параметры проекта Xamarin.iOS и убедитесь, что вы используете только что созданный профиль подготовки:

    Select the provisioning profile just created

  9. Затем измените файл Info.plist и убедитесь, что вы используете идентификатор приложения, который использовался для создания профиля подготовки:

    Set App ID

  10. Прокрутите страницу до раздела фоновых режимов и проверка следующие элементы:

    Enable the required background modes

  11. Сохраните изменения во всех файлах.

С помощью этих параметров приложение теперь готово к доступу к 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 Добавьте ключ и создайте следующие идентификаторы:

The NSUserActivityTypes key and required identifiers in the plist editor

Мы создали четыре новых идентификатора типа действия, по одному для каждой вкладки в примере приложения 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 экземпляре. Приложение может создавать столько действий, сколько требуется, и характер этих действий зависит от функциональных возможностей и функций приложения, о которых идет речь. Например, почтовое приложение может создать одно действие для создания нового сообщения, а другое — для чтения сообщения.

В нашем примере приложение создается каждый раз, 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, что это действие пользователя является текущим действием.

Заполнение словаря UserInfo

Как мы видели выше, свойство NSUserActivity класса представляет собой NSDictionary пары "ключ-значение", UserInfo используемые для определения состояния заданного действия. Значения, хранящиеся вUserInfo, должны быть одним из следующих типов: NSArray, NSData, NSDictionaryNSDate, NSNull, NSNumber, NSStringNSSetили 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;
}

В приведенном выше примере каждый контроллер представления регистрируется в AppDelegatePreparingToHandoff общедоступном методе, который отображает индикатор активности и сообщение, позволяющее пользователю знать, что действие будет передано текущему устройству. Пример:

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его или AppKitUIKit автоматически возобновляете действие. Дополнительные сведения см. в разделе "Вспомогательный раздаток" в приложениях на основе документов.

Сбой Рукой грейстно

Так как 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-Typeapplication/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 праве. httphttps Поддерживаются только протоколы, любой другой протокол вызовет исключение.

Поддержка передачи в приложениях на основе документов

Как указано выше, в 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 свойству экземпляра trueNSUserActivity значение . Например:

// 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"s WillContinueUserActivity " и сообщить пользователю о том, что продолжение будет запущено.

Пример приложения для передачи

В качестве примера использования Handoff в приложении Xamarin.iOS мы включили пример приложения MonkeyBrowser в это руководство. Приложение имеет четыре вкладки, которые пользователь может использовать для просмотра в Интернете, каждый из которых имеет заданный тип действия: Погода, Избранное, Кофе-перерыв и работа.

На любой вкладке, когда пользователь вводит новый URL-адрес и нажимает кнопку Go , для этой вкладки создается новая NSUserActivity вкладка, содержащая URL-адрес, который пользователь в настоящее время просматривает:

Example Handoff App

Если у другого устройства пользователя установлено приложение MonkeyBrowser , войдите в iCloud с помощью той же учетной записи пользователя, находится в той же сети и в близком расположении к приведенному выше устройству, действие передачи будет отображаться на начальном экране (в нижнем левом углу):

The Handoff Activity displayed on the home screen in the lower left hand corner

Если пользователь перетаскивает вверх по значку handoff, приложение будет запущено, а действие пользователя, указанное в NSUserActivity этом элементе, будет продолжено на новом устройстве:

The User Activity continued on the new device

Когда действие пользователя успешно отправлено другому устройству Apple, отправляющее устройство NSUserActivity получит вызов UserActivityWasContinued метода на своем NSUserActivityDelegate устройстве, чтобы сообщить ему, что действие пользователя успешно передано другому устройству.

Итоги

В этой статье приведены общие сведения о платформе handoff, используемой для продолжения действия пользователей между несколькими устройствами Apple пользователя. Далее он показал, как включить и реализовать Handoff в приложении Xamarin.iOS. Наконец, он обсудил различные типы продолжений Handoff, доступные и рекомендации handoff.