Übergabe in Xamarin.iOS

In diesem Artikel wird die Arbeit mit Handoff in einer Xamarin.iOS-App behandelt, um Benutzeraktivitäten zwischen Apps zu übertragen, die auf den anderen Geräten des Benutzers ausgeführt werden.

Apple hat Handoff in iOS 8 und OS X Yosemite (10.10) eingeführt, um einen gemeinsamen Mechanismus zu schaffen, mit dem der Benutzer*innen Aktivitäten, die sie auf einem ihrer Geräte begonnen haben, auf ein anderes Gerät übertragen können, auf dem die gleiche App oder eine andere App läuft, die dieselbe Aktivität unterstützt.

An example of performing a Handoff operation

In diesem Artikel wird die Aktivierung der Aktivitätsfreigabe in einer Xamarin.iOS-App schnell erläutert und das Handoff-Framework ausführlich behandelt:

Informationen zur Übergabe

Handoff (auch bekannt als Kontinuität) wurde von Apple in iOS 8 und OS X Yosemite (10.10) eingeführt, damit Benutzer*innen eine Aktivität auf einem ihrer Geräte (entweder iOS oder Mac) starten und diese Aktivität auf einem anderen ihrer Geräte (wie durch das iCloud-Konto der Benutzer*innen identifiziert) fortsetzen können.

Handoff wurde in iOS 9 erweitert, um auch neue, erweiterte Suchfunktionen zu unterstützen. Weitere Informationen finden Sie in unserer Dokumentation zu Suchverbesserungen.

Beispielsweise kann der Benutzer eine E-Mail auf dem i Telefon starten und die E-Mail auf dem Mac nahtlos fortsetzen, wobei alle gleichen Nachrichteninformationen ausgefüllt sind und sich der Cursor an derselben Stelle befindet, an der sie in iOS verbleibt.

Jede Ihrer Apps, die dieselbe Team-ID gemeinsam nutzen, ist berechtigt, die Benutzeraktivitäten über Apps hinweg fortzusetzen, solange diese App entweder über den iTunes App Store übermittelt oder von einem registrierten Entwickler (für Mac- oder Enterprise- oder Ad-Hoc-Apps) signiert wurde.

Alle NSDocument oder UIDocument basierte Apps verfügen automatisch über integrierte Handoff-Unterstützung und erfordern minimale Änderungen zur Unterstützung von Handoff.

Fortsetzen von Benutzeraktivitäten

Die NSUserActivity Klasse (zusammen mit einigen kleinen Änderungen UIKit an und AppKit) bietet Unterstützung für die Definition der Benutzeraktivität, die möglicherweise auf einem anderen Gerät des Benutzers fortgesetzt werden kann.

Damit eine Aktivität an eine andere der Geräte des Benutzers übergeben werden kann, muss sie in einer Instanz NSUserActivitygekapselt werden, die als "Aktuelle Aktivität" gekennzeichnet ist, die Nutzlast festgelegt ist (die Zum Ausführen der Fortsetzung verwendeten Daten), und die Aktivität muss dann an dieses Gerät übertragen werden.

Handoff übergibt das minimale Minimum an Informationen, um die Aktivität zu definieren, die fortgesetzt werden soll, wobei größere Datenpakete über iCloud synchronisiert werden.

Auf dem empfangenden Gerät erhält der Benutzer eine Benachrichtigung, dass eine Aktivität für die Fortsetzung verfügbar ist. Wenn der Benutzer die Aktivität auf dem neuen Gerät fortsetzen möchte, wird die angegebene App gestartet (sofern noch nicht ausgeführt), und die Nutzlast wird NSUserActivity verwendet, um die Aktivität neu zu starten.

An overview of Continuing User Activities

Nur Apps, die dieselbe Entwicklerteam-ID gemeinsam nutzen und auf einen bestimmten Aktivitätstyp reagieren, sind für die Fortsetzung berechtigt. Eine App definiert die Aktivitätstypen, die sie unter dem NSUserActivityTypes Schlüssel der Info.plist-Datei unterstützt. In diesem Fall wählt ein fortlaufendes Gerät die App aus, um die Fortsetzung basierend auf der Team-ID, dem Aktivitätstyp und optional dem Aktivitätstitel auszuführen.

Die empfangende App verwendet Informationen aus dem NSUserActivityUserInfo Wörterbuch, um die Benutzeroberfläche zu konfigurieren und den Status der angegebenen Aktivität wiederherzustellen, sodass der Übergang für den Endbenutzer nahtlos erscheint.

Wenn für die Fortsetzung mehr Informationen erforderlich sind, als effizient über eine NSUserActivityApp gesendet werden können, kann die fortgesetzte App einen Aufruf an die Ursprungs-App senden und einen oder mehrere Datenströme einrichten, um die erforderlichen Daten zu übertragen. Wenn die Aktivität z. B. ein großes Textdokument mit mehreren Bildern bearbeitet hat, wäre streaming erforderlich, um die erforderlichen Informationen zu übertragen, um die Aktivität auf dem empfangenden Gerät fortzusetzen. Weitere Informationen finden Sie im Abschnitt "Unterstützende Fortsetzungsstreams " weiter unten.

