Przekazywanie w środowisku Xamarin.iOS

W tym artykule opisano pracę z przekazywaniem w aplikacji platformy Xamarin.iOS w celu przeniesienia działań użytkownika między aplikacjami uruchomionymi na innych urządzeniach użytkownika.

Firma Apple wprowadziła funkcję Handoff w systemach iOS 8 i OS X Yosemite (10.10), aby zapewnić wspólny mechanizm przenoszenia działań wykonywanych na jednym z urządzeń na innym urządzeniu z tą samą aplikacją lub inną aplikacją, która obsługuje tę samą aktywność.

An example of performing a Handoff operation

W tym artykule przedstawiono szybkie omówienie włączania udostępniania działań w aplikacji platformy Xamarin.iOS i omówiono szczegółowo strukturę Handoff:

Informacje o przekazach

Przekazywanie (znane również jako ciągłość) zostało wprowadzone przez firmę Apple w systemach iOS 8 i OS X Yosemite (10.10) jako sposób na rozpoczęcie działania na jednym z urządzeń (iOS lub Mac) i kontynuowanie tej samej aktywności na innych urządzeniach (zidentyfikowanych przez konto użytkownika w usłudze iCloud).

Przekazywanie zostało rozszerzone w systemie iOS 9, aby również obsługiwać nowe, ulepszone funkcje wyszukiwania. Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą ulepszeń wyszukiwania.

Na przykład użytkownik może uruchomić wiadomość e-mail na swoim urządzeniu i Telefon i bezproblemowo kontynuować wiadomość e-mail na komputerze Mac, z wszystkimi tymi samymi informacjami o wiadomościach wypełnionymi i kursorem w tej samej lokalizacji, w której ją opuścili w systemie iOS.

Wszystkie aplikacje, które współużytkują ten sam identyfikator zespołu, kwalifikują się do korzystania z funkcji Handoff w celu kontynuowania działań użytkowników w aplikacjach, o ile ta aplikacja jest dostarczana za pośrednictwem sklepu iTunes App Store lub podpisanego przez zarejestrowanego dewelopera (w przypadku aplikacji Dla komputerów Mac, Enterprise lub Ad Hoc).

Wszystkie NSDocument aplikacje lub UIDocument oparte automatycznie mają wbudowaną obsługę przekazywania i wymagają minimalnych zmian w celu obsługi przekazywania.

Dalsze działania użytkownika

Klasa NSUserActivity (wraz z niewielkimi zmianami w UIKit systemach i AppKit) zapewnia obsługę definiowania aktywności użytkownika, które potencjalnie mogą być kontynuowane na innych urządzeniach użytkownika.

Aby działanie zostało przekazane do innego urządzenia użytkownika, musi ono zostać hermetyzowane w wystąpieniu NSUserActivityoznaczonym jako bieżące działanie, czy jest to zestaw ładunków (dane używane do wykonania kontynuacji), a następnie działanie musi zostać przesłane do tego urządzenia.

Przekazywanie przekazuje podstawowe informacje, aby zdefiniować działanie, które ma być kontynuowane, przy czym większe pakiety danych są synchronizowane za pośrednictwem usługi iCloud.

Na urządzeniu odbieranym użytkownik otrzyma powiadomienie, że działanie jest dostępne do kontynuacji. Jeśli użytkownik zdecyduje się kontynuować działanie na nowym urządzeniu, określona aplikacja zostanie uruchomiona (jeśli jeszcze nie jest uruchomiona), a ładunek z NSUserActivity niego zostanie użyty do ponownego uruchomienia działania.

An overview of Continuing User Activities

Tylko aplikacje, które współużytkują ten sam identyfikator zespołu deweloperów i odpowiadają na dany typ działania, kwalifikują się do kontynuacji. Aplikacja definiuje typy działań, które obsługuje w kluczu NSUserActivityTypespliku Info.plist . Biorąc pod uwagę to, ciągłe urządzenie wybiera aplikację do wykonania kontynuacji na podstawie identyfikatora zespołu, typu działania i opcjonalnie tytułu działania.

Aplikacja odbierającą używa informacji ze NSUserActivitysłownika w celu skonfigurowania UserInfo interfejsu użytkownika i przywrócenia stanu danego działania, aby przejście było bezproblemowe dla użytkownika końcowego.

Jeśli kontynuacja wymaga więcej informacji niż można wysłać wydajnie za pośrednictwem NSUserActivityaplikacji , wznawianie aplikacji może wysłać wywołanie do aplikacji źródłowej i ustanowić jeden lub więcej strumieni w celu przesłania wymaganych danych. Jeśli na przykład działanie edytowało duży dokument tekstowy z wieloma obrazami, przesyłanie strumieniowe będzie wymagane do przeniesienia informacji potrzebnych do kontynuowania działania na urządzeniu odbierającego. Aby uzyskać więcej informacji, zobacz sekcję Obsługa kontynuacji Strumienie poniżej.

Jak wspomniano powyżej, NSDocument aplikacje UIDocument oparte automatycznie mają wbudowaną obsługę przekazywania. Aby uzyskać więcej informacji, zobacz sekcję Obsługa przekazywania w aplikacjach opartych na dokumentach poniżej.

Klasa NSUserActivity

Klasa NSUserActivity jest obiektem podstawowym w wymianie handoff i służy do hermetyzacji stanu działania użytkownika, który jest dostępny do kontynuacji. Aplikacja utworzy wystąpienie kopii dowolnego obsługiwanego NSUserActivity działania i chce kontynuować na innym urządzeniu. Na przykład edytor dokumentów utworzy działanie dla każdego aktualnie otwartego dokumentu. Jednak tylko dokument z przodu (wyświetlany w najbardziej przednim oknie lub karcie) to bieżące działanie i dostępne dla kontynuacji.

Wystąpienie NSUserActivity klasy jest identyfikowane zarówno przez jego ActivityType właściwości, jak i Title . Właściwość słownika UserInfo służy do przenoszenia informacji o stanie działania. NeedsSave Ustaw właściwość na wartość true , jeśli chcesz opóźnić ładowanie informacji o stanie za pośrednictwem NSUserActivitydelegata . AddUserInfoEntries Użyj metody , aby scalić nowe dane z innych klientów do UserInfo słownika zgodnie z wymaganiami, aby zachować stan działania.

Klasa NSUserActivityDelegate

Element NSUserActivityDelegate służy do przechowywania informacji w NSUserActivityUserInfo słowniku aktualnym i zsynchronizowanym z bieżącym stanem działania. Gdy system wymaga zaktualizowania informacji w działaniu (na przykład przed kontynuacją na innym urządzeniu), wywołuje UserActivityWillSave metodę delegata.

Należy zaimplementować metodę UserActivityWillSave i wprowadzić wszelkie zmiany w NSUserActivity obiekcie (takim jak UserInfo, Titleitp.), aby upewnić się, że nadal odzwierciedla stan bieżącej aktywności. Gdy system wywołuje metodę UserActivityWillSave , flaga NeedsSave zostanie wyczyszczone. Jeśli zmodyfikujesz dowolne właściwości danych działania, musisz ponownie ustawić wartość NeedsSavetrue .

Zamiast używać przedstawionej UserActivityWillSave powyżej metody, możesz opcjonalnie automatycznie mieć UIKit aktywność użytkownika lub AppKit zarządzać nią. W tym celu ustaw właściwość obiektu odpowiadającego UserActivity i zaimplementuj metodę UpdateUserActivityState . Aby uzyskać więcej informacji, zobacz sekcję Pomocnicza przekazywanie w odpowiedziach poniżej.

Obsługa platformy aplikacji

Obie UIKit metody (iOS) i AppKit (OS X) zapewniają wbudowaną obsługę przekazywania w klasach NSDocument, responder (NSResponderUIResponder/) i .AppDelegate Chociaż każdy system operacyjny implementuje przekazywanie nieco inaczej, podstawowy mechanizm i interfejsy API są takie same.

Działania użytkownika w aplikacjach opartych na dokumentach

Aplikacje dla systemów iOS i OS X oparte na dokumentach automatycznie mają wbudowaną obsługę przekazywania. Aby aktywować tę obsługę, musisz dodać NSUbiquitousDocumentUserActivityType klucz i wartość dla każdego CFBundleDocumentTypes wpisu w pliku Info.plist aplikacji.

Jeśli ten klucz jest obecny, zarówno, jak NSDocument i UIDocument automatycznie utwórz NSUserActivity wystąpienia dla dokumentów opartych na usłudze iCloud określonego typu. Musisz podać typ działania dla każdego typu dokumentu obsługiwanego przez aplikację, a wiele typów dokumentów może używać tego samego typu działania. Zarówno, NSDocument jak i UIDocument automatycznie wypełniają UserInfo właściwość NSUserActivity właściwości wartością właściwości FileURL .

W systemie OS X NSUserActivity zarządzane przez AppKit i skojarzone z osobami odpowiadającymi automatycznie stają się bieżącym działaniem, gdy okno dokumentu stanie się głównym oknem. W systemie iOS w przypadku NSUserActivity obiektów zarządzanych przez UIKitprogram należy jawnie wywołać BecomeCurrent metodę lub ustawić właściwość dokumentu UserActivity na UIViewController pierwszym planie, gdy aplikacja pojawi się na pierwszym planie.