Wie oben erwähnt, NSDocument oder UIDocument basierende Apps verfügen automatisch über integrierte Handoff-Unterstützung. Weitere Informationen finden Sie im Abschnitt "Unterstützende Übergabe in dokumentbasierten Apps " weiter unten.

Die NSUserActivity-Klasse

Die NSUserActivity Klasse ist das primäre Objekt in einem Handoff-Austausch und wird verwendet, um den Status einer Benutzeraktivität zu kapseln, die für die Fortsetzung verfügbar ist. Eine App instanziiert eine Kopie aller NSUserActivity unterstützten Aktivitäten und möchte auf einem anderen Gerät fortfahren. Beispielsweise würde der Dokument-Editor eine Aktivität für jedes derzeit geöffnete Dokument erstellen. Es ist jedoch nur das oberste Dokument (im vordersten Fenster oder tab) die aktuelle Aktivität und steht für die Fortsetzung zur Verfügung.

Eine Instanz von NSUserActivity wird sowohl durch ihre eigenschaften Title als auch durch sie ActivityType identifiziert. Die UserInfo Wörterbucheigenschaft wird verwendet, um Informationen zum Status der Aktivität zu übertragen. Legen Sie die NeedsSave Eigenschaft auf true fest, wenn Sie die Statusinformationen über die NSUserActivityStellvertretung laden möchten. Verwenden Sie die AddUserInfoEntries Methode, um neue Daten aus anderen Clients nach Bedarf in das UserInfo Wörterbuch zusammenzuführen, um den Status der Aktivität beizubehalten.

Die NSUserActivityDelegate-Klasse

Dies NSUserActivityDelegate wird verwendet, um Informationen in einem NSUserActivityWörterbuch UserInfo auf dem neuesten Stand zu halten und mit dem aktuellen Status der Aktivität zu synchronisieren. Wenn das System die Informationen in der Aktivität aktualisiert werden muss (z. B. vor der Fortsetzung auf einem anderen Gerät), ruft es die UserActivityWillSave Methode des Delegaten auf.

Sie müssen die UserActivityWillSave Methode implementieren und änderungen an den NSUserActivity Änderungen vornehmen (z UserInfo. B. , Titleusw.), um sicherzustellen, dass sie weiterhin den Status der aktuellen Aktivität widerspiegelt. Wenn das System die UserActivityWillSave Methode aufruft, wird das NeedsSave Flag gelöscht. Wenn Sie eine der Dateneigenschaften der Aktivität ändern, müssen Sie sie erneut festlegen NeedsSavetrue .

Statt die UserActivityWillSave oben dargestellte Methode zu verwenden, können Sie optional die Benutzeraktivität automatisch verwenden UIKit oder AppKit verwalten. Legen Sie dazu die Eigenschaft des Responderobjekts UserActivity fest, und implementieren Sie die UpdateUserActivityState Methode. Weitere Informationen finden Sie im Abschnitt "Unterstützende Übergabe in Responders".

App-Framework-Unterstützung

Sowohl (iOS) als AppKit auch UIKit (OS X) bieten integrierte Unterstützung für Handoff in den NSDocumentKlassen , Responder (UIResponder/NSResponder) und AppDelegate Klassen. Während jedes Betriebssystem Handoff etwas anders implementiert, sind der grundlegende Mechanismus und die APIs identisch.

Benutzeraktivitäten in dokumentbasierten Apps

Dokumentbasierte iOS- und OS X-Apps verfügen automatisch über integrierte Handoff-Unterstützung. Um diese Unterstützung zu aktivieren, müssen Sie für jeden Eintrag in der Datei "Info.plist" der App einen NSUbiquitousDocumentUserActivityType Schlüssel und einen CFBundleDocumentTypes Wert hinzufügen.

Wenn dieser Schlüssel vorhanden ist, erstellen NSUserActivity Sie sowohl Instanzen NSDocumentUIDocument für iCloud-basierte Dokumente des angegebenen Typs als auch automatisch. Sie müssen einen Aktivitätstyp für jeden Dokumenttyp bereitstellen, den die App unterstützt, und mehrere Dokumenttypen können denselben Aktivitätstyp verwenden. UIDocument Sowohl die Eigenschaft als auch NSDocument die UserInfo Eigenschaft automatisch mit dem NSUserActivity Wert ihrer FileURL Eigenschaft auffüllen.

Unter OS X wird die NSUserActivity verwaltete AppKit und den Antwortenden zugeordnete Aktivität automatisch zur aktuellen Aktivität, wenn das Fenster des Dokuments zum Standard-Fenster wird. Unter iOS müssen Sie für NSUserActivity Objekte, die von UIKitverwalteten Objekten verwaltet werden, entweder explizit aufrufen BecomeCurrent oder die Eigenschaft des UserActivity Dokuments auf eine UIViewController Festgelegte festlegen, wenn die App in den Vordergrund kommt.