AppKit spowoduje automatyczne przywrócenie dowolnej UserActivity właściwości utworzonej w ten sposób w systemie OS X. Dzieje się tak, jeśli ContinueUserActivity metoda zwraca false wartość lub jeśli jest ona nieimplementowana. W takiej sytuacji dokument zostanie otwarty przy OpenDocument użyciu metody NSDocumentController , a następnie otrzyma RestoreUserActivityState wywołanie metody.

Aby uzyskać więcej informacji, zobacz sekcję Obsługa przekazywania w aplikacjach opartych na dokumentach poniżej.

Działania użytkowników i osoby reagujące

Zarówno UIKit działanie użytkownika, jak i AppKit może automatycznie zarządzać nim, jeśli ustawisz je jako właściwość obiektu odpowiadającego UserActivity . Jeśli stan został zmodyfikowany, należy ustawić NeedsSave właściwość obiektu odpowiadającego UserActivity na truewartość . System automatycznie zapisze UserActivity w razie potrzeby czas odpowiedzi, aby zaktualizować stan, wywołując jego UpdateUserActivityState metodę.

Jeśli wiele osób odpowiadających współużytkuje jedno NSUserActivity wystąpienie, otrzymują wywołanie UpdateUserActivityState zwrotne, gdy system aktualizuje obiekt aktywności użytkownika. Osoba odpowiadająca musi wywołać metodę AddUserInfoEntries w celu zaktualizowania NSUserActivitysłownika UserInfo w celu odzwierciedlenia bieżącego stanu działania w tym momencie. Słownik UserInfo jest czyszczone przed każdym UpdateUserActivityState wywołaniem.

Aby usunąć skojarzenie się z działania, obiekt odpowiadający może ustawić jego UserActivity właściwość na null. Jeśli wystąpienie zarządzane NSUserActivity platformy aplikacji nie ma więcej skojarzonych osób odpowiadających ani dokumentów, jest ono automatycznie unieważniane.

Aby uzyskać więcej informacji, zobacz sekcję Pomocnicza przekazywanie w odpowiedziach poniżej.

Działania użytkownika i element AppDelegate

AppDelegate Aplikacja jest podstawowym punktem wejścia podczas obsługi kontynuacji przekazywania. Gdy użytkownik odpowie na powiadomienie przekazanie, zostanie uruchomiona odpowiednia aplikacja (jeśli jeszcze nie jest uruchomiona), a WillContinueUserActivityWithType metoda AppDelegate metody zostanie wywołana. W tym momencie aplikacja powinna poinformować użytkownika o rozpoczęciu kontynuacji.

NSUserActivity Wystąpienie jest dostarczane po wywołaniu AppDelegatemetody .ContinueUserActivity W tym momencie należy skonfigurować interfejs użytkownika aplikacji i kontynuować daną aktywność.

Aby uzyskać więcej informacji, zobacz sekcję Implementowanie przekazywania poniżej.

Włączanie przekazywania w aplikacji platformy Xamarin

Ze względu na wymagania dotyczące zabezpieczeń nałożone przez handoff, aplikacja platformy Xamarin.iOS korzystająca z platformy Handoff musi być prawidłowo skonfigurowana zarówno w portalu dla deweloperów firmy Apple, jak i w pliku projektu Xamarin.iOS.

Należy wykonać następujące czynności:

  1. Zaloguj się do portalu dla deweloperów firmy Apple.

  2. Kliknij pozycję Certyfikaty, Identyfikatory i profile.

  3. Jeśli jeszcze tego nie zrobiono, kliknij pozycję Identyfikatory i utwórz identyfikator aplikacji (np. com.company.appname), a następnie edytuj istniejący identyfikator.

  4. Upewnij się, że usługa iCloud została sprawdzona dla danego identyfikatora:

    Enable the iCloud service for the given ID

  5. Zapisz zmiany.

  6. Kliknij pozycję Tworzenie profilów> aprowizacji i utwórz nowy profil aprowizacji programowania dla aplikacji:

    Create a new development provisioning profile for the app

  7. Pobierz i zainstaluj nowy profil aprowizacji lub użyj programu Xcode, aby pobrać i zainstalować profil.

  8. Edytuj opcje projektu platformy Xamarin.iOS i upewnij się, że używasz właśnie utworzonego profilu aprowizacji:

    Select the provisioning profile just created

  9. Następnie zmodyfikuj plik Info.plist i upewnij się, że używasz identyfikatora aplikacji użytego do utworzenia profilu aprowizacji:

    Set App ID

  10. Przewiń do sekcji Tryby tła i sprawdź następujące elementy:

    Enable the required background modes

  11. Zapisz zmiany we wszystkich plikach.