AppKit stellt alle UserActivity auf os X erstellten Eigenschaften automatisch wieder her. Dies tritt auf, wenn die ContinueUserActivity Methode zurückgegeben false wird oder nicht implementiert ist. In diesem Fall wird das Dokument mit der OpenDocument Methode des NSDocumentController Dokuments geöffnet und empfängt dann einen RestoreUserActivityState Methodenaufruf.

Weitere Informationen finden Sie im Abschnitt "Unterstützende Übergabe in dokumentbasierten Apps".

Benutzeraktivitäten und Antwortende

Beide und UIKitAppKit können eine Benutzeraktivität automatisch verwalten, wenn Sie sie als Eigenschaft eines UserActivity Responder-Objekts festlegen. Wenn der Zustand geändert wurde, müssen Sie die NeedsSave Eigenschaft des Antwortenden UserActivity auf festlegen true. Das System speichert den UserActivity erforderlichen Zeitpunkt automatisch, nachdem der Antwortende Zeit zum Aktualisieren des Zustands durch Aufrufen der UpdateUserActivityState Methode erhalten hat.

Wenn mehrere Antwortende eine einzelne NSUserActivity Instanz freigeben, erhalten sie einen UpdateUserActivityState Rückruf, wenn das System das Benutzeraktivitätsobjekt aktualisiert. Der Responder muss die AddUserInfoEntries Methode aufrufen, um das NSUserActivityWörterbuch zu aktualisieren, um den aktuellen Aktivitätsstatus UserInfo an diesem Punkt widerzuspiegeln. Das UserInfo Wörterbuch wird vor jedem UpdateUserActivityState Anruf gelöscht.

Um sich von einer Aktivität zu trennen, kann ein Responder seine UserActivity Eigenschaft auf nullfestlegen. Wenn eine verwaltete NSUserActivity Instanz eines App-Frameworks keine weiteren antwortenden Personen oder Dokumente enthält, wird sie automatisch ungültig.

Weitere Informationen finden Sie im Abschnitt "Unterstützende Übergabe in Responders".

Benutzeraktivitäten und appDelegate

Die App ist AppDelegate der primäre Einstiegspunkt bei der Behandlung einer Handoff-Fortsetzung. Wenn der Benutzer auf eine Handoff-Benachrichtigung antwortet, wird die entsprechende App gestartet (sofern noch nicht ausgeführt), und die WillContinueUserActivityWithType Methode der AppDelegate App wird aufgerufen. An diesem Punkt sollte die App den Benutzer darüber informieren, dass die Fortsetzung gestartet wird.

Die NSUserActivity Instanz wird übermittelt, wenn die AppDelegateMethode ContinueUserActivity aufgerufen wird. Zu diesem Zeitpunkt sollten Sie die Benutzeroberfläche der App konfigurieren und die angegebene Aktivität fortsetzen.

Weitere Informationen finden Sie im Abschnitt "Implementieren von Handoff" weiter unten.

Aktivieren der Übergabe in einer Xamarin-App

Aufgrund der von Handoff auferlegten Sicherheitsanforderungen muss eine Xamarin.iOS-App, die das Handoff-Framework verwendet, sowohl im Apple Developer Portal als auch in der Xamarin.iOS-Projektdatei ordnungsgemäß konfiguriert sein.

Gehen Sie folgendermaßen vor:

  1. Melden Sie sich beim Apple Developer Portal an.

  2. Klicken Sie auf Zertifikate, Bezeichner und Profile.

  3. Wenn Sie dies noch nicht getan haben, klicken Sie auf Bezeichner , und erstellen Sie eine ID für Ihre App (z. B. com.company.appname), sonst bearbeiten Sie Ihre vorhandene ID.

  4. Stellen Sie sicher, dass der iCloud-Dienst auf die angegebene ID überprüft wurde:

    Enable the iCloud service for the given ID

  5. Speichern Sie die Änderungen.

  6. Klicken Sie auf die Entwicklung von Bereitstellungsprofilen>, und erstellen Sie ein neues Entwicklungsbereitstellungsprofil für Ihre App:

    Create a new development provisioning profile for the app

  7. Laden Sie entweder das neue Bereitstellungsprofil herunter, und installieren Sie es mit Xcode, um das Profil herunterzuladen und zu installieren.

  8. Bearbeiten Sie Ihre Xamarin.iOS-Projektoptionen, und stellen Sie sicher, dass Sie das soeben erstellte Bereitstellungsprofil verwenden:

    Select the provisioning profile just created

  9. Bearbeiten Sie als Nächstes Ihre Info.plist-Datei , und stellen Sie sicher, dass Sie die App-ID verwenden, die zum Erstellen des Bereitstellungsprofils verwendet wurde:

    Set App ID

  10. Scrollen Sie zum Abschnitt "Hintergrundmodi" , und überprüfen Sie die folgenden Elemente:

    Enable the required background modes

  11. Speichern Sie die Änderungen an allen Dateien.