Po zastosowaniu tych ustawień aplikacja jest teraz gotowa do uzyskiwania dostępu do interfejsów API platformy Handoff Framework. Aby uzyskać szczegółowe informacje na temat aprowizacji, zobacz przewodniki Device Provisioning and Provisioning Your App (Aprowizowanie urządzeń i aprowizowanie aplikacji ).

Implementowanie przekazywania

Działania użytkowników można kontynuować wśród aplikacji podpisanych przy użyciu tego samego identyfikatora zespołu deweloperów i obsługiwać ten sam typ działania. Zaimplementowanie przekazywania w aplikacji platformy Xamarin.iOS wymaga utworzenia obiektu aktywności użytkownika (w systemie UIKit lub AppKit), zaktualizowania stanu obiektu w celu śledzenia działania i kontynuowania działania na urządzeniu odbierającego.

Identyfikowanie działań użytkownika

Pierwszym krokiem implementacji handoff jest zidentyfikowanie typów działań użytkownika, które obsługuje aplikacja, i zobaczenie, które z tych działań są dobrymi kandydatami do kontynuacji na innym urządzeniu. Na przykład: aplikacja ToDo może obsługiwać edytowanie elementów jako jeden typ działania użytkownika i obsługiwać przeglądanie listy dostępnych elementów jako innej.

Aplikacja może utworzyć dowolną liczbę typów aktywności użytkownika, która jest wymagana dla dowolnej funkcji, którą udostępnia aplikacja. Dla każdego typu działania użytkownika aplikacja musi śledzić, kiedy rozpoczyna się i kończy działanie typu, i musi zachować aktualne informacje o stanie, aby kontynuować to zadanie na innym urządzeniu.

Działania użytkownika mogą być kontynuowane w dowolnej aplikacji podpisanej przy użyciu tego samego identyfikatora zespołu bez żadnego mapowania jeden do jednego między wysyłaniem i odbieraniem aplikacji. Na przykład dana aplikacja może utworzyć cztery różne typy działań, które są używane przez różne, poszczególne aplikacje na innym urządzeniu. Jest to typowe wystąpienie między wersją aplikacji dla komputerów Mac (która może mieć wiele funkcji i funkcji) i aplikacjami systemu iOS, gdzie każda aplikacja jest mniejsza i koncentruje się na konkretnym zadaniu.

Tworzenie identyfikatorów typów działań

Identyfikator typu działania to krótki ciąg dodany do NSUserActivityTypes tablicy pliku Info.plist aplikacji używany do unikatowego identyfikowania danego typu działania użytkownika. W tablicy będzie znajdować się jeden wpis dla każdego działania obsługiwanego przez aplikację. Firma Apple sugeruje użycie odwrotnej notacji w stylu DNS dla identyfikatora typu działania, aby uniknąć kolizji. Na przykład: com.company-name.appname.activity w przypadku określonych działań opartych na aplikacji lub com.company-name.activity działań, które mogą być uruchamiane w wielu aplikacjach.

Identyfikator typu działania jest używany podczas tworzenia NSUserActivity wystąpienia do identyfikowania typu działania. Gdy działanie będzie kontynuowane na innym urządzeniu, typ działania (wraz z identyfikatorem zespołu aplikacji) określa, która aplikacja ma być uruchamiana, aby kontynuować działanie.

Na przykład utworzymy przykładową aplikację o nazwie MonkeyBrowser (pobierz tutaj). Ta aplikacja będzie wyświetlać cztery karty, z których każdy ma inny adres URL otwarty w widoku przeglądarki internetowej. Użytkownik będzie mógł kontynuować dowolną kartę na innym urządzeniu z systemem iOS z uruchomioną aplikacją.

Aby utworzyć wymagane identyfikatory typów działań do obsługi tego zachowania, zmodyfikuj plik Info.plist i przejdź do widoku Źródło . NSUserActivityTypes Dodaj klucz i utwórz następujące identyfikatory:

The NSUserActivityTypes key and required identifiers in the plist editor

Utworzyliśmy cztery nowe identyfikatory typów działań, po jednym dla każdej karty w przykładowej aplikacji MonkeyBrowser . Podczas tworzenia własnych aplikacji zastąp zawartość NSUserActivityTypes tablicy identyfikatorami typów działań specyficznymi dla działań, które obsługuje aplikacja.

Śledzenie zmian aktywności użytkownika