Mit diesen Einstellungen ist die Anwendung jetzt bereit, auf die Handoff Framework-APIs zuzugreifen. Ausführliche Informationen zur Bereitstellung finden Sie in unseren Leitfäden zur Gerätebereitstellung und -bereitstellung.

Implementieren von Handoff

Benutzeraktivitäten können unter Apps fortgesetzt werden, die mit derselben Entwicklerteam-ID signiert sind und denselben Aktivitätstyp unterstützen. Die Implementierung von Handoff in einer Xamarin.iOS-App erfordert, dass Sie ein Benutzeraktivitätsobjekt (entweder in UIKit oder AppKit), den Status des Objekts aktualisieren, um die Aktivität nachzuverfolgen und die Aktivität auf einem empfangenden Gerät fortzusetzen.

Identifizieren von Benutzeraktivitäten

Der erste Schritt bei der Implementierung von Handoff besteht darin, die Arten von Benutzeraktivitäten zu identifizieren, die Ihre App unterstützt, und zu sehen, welche dieser Aktivitäten für die Fortsetzung auf einem anderen Gerät geeignet sind. Beispiel: Eine ToDo-App kann die Bearbeitung von Elementen als einen Benutzeraktivitätstyp unterstützen und das Durchsuchen der liste verfügbarer Elemente als eine andere unterstützen.

Eine App kann beliebig viele Benutzeraktivitätstypen erstellen, eine für jede funktion, die die App bereitstellt. Für jeden Benutzeraktivitätstyp muss die App nachverfolgen, wann eine Aktivität des Typs beginnt und endet, und muss aktuelle Statusinformationen Standard beibehalten, um diese Aufgabe auf einem anderen Gerät fortzusetzen.

Benutzeraktivitäten können für jede App fortgesetzt werden, die mit derselben Team-ID signiert ist, ohne eine 1:1-Zuordnung zwischen dem Senden und Empfangen von Apps durchzuführen. Beispielsweise kann eine bestimmte App vier verschiedene Arten von Aktivitäten erstellen, die von verschiedenen, einzelnen Apps auf einem anderen Gerät genutzt werden. Dies ist ein häufiges Vorkommen zwischen einer Mac-Version der App (die möglicherweise über viele Features und Funktionen verfügt) und iOS-Apps, bei denen jede App kleiner ist und sich auf eine bestimmte Aufgabe konzentriert.

Erstellen von Aktivitätstypbezeichnern

Der Aktivitätstypbezeichner ist eine kurze Zeichenfolge, die dem NSUserActivityTypes Array der Info.plist-Datei der App hinzugefügt wird, die verwendet wird, um einen bestimmten Benutzeraktivitätstyp eindeutig zu identifizieren. Es gibt einen Eintrag im Array für jede Aktivität, die die App unterstützt. Apple schlägt vor, eine Reverse-DNS-Schreibweise für den Aktivitätstypbezeichner zu verwenden, um Kollisionen zu vermeiden. Beispiel: com.company-name.appname.activity für bestimmte appbasierte Aktivitäten oder com.company-name.activity für Aktivitäten, die über mehrere Apps hinweg ausgeführt werden können.

Der Aktivitätstypbezeichner wird beim Erstellen einer NSUserActivity Instanz verwendet, um den Aktivitätstyp zu identifizieren. Wenn eine Aktivität auf einem anderen Gerät fortgesetzt wird, bestimmt der Aktivitätstyp (zusammen mit der Team-ID der App), welche App gestartet werden soll, um die Aktivität fortzusetzen.

Als Beispiel erstellen wir eine Beispiel-App namens MonkeyBrowser (hier herunterladen). Diese App stellt vier Registerkarten dar, wobei jeweils eine andere URL in einer Webbrowseransicht geöffnet ist. Der Benutzer kann jede Registerkarte auf einem anderen iOS-Gerät fortsetzen, auf dem die App ausgeführt wird.

Um die erforderlichen Aktivitätstypbezeichner zu erstellen, um dieses Verhalten zu unterstützen, bearbeiten Sie die Info.plist-Datei , und wechseln Sie zur Quellansicht . Fügen Sie einen NSUserActivityTypes Schlüssel hinzu, und erstellen Sie die folgenden Bezeichner:

The NSUserActivityTypes key and required identifiers in the plist editor

Wir haben vier neue Aktivitätstyp-IDs erstellt, eine für jede der Registerkarten in der Beispiel-MonkeyBrowser-App. Ersetzen Sie beim Erstellen Ihrer eigenen Apps den Inhalt des NSUserActivityTypes Arrays durch die Aktivitätstypbezeichner, die für die von Ihrer App unterstützten Aktivitäten spezifisch sind.

Nachverfolgen von Benutzeraktivitätsänderungen

Wenn wir eine neue Instanz der NSUserActivity Klasse erstellen, geben wir eine NSUserActivityDelegate Instanz an, um Änderungen am Status der Aktivität nachzuverfolgen. Beispielsweise kann der folgende Code verwendet werden, um Zustandsänderungen nachzuverfolgen:

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

Die UserActivityReceivedData Methode wird aufgerufen, wenn ein Fortsetzungsstream Daten von einem sendenden Gerät empfangen hat. Weitere Informationen finden Sie im Abschnitt "Unterstützende Fortsetzungsstreams " weiter unten.

Die UserActivityWasContinued Methode wird aufgerufen, wenn ein anderes Gerät eine Aktivität vom aktuellen Gerät übernommen hat. Je nach Aktivitätstyp, z. B. dem Hinzufügen eines neuen Elements zu einer ToDo-Liste, muss die App möglicherweise die Aktivität auf dem sendenden Gerät abbrechen.

Die UserActivityWillSave Methode wird aufgerufen, bevor Änderungen an der Aktivität gespeichert und auf lokal verfügbaren Geräten synchronisiert werden. Mit dieser Methode können Sie alle letzten Minutenänderungen an der UserInfo Eigenschaft der NSUserActivity Instanz vornehmen, bevor sie gesendet wird.

Erstellen einer NSUserActivity-Instanz

Jede Aktivität, die Ihre App bereitstellen möchte, muss in einer NSUserActivity Instanz gekapselt werden. Die App kann beliebig viele Aktivitäten erstellen, und die Art dieser Aktivitäten hängt von der Funktionalität und den Features der betreffenden App ab. Beispielsweise kann eine E-Mail-App eine Aktivität zum Erstellen einer neuen Nachricht und eine andere zum Lesen einer Nachricht erstellen.

Für unsere Beispiel-App wird jedes Mal eine neue NSUserActivity URL erstellt, wenn der Benutzer eine neue URL in einer der Webbrowseransicht im Registerkartenformat eingibt. Der folgende Code speichert den Status einer bestimmten Registerkarte:

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

Es erstellt eine neue NSUserActivity Verwendung des oben erstellten Benutzeraktivitätstyps und stellt einen lesbaren Titel für die Aktivität bereit. Es wird an eine Instanz der NSUserActivityDelegate oben erstellten Instanz angefügt, um auf Zustandsänderungen zu achten und iOS darüber zu informieren, dass diese Benutzeraktivität die aktuelle Aktivität ist.

Auffüllen des UserInfo-Wörterbuchs

Wie oben gezeigt, ist die UserInfo Eigenschaft der NSUserActivity Klasse ein NSDictionary Schlüsselwertpaar, das zum Definieren des Zustands einer bestimmten Aktivität verwendet wird. Die gespeicherten UserInfo Werte müssen einen der folgenden Typen aufweisen: NSArray, , NSData, NSDate, NSDictionary, NSNull, NSNumber, , NSSet, NSStringoder NSURL. NSURL Datenwerte, die auf iCloud-Dokumente verweisen, werden automatisch angepasst, sodass sie auf dieselben Dokumente auf einem empfangenden Gerät verweisen.

Im obigen Beispiel haben wir ein NSMutableDictionary Objekt erstellt und mit einem einzelnen Schlüssel aufgefüllt, der die URL angibt, die der Benutzer aktuell auf der angegebenen Registerkarte anzeigte. Die AddUserInfoEntries Methode der Benutzeraktivität wurde verwendet, um die Aktivität mit den Daten zu aktualisieren, die zum Wiederherstellen der Aktivität auf dem empfangenden Gerät verwendet werden:

// 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 schlägt vor, die informationen so gering wie möglich zu halten, um sicherzustellen, dass die Aktivität rechtzeitig an das empfangende Gerät gesendet wird. Wenn größere Informationen erforderlich sind, z. B. ein an ein Dokument angefügtes Bild, das bearbeitet werden muss, sollten Sie Fortsetzungsstreams verwenden. Weitere Informationen finden Sie im Abschnitt "Unterstützende Fortsetzungsstreams" weiter unten.

Fortsetzen einer Aktivität

Handoff informiert automatisch lokale iOS- und OS X-Geräte, die sich in physischer Nähe zum ursprünglichen Gerät befinden und bei demselben iCloud-Konto angemeldet sind, über die Verfügbarkeit von zusammenhängenden Benutzeraktivitäten. Wenn der Benutzer eine Aktivität auf einem neuen Gerät fortsetzen möchte, startet das System die entsprechende App (basierend auf der Team-ID und dem Aktivitätstyp) und informationen AppDelegate darüber, dass die Fortsetzung erfolgen muss.