Podczas tworzenia nowego wystąpienia klasy określimy NSUserActivityDelegate wystąpienie NSUserActivity do śledzenia zmian stanu działania. Na przykład poniższy kod może służyć do śledzenia zmian stanu:

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
    }
}

Metoda jest wywoływana UserActivityReceivedData , gdy strumień kontynuacji odebrał dane z urządzenia wysyłającego. Aby uzyskać więcej informacji, zobacz sekcję Obsługa kontynuacji Strumienie poniżej.

Metoda jest wywoływana UserActivityWasContinued , gdy inne urządzenie przejęło działanie z bieżącego urządzenia. W zależności od typu działania, takiego jak dodanie nowego elementu do listy zadań do wykonania, aplikacja może wymagać przerwania działania na urządzeniu wysyłającym.

Metoda jest wywoływana UserActivityWillSave przed zapisaną i zsynchronizowaną ze wszystkimi zmianami działania na urządzeniach dostępnych lokalnie. Tej metody można użyć do wprowadzania jakichkolwiek zmian w ostatniej chwili we UserInfo właściwości NSUserActivity wystąpienia przed wysłaniem.

Tworzenie wystąpienia NSUserActivity

Każde działanie, które aplikacja chce zapewnić możliwość kontynuowania pracy na innym urządzeniu, musi być hermetyzowane w wystąpieniu NSUserActivity . Aplikacja może tworzyć dowolną liczbę działań, a charakter tych działań zależy od funkcjonalności i funkcji danej aplikacji. Na przykład aplikacja poczty e-mail może utworzyć jedno działanie do tworzenia nowej wiadomości, a drugie do czytania wiadomości.

W naszej przykładowej aplikacji jest tworzony nowy NSUserActivity za każdym razem, gdy użytkownik wprowadza nowy adres URL w jednym z kart widoku przeglądarki internetowej. Poniższy kod przechowuje stan danej karty:

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 ();

Tworzy nowy NSUserActivity przy użyciu jednego z utworzonych powyżej typów działań użytkownika i udostępnia czytelny dla człowieka tytuł działania. Dołącza ono do wystąpienia utworzonego NSUserActivityDelegate powyżej, aby obserwować zmiany stanu i informuje system iOS, że to działanie użytkownika jest bieżącym działaniem.

Wypełnianie słownika UserInfo

Jak widzieliśmy powyżej, UserInfo właściwość NSUserActivity klasy jest NSDictionary par klucz-wartość używana do definiowania stanu danego działania. Wartości przechowywane w pliku UserInfo muszą być jednym z następujących typów: NSArray, , NSData, NSDateNSNumberNSNullNSSetNSDictionaryNSStringlub .NSURL NSURL wartości danych, które wskazują dokumenty w usłudze iCloud, zostaną automatycznie dostosowane tak, aby wskazywały te same dokumenty na urządzeniu odbieranym.

W powyższym przykładzie utworzyliśmy NSMutableDictionary obiekt i wypełniliśmy go pojedynczym kluczem, podając adres URL, który był obecnie wyświetlany przez użytkownika na danej karcie. Metoda AddUserInfoEntries działania użytkownika została użyta do zaktualizowania działania przy użyciu danych, które zostaną użyte do przywrócenia działania na urządzeniu odbierającego:

// Update the activity when the tab's URL changes
var userInfo = new NSMutableDictionary ();
userInfo.Add (new NSString ("Url"), new NSString (url));
UserActivity.AddUserInfoEntries (userInfo);

Firma Apple sugeruje utrzymywanie informacji wysyłanych do najcięższego minimum, aby upewnić się, że działanie jest wysyłane w odpowiednim czasie do urządzenia odbierającego. Jeśli wymagane są większe informacje, takie jak obraz dołączony do dokumentu musi zostać wysłany, należy użyć Strumienie kontynuacji. Aby uzyskać więcej informacji, zobacz sekcję Obsługa kontynuacji Strumienie poniżej.

Kontynuowanie działania

Przekazywanie automatycznie informuje lokalne urządzenia z systemami iOS i OS X, które znajdują się w fizycznej odległości od urządzenia źródłowego i zalogowały się do tego samego konta w usłudze iCloud, o dostępności ciągłych działań użytkownika. Jeśli użytkownik zdecyduje się kontynuować działanie na nowym urządzeniu, system uruchomi odpowiednią aplikację (na podstawie identyfikatora zespołu i typu działania) i informacje, AppDelegate które muszą wystąpić kontynuacja.

Najpierw metoda jest wywoływana, aby aplikacja mogła poinformować użytkownika, WillContinueUserActivityWithType że kontynuacja ma się rozpocząć. W pliku AppDelegate.cs przykładowej aplikacji użyjemy następującego kodu, aby obsłużyć uruchamianie kontynuacji:

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;
}

W powyższym przykładzie każdy kontroler widoku rejestruje się w AppDelegate obiekcie i ma publiczną PreparingToHandoff metodę, która wyświetla wskaźnik aktywności i komunikat informujący użytkownika, że działanie ma zostać przekazane bieżącemu urządzeniu. Przykład:

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...");
}

Element ContinueUserActivity zostanie wezwany AppDelegate , aby rzeczywiście kontynuować daną aktywność. Ponownie z naszej przykładowej aplikacji:

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;
}

Publiczna PerformHandoff metoda każdego kontrolera widoku faktycznie preformuje przekazanie i przywraca działanie na bieżącym urządzeniu. W przypadku przykładu wyświetla ten sam adres URL na danej karcie, którą użytkownik przeglądał na innym urządzeniu. Przykład:

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 ();

}

Metoda ContinueUserActivity zawiera element UIApplicationRestorationHandler , który można wywołać w celu wznowienia działania opartego na dokumencie lub odpowiedzi. Po wywołaniu należy przekazać NSArray lub przywrócić obiekty do programu obsługi przywracania. Na przykład:

completionHandler (new NSObject[]{Tab4});

Dla każdego przekazanego obiektu zostanie wywołana jego RestoreUserActivityState metoda. Każdy obiekt może następnie używać danych w słowniku UserInfo do przywrócenia własnego stanu. Na przykład:

public override void RestoreUserActivityState (NSUserActivity activity)
{
    base.RestoreUserActivityState (activity);

    // Log activity
    Console.WriteLine ("Restoring Activity {0}", activity.Title);
}

W przypadku aplikacji opartych na dokumentach, jeśli nie implementujesz ContinueUserActivity metody lub zwraca falsewartość , UIKit lub AppKit może automatycznie wznowić działanie. Aby uzyskać więcej informacji, zobacz sekcję Obsługa przekazywania w aplikacjach opartych na dokumentach poniżej.

Niepowodzenie przekazywania w sposób wdzięczny

Ponieważ handoff opiera się na transmisji informacji między kolekcją luźno połączonych urządzeń z systemem iOS i OS X, proces transferu może czasami zakończyć się niepowodzeniem. Aplikacja powinna być zaprojektowana tak, aby obsługiwała te błędy bezpiecznie i informować użytkownika o wszelkich pojawiających się sytuacjach.

W przypadku awarii DidFailToContinueUserActivitiyAppDelegate metoda metody zostanie wywołana. Na przykład:

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);
}

Należy użyć podanej informacji NSError , aby przekazać użytkownikowi informacje o awarii.

Przekazywanie aplikacji natywnej do przeglądarki internetowej

Użytkownik może chcieć kontynuować działanie bez konieczności zainstalowania odpowiedniej aplikacji natywnej na żądanym urządzeniu. W niektórych sytuacjach interfejs internetowy może zapewniać wymagane funkcje, a działanie nadal może być kontynuowane. Na przykład konto e-mail użytkownika może zapewnić internetowy podstawowy interfejs użytkownika do komponowania i odczytywania wiadomości.

Jeśli źródło, aplikacja natywna zna adres URL interfejsu internetowego (i wymaganą składnię identyfikującą dany element, który jest kontynuowany), może zakodować te informacje we WebpageURL właściwości NSUserActivity wystąpienia. Jeśli urządzenie odbierające nie ma zainstalowanej odpowiedniej aplikacji natywnej do obsługi kontynuacji, można wywołać podany interfejs internetowy.

Przekazywanie przeglądarki internetowej do aplikacji natywnej

Jeśli użytkownik używał interfejsu internetowego na urządzeniu źródłowym, a aplikacja natywna w odbierającym urządzeniu twierdzi, że część WebpageURL domeny właściwości jest używana przez system, będzie używać tej aplikacji do obsługi kontynuacji. Nowe urządzenie otrzyma NSUserActivity wystąpienie, które oznacza typ działania jako BrowsingWeb i WebpageURL będzie zawierać adres URL odwiedzany przez użytkownika, UserInfo słownik będzie pusty.

Aby aplikacja brała udział w tym typie przekazywania, musi ona podawać domenę com.apple.developer.associated-domains w uprawnieniach w formacie <service>:<fully qualified domain name> (na przykład: activity continuation:company.com).