Zunächst wird die WillContinueUserActivityWithType Methode aufgerufen, damit die App den Benutzer darüber informieren kann, dass die Fortsetzung beginnen soll. Wir verwenden den folgenden Code in der AppDelegate.cs Datei unserer Beispiel-App, um einen Fortsetzungsstart zu behandeln:

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

Im obigen Beispiel registriert sich jeder Ansichtscontroller mit der und verfügt über eine öffentliche PreparingToHandoff Methode, mit der AppDelegate ein Aktivitätsindikator angezeigt wird, und eine Meldung, die dem Benutzer darüber informiert, dass die Aktivität an das aktuelle Gerät übergeben werden soll. Beispiel:

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 Der ContinueUserActivity Wille wird aufgerufen, die angegebene Aktivität tatsächlich fortzusetzen. Erneut aus unserer Beispiel-App:

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

Die öffentliche PerformHandoff Methode jedes Ansichtscontrollers stellt die Übergabe tatsächlich vor und stellt die Aktivität auf dem aktuellen Gerät wieder her. Im Fall des Beispiels wird dieselbe URL auf einer bestimmten Registerkarte angezeigt, die der Benutzer auf einem anderen Gerät durchsucht hat. Beispiel:

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

}

Die ContinueUserActivity Methode enthält eine UIApplicationRestorationHandler Methode, die Sie für die Fortsetzung der dokument- oder responder-basierten Aktivität aufrufen können. Sie müssen beim Aufrufen ein NSArray oder wiederherstellbare Objekte an den Wiederherstellungshandler übergeben. Zum Beispiel:

completionHandler (new NSObject[]{Tab4});

Für jedes übergebene Objekt wird seine RestoreUserActivityState Methode aufgerufen. Jedes Objekt kann dann die Daten im UserInfo Wörterbuch verwenden, um seinen eigenen Zustand wiederherzustellen. Zum Beispiel:

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

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

Bei dokumentbasierten Apps, wenn Sie die ContinueUserActivity Methode nicht implementieren oder diese zurückgeben false, UIKit oder AppKit die Aktivität automatisch fortsetzen können. Weitere Informationen finden Sie im Abschnitt "Unterstützende Übergabe in dokumentbasierten Apps".

Fehlerhafte Übergabe ordnungsgemäß

Da Handoff auf die Übertragung von Informationen zwischen einer Sammlung lose angeschlossenen iOS- und OS X-Geräten beruht, kann der Übertragungsprozess manchmal fehlschlagen. Sie sollten Ihre App so entwerfen, dass diese Fehler ordnungsgemäß behandelt werden, und den Benutzer über situationen informieren, die auftreten.

Im Falle eines Fehlers wird die DidFailToContinueUserActivitiy Methode der AppDelegate Methode aufgerufen. Zum Beispiel:

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

Sie sollten die bereitgestellten NSError Informationen verwenden, um dem Benutzer Informationen über den Fehler bereitzustellen.

Native App in Webbrowser Handoff

Ein Benutzer möchte möglicherweise eine Aktivität fortsetzen, ohne eine entsprechende systemeigene App auf dem gewünschten Gerät installiert zu haben. In einigen Fällen kann eine webbasierte Schnittstelle die erforderliche Funktionalität bereitstellen, und die Aktivität kann weiterhin fortgesetzt werden. Beispielsweise kann das E-Mail-Konto des Benutzers eine Webbasisbenutzeroberfläche zum Verfassen und Lesen von Nachrichten bereitstellen.

Wenn die ursprüngliche App die URL für die Webschnittstelle kennt (und die erforderliche Syntax zum Identifizieren des angegebenen Elements, das fortgesetzt wird), kann sie diese Informationen in der WebpageURL Eigenschaft der NSUserActivity Instanz codieren. Wenn das empfangende Gerät keine entsprechende systemeigene App installiert hat, um die Fortsetzung zu verarbeiten, kann die bereitgestellte Webschnittstelle aufgerufen werden.

Webbrowser zur nativen App-Übergabe

Wenn der Benutzer eine webbasierte Schnittstelle auf dem ursprünglichen Gerät verwendet hat und eine systemeigene App auf dem empfangenden Gerät den Do Standard Teil der WebpageURL Eigenschaft angibt, verwendet das System diese App, um die Fortsetzung zu behandeln. Das neue Gerät erhält eine NSUserActivity Instanz, die den Aktivitätstyp als BrowsingWeb und die WebpageURL URL enthält, die der Benutzer besucht hat, das UserInfo Wörterbuch ist leer.

Damit eine App an dieser Art von Handoff teilnimmt, muss sie das tun Standard in einer com.apple.developer.associated-domains Berechtigung mit dem Format <service>:<fully qualified domain name> (z. B.: activity continuation:company.com).

Wenn die angegebene Do Standard dem Wert einer WebpageURL Eigenschaft entspricht, lädt Handoff eine Liste genehmigter App-IDs von der Website dazu herunter Standard. Die Website muss eine Liste genehmigter IDs in einer signierten JSON-Datei mit dem Namen apple-app-site-association (z. B https://company.com/apple-app-site-association. ) bereitstellen.

Diese JSON-Datei enthält ein Wörterbuch, das eine Liste der App-IDs im Formular <team identifier>.<bundle identifier>angibt. Zum Beispiel:

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

Verwenden Sie die Content-Typeapplication/pkcs7-mimeTerminal-App und einen Befehl mit einem Zertifikat und einem openssl Schlüssel, die von einer von iOS vertrauenswürdigen Zertifizierungsstelle ausgestellt wurde (siehe https://support.apple.com/kb/ht5012 Liste). Zum Beispiel:

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

Der openssl Befehl gibt eine signierte JSON-Datei aus, die Sie auf Ihrer Website unter der URL der Apple-app-site-association platzieren. Zum Beispiel:

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

Die App erhält jede Aktivität, deren WebpageURL Aufgaben Standard sich in ihrer com.apple.developer.associated-domains Berechtigung befindet. Nur die httphttps Protokolle werden unterstützt, jedes andere Protokoll löst eine Ausnahme aus.

Unterstützung der Übergabe in dokumentbasierten Apps

Wie oben erwähnt, unterstützen dokumentbasierte iOS- und OS X-Apps automatisch die Übergabe von iCloud-basierten Dokumenten, wenn die Datei "Info.plist" der App einen CFBundleDocumentTypes Schlüssel NSUbiquitousDocumentUserActivityTypeenthält. Zum Beispiel:

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

In diesem Beispiel ist die Zeichenfolge ein Reverse-DNS-App-Designator mit dem Namen der angefügten Aktivität. Wenn sie auf diese Weise eingegeben werden, müssen die Aktivitätstypeinträge nicht im NSUserActivityTypes Array der Info.plist-Datei wiederholt werden.

Auf das automatisch erstellte Benutzeraktivitätsobjekt (verfügbar über die Eigenschaft des Dokuments) kann von anderen Objekten in der App verwiesen und zum Wiederherstellen des Zustands UserActivity für die Fortsetzung verwendet werden. Beispielsweise zum Nachverfolgen der Elementauswahl und Dokumentposition. Sie müssen diese Aktivitätseigenschaft NeedsSavetrue immer dann festlegen, wenn sich der Zustand ändert und das UserInfo Wörterbuch in der UpdateUserActivityState Methode aktualisiert.

Die UserActivity Eigenschaft kann von jedem Thread verwendet werden und entspricht dem KVO-Protokoll (Key-Value Observing), sodass es verwendet werden kann, um ein Dokument synchron zu halten, während es sich in und aus iCloud bewegt. Die UserActivity Eigenschaft wird beim Schließen des Dokuments ungültig.

Weitere Informationen finden Sie in der Dokumentation zu dokumentbasierten Apps in der Apple-Dokumentation zur Benutzeraktivität.

Unterstützung von Handoff in Respondern

Sie können Antwortende (geerbt von iOS UIResponder oder NSResponder os X) zu Aktivitäten zuordnen, indem Sie deren UserActivity Eigenschaften festlegen. Das System speichert die UserActivity Eigenschaft automatisch zu den entsprechenden Zeiten, wobei die Methode des UpdateUserActivityState Antwortenden aufgerufen wird, um dem User Activity-Objekt mithilfe der AddUserInfoEntriesFromDictionary Methode aktuelle Daten hinzuzufügen.

Unterstützen von Fortsetzungsstreams

Dies kann situationen sein, in denen die Menge der informationen, die erforderlich sind, um eine Aktivität fortzusetzen, nicht effizient von der anfänglichen Handoff-Nutzlast übertragen werden kann. In diesen Fällen kann die empfangende App einen oder mehrere Datenströme zwischen sich selbst und der ursprünglichen App einrichten, um die Daten zu übertragen.

Die ursprüngliche App legt die SupportsContinuationStreams Eigenschaft der NSUserActivity Instanz auf true. Zum Beispiel:

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

Die empfangende App kann dann die GetContinuationStreams Methode des NSUserActivity Datenstroms AppDelegate aufrufen, um den Datenstrom herzustellen. Zum Beispiel:

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

Auf dem ursprünglichen Gerät empfängt der Benutzeraktivitätsdelegat die Datenströme, indem er seine DidReceiveInputStream Methode aufruft, um die angeforderten Daten bereitzustellen, um die Benutzeraktivität auf dem reaktivierenden Gerät fortzusetzen.

Sie verwenden einen NSInputStream schreibgeschützten Zugriff auf Datenstreams und einen NSOutputStream schreibgeschützten Zugriff. Die Datenströme sollten auf Anforderungs- und Antwort weise verwendet werden, wobei die empfangende App weitere Daten anfordert und die ursprüngliche App sie bereitstellt. Daher werden daten, die in den Ausgabedatenstrom auf dem ursprünglichen Gerät geschrieben wurden, aus dem Eingabedatenstrom auf dem fortlaufenden Gerät gelesen und umgekehrt.

Auch in Situationen, in denen Fortsetzungsstream erforderlich ist, sollte die Kommunikation zwischen den beiden Apps minimal sein.

Weitere Informationen finden Sie in der Dokumentation zur Verwendung von Fortsetzungsstreams von Apple.

Bewährte Methoden für die Übergabe

Die erfolgreiche Implementierung der nahtlosen Fortsetzung einer Benutzeraktivität über Handoff erfordert ein sorgfältiges Design aufgrund aller beteiligten Komponenten. Apple schlägt vor, die folgenden bewährten Methoden für Ihre Handoff-aktivierten Apps zu übernehmen:

  • Entwerfen Sie Ihre Benutzeraktivitäten so, dass die kleinste Nutzlast erforderlich ist, die möglich ist, um den Status der Aktivität zu verknüpfen, die fortgesetzt werden soll. Je größer die Nutzlast ist, desto länger dauert die Fortsetzung.
  • Wenn Sie große Datenmengen für eine erfolgreiche Fortsetzung übertragen müssen, berücksichtigen Sie die Kosten für die Konfiguration und den Netzwerkaufwand.
  • Es ist üblich, dass eine große Mac-App Benutzeraktivitäten erstellt, die von mehreren, kleineren aufgabenspezifischen Apps auf iOS-Geräten behandelt werden. Die verschiedenen App- und Betriebssystemversionen sollten so konzipiert sein, dass sie gut zusammenarbeiten oder ordnungsgemäß fehlschlagen.
  • Verwenden Sie bei der Angabe Ihrer Aktivitätstypen die Reverse-DNS-Notation, um Kollisionen zu vermeiden. Wenn eine Aktivität für eine bestimmte App spezifisch ist, sollte der Name in die Typdefinition aufgenommen werden (z. B com.myCompany.myEditor.editing. ). Wenn die Aktivität über mehrere Apps hinweg funktionieren kann, legen Sie den App-Namen aus der Definition ab (z. B com.myCompany.editing. ).
  • Wenn Ihre App den Status einer Benutzeraktivität (NSUserActivity) aktualisieren muss, legen Sie die NeedsSave Eigenschaft auf true. Zu geeigneten Zeiten ruft Handoff die Methode der UserActivityWillSave Stellvertretung auf, damit Sie das UserInfo Wörterbuch nach Bedarf aktualisieren können.
  • Da der Übergabevorgang möglicherweise nicht sofort auf dem empfangenden Gerät initialisiert wird, sollten Sie die AppDelegate's WillContinueUserActivity implementieren und den Benutzer darüber informieren, dass eine Fortsetzung beginnt.

Beispiel-Handoff-App

Als Beispiel für die Verwendung von Handoff in einer Xamarin.iOS-App haben wir die MonkeyBrowser-Beispiel-App mit diesem Leitfaden aufgenommen. Die App verfügt über vier Registerkarten, mit denen der Benutzer das Web durchsuchen kann, jeweils mit einem bestimmten Aktivitätstyp: Wetter, Favorit, Kaffeepause und Arbeit.

Wenn der Benutzer auf einer beliebigen Registerkarte eine neue URL eingibt und auf die Schaltfläche "Gehe" tippt, wird eine neue NSUserActivity Für diese Registerkarte erstellt, die die URL enthält, die der Benutzer gerade durchsucht:

Example Handoff App

Wenn eine andere der Geräte des Benutzers die MonkeyBrowser-App installiert hat, mit demselben Benutzerkonto bei iCloud angemeldet ist, sich im gleichen Netzwerk befindet und sich in unmittelbarer Nähe zum obigen Gerät befindet, wird die Handoff-Aktivität auf dem Startbildschirm angezeigt (in der unteren linken Ecke):

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

Wenn der Benutzer auf das Handoff-Symbol nach oben zieht, wird die App gestartet, und die in der NSUserActivity App angegebene Benutzeraktivität wird auf dem neuen Gerät fortgesetzt:

The User Activity continued on the new device

Wenn die Benutzeraktivität erfolgreich an ein anderes Apple-Gerät gesendet wurde, erhält das sendende Gerät NSUserActivity einen Aufruf der UserActivityWasContinued Methode, NSUserActivityDelegate um sie darüber zu informieren, dass die Benutzeraktivität erfolgreich auf ein anderes Gerät übertragen wurde.

Zusammenfassung

Dieser Artikel enthält eine Einführung in das Handoff-Framework, das verwendet wird, um eine Benutzeraktivität zwischen mehreren Apple-Geräten des Benutzers fortzusetzen. Als Nächstes wurde gezeigt, wie Handoff in einer Xamarin.iOS-App aktiviert und implementiert wird. Schließlich wurden die verschiedenen Verfügbaren Arten von Handoff-Fortsetzungen und die bewährten Methoden der Handoff erörtert.