Jeśli określona domena pasuje do WebpageURL wartości właściwości, Handoff pobiera listę zatwierdzonych identyfikatorów aplikacji z witryny internetowej w tej domenie. Witryna internetowa musi podać listę zatwierdzonych identyfikatorów w podpisanym pliku JSON o nazwie apple-app-site-association (na przykład https://company.com/apple-app-site-association).

Ten plik JSON zawiera słownik, który określa listę identyfikatorów aplikacji w formularzu <team identifier>.<bundle identifier>. Na przykład:

{
    "activitycontinuation": {
        "apps": [    "YWBN8XTPBJ.com.company.FirstApp",
            "YWBN8XTPBJ.com.company.SecondApp" ]
    }
}

Aby podpisać plik JSON (tak, aby miał poprawność Content-Typeapplication/pkcs7-mime), użyj aplikacji Terminal i openssl polecenia z certyfikatem i kluczem wystawionym przez urząd certyfikacji zaufany przez system iOS (zobacz https://support.apple.com/kb/ht5012 listę). Na przykład:

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

Polecenie openssl generuje podpisany plik JSON umieszczany w witrynie internetowej pod adresem URL skojarzenia apple-app-site-association . Na przykład:

https://example.com/apple-app-site-association.

Aplikacja otrzyma wszelkie działania, których WebpageURL domena znajduje się w jej com.apple.developer.associated-domains upoważnieniu. http Obsługiwane są tylko protokoły ihttps. Każdy inny protokół zgłosi wyjątek.

Obsługa przekazywania w aplikacjach opartych na dokumentach

Jak wspomniano powyżej, w systemach iOS i OS X aplikacje oparte na dokumentach będą automatycznie obsługiwać przekazywanie dokumentów opartych na usłudze iCloud, jeśli plik Info.plist aplikacji zawiera CFBundleDocumentTypes klucz NSUbiquitousDocumentUserActivityType. Na przykład:

<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>

W tym przykładzie ciąg jest inicjatorem odwrotnej aplikacji DNS o nazwie dołączonego działania. W przypadku wprowadzenia w ten sposób wpisy typu działania nie muszą być powtarzane w NSUserActivityTypes tablicy pliku Info.plist .

Automatycznie utworzony obiekt aktywność użytkownika (dostępny za pośrednictwem właściwości dokumentu UserActivity ) może być przywoływały inne obiekty w aplikacji i używane do przywracania stanu kontynuacji. Na przykład w celu śledzenia zaznaczenia elementu i położenia dokumentu. Należy ustawić tę właściwość działań NeedsSave na true zawsze, gdy stan zmieni się i zaktualizuj UserInfo słownik w metodzie UpdateUserActivityState .

Właściwość UserActivity może być używana z dowolnego wątku i jest zgodna z protokołem obserwującym klucz-wartość (KVO), dzięki czemu może służyć do synchronizowania dokumentu podczas przemieszczania się i z usługi iCloud. Właściwość UserActivity zostanie unieważniona po zamknięciu dokumentu.

Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą działań użytkowników firmy Apple w dokumentacji aplikacji opartych na dokumentach .

Obsługa przekazywania w osobach odpowiadających

Można skojarzyć osoby reagujące (dziedziczone z UIResponder systemu iOS lub NSResponder OS X) do działań, ustawiając ich UserActivity właściwości. System automatycznie zapisuje UserActivity właściwość w odpowiednim czasie, wywołując metodę obiektu UpdateUserActivityState odpowiadającego w celu dodania bieżących danych do obiektu Aktywność użytkownika przy użyciu AddUserInfoEntriesFromDictionary metody .

Obsługa Strumienie kontynuacji

Mogą to być sytuacje, w których ilość informacji wymaganych do kontynuowania działania nie może być wydajnie przenoszona przez początkowy ładunek przekazywania. W takich sytuacjach aplikacja odbierającą może ustanowić jeden lub więcej strumienia między samą aplikacją a aplikacją źródłową w celu transferu danych.

Aplikacja źródłowa ustawi SupportsContinuationStreams właściwość NSUserActivity wystąpienia na true. Na przykład:

// 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 ();

Aplikacja odbierający może następnie wywołać metodę GetContinuationStreamsNSUserActivity w pliku AppDelegate , aby ustanowić strumień. Na przykład:

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;
}

Na urządzeniu źródłowym delegat aktywności użytkownika odbiera strumienie, wywołując jego DidReceiveInputStream metodę w celu dostarczenia żądanych danych w celu kontynuowania aktywności użytkownika na wznawiającym urządzeniu.

Użyjesz elementu , NSInputStream aby zapewnić dostęp tylko do odczytu do danych strumieniowych i NSOutputStream zapewnić dostęp tylko do zapisu. Strumienie powinny być używane w sposób żądania i odpowiedzi, gdzie odbierana aplikacja żąda większej ilości danych, a źródłową aplikację ją udostępnia. Tak więc dane zapisane w strumieniu wyjściowym na urządzeniu źródłowym są odczytywane ze strumienia wejściowego na urządzeniu kontynuowanym i odwrotnie.

Nawet w sytuacjach, w których wymagany jest strumień kontynuacji, komunikacja między dwiema aplikacjami powinna być minimalna.

Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą korzystania z kontynuacji Strumienie firmy Apple.

Najlepsze rozwiązania dotyczące przekazywania

Pomyślna implementacja bezproblemowej kontynuacji działania użytkownika za pośrednictwem przekazywania wymaga starannego projektowania ze względu na wszystkie zaangażowane składniki. Firma Apple sugeruje wdrożenie najlepszych rozwiązań dotyczących aplikacji obsługujących przekazywanie:

  • Zaprojektuj działania użytkownika, aby wymagać najmniejszego ładunku możliwego do powiązania stanu działania, aby były kontynuowane. Większy ładunek, tym dłużej trwa kontynuowanie.
  • Jeśli musisz przenieść duże ilości danych w celu pomyślnej kontynuacji, weź pod uwagę koszty związane z konfiguracją i obciążeniem sieci.
  • Duża aplikacja dla komputerów Mac często tworzy działania użytkownika obsługiwane przez kilka mniejszych aplikacji specyficznych dla zadań na urządzeniach z systemem iOS. Różne wersje aplikacji i systemu operacyjnego powinny być zaprojektowane tak, aby działały dobrze lub bezproblemowo.
  • Podczas określania typów działań użyj notacji odwrotnej DNS, aby uniknąć kolizji. Jeśli działanie jest specyficzne dla danej aplikacji, jej nazwa powinna zostać uwzględniona w definicji typu (na przykład com.myCompany.myEditor.editing). Jeśli działanie może działać w wielu aplikacjach, upuść nazwę aplikacji z definicji (na przykład com.myCompany.editing).
  • Jeśli aplikacja musi zaktualizować stan działania użytkownika (NSUserActivity) ustaw NeedsSave właściwość na true. W odpowiednim czasie funkcja Handoff wywoła metodę delegata UserActivityWillSave , aby można było zaktualizować UserInfo słownik zgodnie z potrzebami.
  • Ponieważ proces przekazywania może nie być natychmiast inicjowany na urządzeniu odbierającego, należy zaimplementować AppDelegates WillContinueUserActivity i poinformować użytkownika, że kontynuacja ma się rozpocząć.

Przykładowa aplikacja do przekazywania

Jako przykład użycia funkcji Handoff w aplikacji platformy Xamarin.iOS dołączyliśmy przykładową aplikację MonkeyBrowser z tym przewodnikiem. Aplikacja ma cztery karty, których użytkownik może użyć do przeglądania internetu, z których każdy ma określony typ działania: Pogoda, Ulubione, Przerwy na kawę i Praca.

Na dowolnej karcie, gdy użytkownik wprowadzi nowy adres URL i naciśnie przycisk Przejdź , zostanie utworzona nowa NSUserActivity karta zawierająca adres URL aktualnie przeglądający:

Example Handoff App

Jeśli na innym urządzeniu użytkownika jest zainstalowana aplikacja MonkeyBrowser , jest zalogowany do usługi iCloud przy użyciu tego samego konta użytkownika, znajduje się w tej samej sieci i blisko powyższego urządzenia, na ekranie głównym zostanie wyświetlone działanie przekazywania (w lewym dolnym rogu):

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

Jeśli użytkownik przeciągnie w górę ikonę Przekazywanie, aplikacja zostanie uruchomiona, a działanie użytkownika określone w elemecie NSUserActivity będzie kontynuowane na nowym urządzeniu:

The User Activity continued on the new device

Gdy działanie użytkownika zostało pomyślnie wysłane do innego urządzenia Firmy Apple, urządzenie NSUserActivity wysyłające otrzyma wywołanie UserActivityWasContinued metody na nim NSUserActivityDelegate , aby poinformować go, że działanie użytkownika zostało pomyślnie przeniesione na inne urządzenie.

Podsumowanie

W tym artykule przedstawiono wprowadzenie do platformy Handoff używanej do kontynuowania aktywności użytkownika między wieloma urządzeniami firmy Apple użytkownika. Następnie pokazano, jak włączyć i zaimplementować przekazywanie w aplikacji platformy Xamarin.iOS. Na koniec omówiła różne typy dostępnych kontynuacji handoff i najlepsze rozwiązania dotyczące przekazywania.