Dokumentauswahl in Xamarin.iOS

Mit der Dokumentauswahl können Dokumente zwischen Apps freigegeben werden. Diese Dokumente können in iCloud oder im Verzeichnis einer anderen App gespeichert werden. Dokumente werden über die Dokumentanbietererweiterungen freigegeben, die der Benutzer auf dem Gerät installiert hat.

Aufgrund der Schwierigkeit, Dokumente apps- und cloudübergreifend zu synchronisieren, führen sie zu einer gewissen Komplexität.

Anforderungen

Zum Ausführen der in diesem Artikel beschriebenen Schritte ist Folgendes erforderlich:

  • Xcode 7 und iOS 8 oder neuer – Die Xcode 7- und iOS 8- oder neueren APIs von Apple müssen auf dem Computer des Entwicklers installiert und konfiguriert werden.
  • Visual Studio oder Visual Studio für Mac: Die neueste Version von Visual Studio für Mac sollte installiert werden.
  • iOS-Gerät : Ein iOS-Gerät, auf dem iOS 8 oder höher ausgeführt wird.

Änderungen an iCloud

Um die neuen Features der Dokumentauswahl zu implementieren, wurden die folgenden Änderungen am iCloud-Dienst von Apple vorgenommen:

  • Der iCloud-Daemon wurde mit CloudKit vollständig neu geschrieben.
  • Die vorhandenen iCloud-Features wurden in iCloud Drive umbenannt.
  • Unterstützung für Das Microsoft Windows-Betriebssystem wurde iCloud hinzugefügt.
  • Im Mac OS Finder wurde ein iCloud-Ordner hinzugefügt.
  • iOS-Geräte können auf den Inhalt des Mac OS iCloud-Ordners zugreifen.

Wichtig

Apple stellt Tools zur Verfügung, die Entwickler dabei unterstützen, die Datenschutz-Grundverordnung (DSGVO) der Europäischen Union umzusetzen.

Was ist ein Dokument?

Wenn sie sich auf ein Dokument in iCloud beziehen, handelt es sich um eine einzelne eigenständige Entität und sollte vom Benutzer als solche wahrgenommen werden. Ein Benutzer kann das Dokument ändern oder für andere Benutzer freigeben (z. B. per E-Mail).

Es gibt verschiedene Dateitypen, die der Benutzer sofort als Dokumente erkennt, z. B. Pages, Keynote- oder Numbers-Dateien. iCloud ist jedoch nicht auf dieses Konzept beschränkt. Beispielsweise kann der Zustand eines Spiels (z. B. ein Schachspiel) als Dokument behandelt und in iCloud gespeichert werden. Diese Datei kann zwischen den Geräten eines Benutzers übergeben werden und es ihnen ermöglichen, ein Spiel auf einem anderen Gerät aufzugeben.

Umgang mit Dokumenten

Bevor Sie sich mit dem Code befassen, der für die Verwendung der Dokumentauswahl mit Xamarin erforderlich ist, werden in diesem Artikel die bewährten Methoden für die Arbeit mit iCloud-Dokumenten und einige der Änderungen an vorhandenen APIs behandelt, die zur Unterstützung der Dokumentauswahl erforderlich sind.

Verwenden der Dateikoordination

Da eine Datei von mehreren verschiedenen Speicherorten aus geändert werden kann, muss eine Koordinierung verwendet werden, um Datenverluste zu verhindern.

Verwenden der Dateikoordination

Sehen wir uns die obige Abbildung an:

  1. Ein iOS-Gerät, das die Dateikoordination verwendet, erstellt ein neues Dokument und speichert es im iCloud-Ordner.
  2. iCloud speichert die geänderte Datei zur Verteilung auf jedes Gerät in der Cloud.
  3. Ein angefügter Mac sieht die geänderte Datei im iCloud-Ordner und kopiert die Änderungen in die Datei mithilfe der Dateikoordination.
  4. Ein Gerät, das die Dateikoordination nicht verwendet, nimmt eine Änderung an der Datei vor und speichert sie im iCloud-Ordner. Diese Änderungen werden sofort auf die anderen Geräte repliziert.

Angenommen, das ursprüngliche iOS-Gerät oder der Mac hat die Datei bearbeitet, jetzt gehen die Änderungen verloren und werden mit der Version der Datei vom nicht koordinierten Gerät überschrieben. Um Datenverluste zu vermeiden, ist die Dateikoordination bei der Arbeit mit cloudbasierten Dokumenten ein Muss.

Verwenden von UIDocument

UIDocument macht die Dinge einfach (oder NSDocument unter macOS), indem sie alle schweren Hebehebungen für den Entwickler ausführen. Es bietet integrierte Dateikoordination mit Hintergrundwarteschlangen, damit die Benutzeroberfläche der Anwendung nicht blockiert wird.

UIDocument macht mehrere allgemeine APIs verfügbar, die den Entwicklungsaufwand einer Xamarin-Anwendung für den vom Entwickler benötigten Zweck erleichtern.

Der folgende Code erstellt eine Unterklasse von, UIDocument um ein generisches textbasiertes Dokument zu implementieren, das zum Speichern und Abrufen von Text aus iCloud verwendet werden kann:

using System;
using Foundation;
using UIKit;

namespace DocPicker
{
    public class GenericTextDocument : UIDocument
    {
        #region Private Variable Storage
        private NSString _dataModel;
        #endregion

        #region Computed Properties
        public string Contents {
            get { return _dataModel.ToString (); }
            set { _dataModel = new NSString(value); }
        }
        #endregion

        #region Constructors
        public GenericTextDocument (NSUrl url) : base (url)
        {
            // Set the default document text
            this.Contents = "";
        }

        public GenericTextDocument (NSUrl url, string contents) : base (url)
        {
            // Set the default document text
            this.Contents = contents;
        }
        #endregion

        #region Override Methods
        public override bool LoadFromContents (NSObject contents, string typeName, out NSError outError)
        {
            // Clear the error state
            outError = null;

            // Were any contents passed to the document?
            if (contents != null) {
                _dataModel = NSString.FromData( (NSData)contents, NSStringEncoding.UTF8 );
            }

            // Inform caller that the document has been modified
            RaiseDocumentModified (this);

            // Return success
            return true;
        }

        public override NSObject ContentsForType (string typeName, out NSError outError)
        {
            // Clear the error state
            outError = null;

            // Convert the contents to a NSData object and return it
            NSData docData = _dataModel.Encode(NSStringEncoding.UTF8);
            return docData;
        }
        #endregion

        #region Events
        public delegate void DocumentModifiedDelegate(GenericTextDocument document);
        public event DocumentModifiedDelegate DocumentModified;

        internal void RaiseDocumentModified(GenericTextDocument document) {
            // Inform caller
            if (this.DocumentModified != null) {
                this.DocumentModified (document);
            }
        }
        #endregion
    }
}

Die GenericTextDocument oben dargestellte Klasse wird in diesem Artikel verwendet, wenn Sie mit der Dokumentauswahl und externen Dokumenten in einer Xamarin.iOS 8-Anwendung arbeiten.

Asynchrone Dateikoordination

iOS 8 bietet mehrere neue asynchrone Dateikoordinationsfeatures über die neuen Dateikoordination-APIs. Vor iOS 8 waren alle vorhandenen Dateikoordination-APIs vollständig synchron. Dies bedeutete, dass der Entwickler für die Implementierung eigener Hintergrundwarteschlangen verantwortlich war, um zu verhindern, dass die Dateikoordination die Benutzeroberfläche der Anwendung blockiert.

Die neue NSFileAccessIntent Klasse enthält eine URL, die auf die Datei verweist, und mehrere Optionen zum Steuern des erforderlichen Koordinierungstyps. Der folgende Code veranschaulicht das Verschieben einer Datei von einem Speicherort an einen anderen mithilfe von Absichten:

// Get source options
var srcURL = NSUrl.FromFilename ("FromFile.txt");
var srcIntent = NSFileAccessIntent.CreateReadingIntent (srcURL, NSFileCoordinatorReadingOptions.ForUploading);

// Get destination options
var dstURL = NSUrl.FromFilename ("ToFile.txt");
var dstIntent = NSFileAccessIntent.CreateReadingIntent (dstURL, NSFileCoordinatorReadingOptions.ForUploading);

// Create an array
var intents = new NSFileAccessIntent[] {
    srcIntent,
    dstIntent
};

// Initialize a file coordination with intents
var queue = new NSOperationQueue ();
var fileCoordinator = new NSFileCoordinator ();
fileCoordinator.CoordinateAccess (intents, queue, (err) => {
    // Was there an error?
    if (err!=null) {
        Console.WriteLine("Error: {0}",err.LocalizedDescription);
    }
});

Ermitteln und Auflisten von Dokumenten

Dokumente können mithilfe der vorhandenen NSMetadataQuery APIs ermittelt und auflisten. In diesem Abschnitt werden neue Features behandelt NSMetadataQuery , die die Arbeit mit Dokumenten noch einfacher als bisher machen.

Vorhandenes Verhalten

Vor iOS 8 wurden lokale Dateiänderungen wie Löschvorgänge, NSMetadataQuery Erstellungen und Umbenennungen nur langsam erfasst.

Übersicht über lokale Dateiänderungen in NSMetadataQuery

Für dieses Diagramm gilt:

  1. Für Dateien, die bereits im Anwendungscontainer vorhanden sind, sind vorhandene NSMetadata Datensätze vorab erstellt und in einem Pool vorhanden, NSMetadataQuery sodass sie sofort für die Anwendung verfügbar sind.
  2. Die Anwendung erstellt eine neue Datei im Anwendungscontainer.
  3. Es gibt eine Verzögerung, bevor NSMetadataQuery die Änderung am Anwendungscontainer angezeigt wird und der erforderliche NSMetadata Datensatz erstellt wird.

Aufgrund der Verzögerung bei der Erstellung des NSMetadata Datensatzes mussten für die Anwendung zwei Datenquellen geöffnet sein: eine für lokale Dateiänderungen und eine für cloudbasierte Änderungen.

Nähte

In iOS 8 NSMetadataQuery ist die direkte Verwendung mit einem neuen Feature namens Stitching einfacher:

NSMetadataQuery mit einem neuen Feature namens Stitching

Verwenden von Stitching im obigen Diagramm:

  1. Wie zuvor sind für Dateien, die bereits im Anwendungscontainer vorhanden sind, NSMetadataQuery vorhandene NSMetadata Datensätze vorab erstellt und in einem Spool ausgeführt.
  2. Die Anwendung erstellt mithilfe der Dateikoordination eine neue Datei im Anwendungscontainer.
  3. Ein Hook im Anwendungscontainer sieht die Änderung und Aufrufe NSMetadataQuery zum Erstellen des erforderlichen NSMetadata Datensatzes.
  4. Der NSMetadata Datensatz wird direkt nach der Datei erstellt und der Anwendung zur Verfügung gestellt.

Durch die Verwendung von Stitching muss die Anwendung keine Datenquelle mehr öffnen, um lokale und cloudbasierte Dateiänderungen zu überwachen. Jetzt kann sich die Anwendung direkt auf NSMetadataQuery die Anwendung verlassen.

Wichtig

Das Stitching funktioniert nur, wenn die Anwendung die Dateikoordination verwendet, wie im obigen Abschnitt dargestellt. Wenn die Dateikoordination nicht verwendet wird, verwenden die APIs standardmäßig das vorhandene Verhalten vor iOS 8.

Neue iOS 8-Metadatenfeatures

Die folgenden neuen Features wurden in iOS 8 hinzugefügt NSMetadataQuery :

  • NSMetatadataQuery kann jetzt nicht lokale Dokumente auflisten, die in der Cloud gespeichert sind.
  • Neue APIs wurden hinzugefügt, um auf Metadateninformationen in den cloudbasierten Dokumenten zuzugreifen.
  • Es gibt eine neue NSUrl_PromisedItems API, die auf die Dateiattribute von Dateien zugreifen kann, für die deren Inhalte lokal verfügbar sind oder nicht.
  • Verwenden Sie die GetPromisedItemResourceValue -Methode, um Informationen zu einer bestimmten Datei abzurufen, oder verwenden Sie die GetPromisedItemResourceValues -Methode, um Informationen zu mehreren Dateien gleichzeitig abzurufen.

Für den Umgang mit Metadaten wurden zwei neue Dateikoordinationsflags hinzugefügt:

  • NSFileCoordinatorReadImmediatelyAvailableMetadataOnly
  • NSFileCoordinatorWriteContentIndependentMetadataOnly

Mit den obigen Flags muss der Inhalt der Dokumentdatei nicht lokal verfügbar sein, damit sie verwendet werden können.

Das folgende Codesegment zeigt, wie Sie verwenden, NSMetadataQuery um das Vorhandensein einer bestimmten Datei abzufragen und die Datei zu erstellen, falls sie nicht vorhanden ist:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Foundation;
using UIKit;
using ObjCRuntime;
using System.IO;

#region Static Properties
public const string TestFilename = "test.txt";
#endregion

#region Computed Properties
public bool HasiCloud { get; set; }
public bool CheckingForiCloud { get; set; }
public NSUrl iCloudUrl { get; set; }

public GenericTextDocument Document { get; set; }
public NSMetadataQuery Query { get; set; }
#endregion

#region Private Methods
private void FindDocument () {
    Console.WriteLine ("Finding Document...");

    // Create a new query and set it's scope
    Query = new NSMetadataQuery();
    Query.SearchScopes = new NSObject [] {
                NSMetadataQuery.UbiquitousDocumentsScope,
                NSMetadataQuery.UbiquitousDataScope,
                NSMetadataQuery.AccessibleUbiquitousExternalDocumentsScope
            };

    // Build a predicate to locate the file by name and attach it to the query
    var pred = NSPredicate.FromFormat ("%K == %@"
        , new NSObject[] {
            NSMetadataQuery.ItemFSNameKey
            , new NSString(TestFilename)});
    Query.Predicate = pred;

    // Register a notification for when the query returns
    NSNotificationCenter.DefaultCenter.AddObserver (this,
            new Selector("queryDidFinishGathering:"),             NSMetadataQuery.DidFinishGatheringNotification,
            Query);

    // Start looking for the file
    Query.StartQuery ();
    Console.WriteLine ("Querying: {0}", Query.IsGathering);
}

[Export("queryDidFinishGathering:")]
public void DidFinishGathering (NSNotification notification) {
    Console.WriteLine ("Finish Gathering Documents.");

    // Access the query and stop it from running
    var query = (NSMetadataQuery)notification.Object;
    query.DisableUpdates();
    query.StopQuery();

    // Release the notification
    NSNotificationCenter.DefaultCenter.RemoveObserver (this
        , NSMetadataQuery.DidFinishGatheringNotification
        , query);

    // Load the document that the query returned
    LoadDocument(query);
}

private void LoadDocument (NSMetadataQuery query) {
    Console.WriteLine ("Loading Document...");    

    // Take action based on the returned record count
    switch (query.ResultCount) {
    case 0:
        // Create a new document
        CreateNewDocument ();
        break;
    case 1:
        // Gain access to the url and create a new document from
        // that instance
        NSMetadataItem item = (NSMetadataItem)query.ResultAtIndex (0);
        var url = (NSUrl)item.ValueForAttribute (NSMetadataQuery.ItemURLKey);

        // Load the document
        OpenDocument (url);
        break;
    default:
        // There has been an issue
        Console.WriteLine ("Issue: More than one document found...");
        break;
    }
}
#endregion

#region Public Methods
public void OpenDocument(NSUrl url) {

    Console.WriteLine ("Attempting to open: {0}", url);
    Document = new GenericTextDocument (url);

    // Open the document
    Document.Open ( (success) => {
        if (success) {
            Console.WriteLine ("Document Opened");
        } else
            Console.WriteLine ("Failed to Open Document");
    });

    // Inform caller
    RaiseDocumentLoaded (Document);
}

public void CreateNewDocument() {
    // Create path to new file
    // var docsFolder = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
    var docsFolder = Path.Combine(iCloudUrl.Path, "Documents");
    var docPath = Path.Combine (docsFolder, TestFilename);
    var ubiq = new NSUrl (docPath, false);

    // Create new document at path
    Console.WriteLine ("Creating Document at:" + ubiq.AbsoluteString);
    Document = new GenericTextDocument (ubiq);

    // Set the default value
    Document.Contents = "(default value)";

    // Save document to path
    Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForCreating, (saveSuccess) => {
        Console.WriteLine ("Save completion:" + saveSuccess);
        if (saveSuccess) {
            Console.WriteLine ("Document Saved");
        } else {
            Console.WriteLine ("Unable to Save Document");
        }
    });

    // Inform caller
    RaiseDocumentLoaded (Document);
}

public bool SaveDocument() {
    bool successful = false;

    // Save document to path
    Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForOverwriting, (saveSuccess) => {
        Console.WriteLine ("Save completion: " + saveSuccess);
        if (saveSuccess) {
            Console.WriteLine ("Document Saved");
            successful = true;
        } else {
            Console.WriteLine ("Unable to Save Document");
            successful=false;
        }
    });

    // Return results
    return successful;
}
#endregion

#region Events
public delegate void DocumentLoadedDelegate(GenericTextDocument document);
public event DocumentLoadedDelegate DocumentLoaded;

internal void RaiseDocumentLoaded(GenericTextDocument document) {
    // Inform caller
    if (this.DocumentLoaded != null) {
        this.DocumentLoaded (document);
    }
}
#endregion

Dokumentminiaturansichten

Apple ist der Meinung, dass die beste Benutzerfreundlichkeit beim Auflisten von Dokumenten für eine Anwendung darin besteht, Vorschauversionen zu verwenden. Dadurch erhalten die Endbenutzer Kontext, sodass sie das Dokument, mit dem sie arbeiten möchten, schnell identifizieren können.

Vor iOS 8 erforderte die Anzeige der Dokumentvorschau eine benutzerdefinierte Implementierung. Neu in iOS 8 sind Dateisystemattribute, die es dem Entwickler ermöglichen, schnell mit Dokumentminiaturansichten zu arbeiten.

Abrufen von Dokumentminiaturansichten

Durch Aufrufen der GetPromisedItemResourceValue -Methode NSUrl_PromisedItems oder GetPromisedItemResourceValues wird die API zurückgegebenNSUrlThumbnailDictionary. Der einzige Schlüssel, der derzeit in diesem Wörterbuch enthalten ist, ist und NSThumbnial1024X1024SizeKey der zugehörige UIImageSchlüssel.

Speichern von Dokumentminiaturansichten

Die einfachste Möglichkeit zum Speichern einer Miniaturansicht ist die Verwendung UIDocumentvon . Durch Aufrufen der GetFileAttributesToWriteUIDocument -Methode und Festlegen der Miniaturansicht wird sie automatisch gespeichert, wenn die Dokumentdatei ist. Diese Änderung wird im iCloud-Daemon angezeigt und an iCloud weitergegeben. Unter Mac OS X werden Miniaturansichten vom Quick Look-Plug-In automatisch für den Entwickler generiert.

Mit den Grundlagen der Arbeit mit iCloud-basierten Dokumenten sowie den Änderungen an der vorhandenen API sind wir bereit, den Dokumentauswahlansichtscontroller in einer mobilen Xamarin iOS 8-Anwendung zu implementieren.

Aktivieren von iCloud in Xamarin

Bevor die Dokumentauswahl in einer Xamarin.iOS-Anwendung verwendet werden kann, muss die iCloud-Unterstützung sowohl in Ihrer Anwendung als auch über Apple aktiviert werden.

In den folgenden Schritten werden exemplarische Schritte zum Bereitstellungsprozess für iCloud ausgeführt.

  1. Erstellen Sie einen iCloud-Container.
  2. Erstellen Sie eine App-ID, die die iCloud-App Service enthält.
  3. Erstellen Sie ein Bereitstellungsprofil, das diese App-ID enthält.

Im Leitfaden Arbeiten mit Funktionen werden die ersten beiden Schritte beschrieben. Führen Sie zum Erstellen eines Bereitstellungsprofils die Schritte im Bereitstellungsprofilhandbuch aus .

Die folgenden Schritte führen Sie exemplarische Schritte zum Konfigurieren Ihrer Anwendung für iCloud durch:

Gehen Sie folgendermaßen vor:

  1. Öffnen Sie das Projekt in Visual Studio für Mac oder Visual Studio.

  2. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie Optionen aus.

  3. Wählen Sie im Dialogfeld Optionen die Option iOS-Anwendung aus, und stellen Sie sicher, dass der Bundle-Bezeichner mit dem übereinstimmt, der in der oben für die Anwendung erstellten App-ID definiert wurde.

  4. Wählen Sie iOS Bundle Signing aus, und wählen Sie die Entwickleridentität und das oben erstellte Bereitstellungsprofil aus.

  5. Klicken Sie auf die Schaltfläche OK , um die Änderungen zu speichern und das Dialogfeld zu schließen.

  6. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste aufEntitlements.plist, um sie im Editor zu öffnen.

    Wichtig

    In Visual Studio müssen Sie möglicherweise den Berechtigungs-Editor öffnen, indem Sie mit der rechten Maustaste darauf klicken, Öffnen mit... und Eigenschaftenlisten-Editor auswählen.

  7. Aktivieren Sie iCloud aktivieren , iCloud-Dokumente , Schlüssel-Wert-Speicher und CloudKit .

  8. Stellen Sie sicher, dass der Container für die Anwendung vorhanden ist (wie oben erstellt). Ein Beispiel: iCloud.com.your-company.AppName

  9. Speichern Sie die Änderungen in der Datei.

Weitere Informationen zu Berechtigungen finden Sie im Leitfaden Arbeiten mit Berechtigungen .

Nachdem das oben genannte Setup eingerichtet wurde, kann die Anwendung jetzt cloudbasierte Dokumente und den neuen Ansichtscontroller für die Dokumentauswahl verwenden.

Allgemeiner Setupcode

Vor den ersten Schritten mit dem Ansichtscontroller für die Dokumentauswahl ist ein Standardsetupcode erforderlich. Ändern Sie zunächst die Datei der AppDelegate.cs Anwendung, und lassen Sie sie wie folgt aussehen:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Foundation;
using UIKit;
using ObjCRuntime;
using System.IO;

namespace DocPicker
{

    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        #region Static Properties
        public const string TestFilename = "test.txt";
        #endregion

        #region Computed Properties
        public override UIWindow Window { get; set; }
        public bool HasiCloud { get; set; }
        public bool CheckingForiCloud { get; set; }
        public NSUrl iCloudUrl { get; set; }

        public GenericTextDocument Document { get; set; }
        public NSMetadataQuery Query { get; set; }
        public NSData Bookmark { get; set; }
        #endregion

        #region Private Methods
        private void FindDocument () {
            Console.WriteLine ("Finding Document...");

            // Create a new query and set it's scope
            Query = new NSMetadataQuery();
            Query.SearchScopes = new NSObject [] {
                NSMetadataQuery.UbiquitousDocumentsScope,
                NSMetadataQuery.UbiquitousDataScope,
                NSMetadataQuery.AccessibleUbiquitousExternalDocumentsScope
            };

            // Build a predicate to locate the file by name and attach it to the query
            var pred = NSPredicate.FromFormat ("%K == %@",
                 new NSObject[] {NSMetadataQuery.ItemFSNameKey
                , new NSString(TestFilename)});
            Query.Predicate = pred;

            // Register a notification for when the query returns
            NSNotificationCenter.DefaultCenter.AddObserver (this
                , new Selector("queryDidFinishGathering:")
                , NSMetadataQuery.DidFinishGatheringNotification
                , Query);

            // Start looking for the file
            Query.StartQuery ();
            Console.WriteLine ("Querying: {0}", Query.IsGathering);
        }

        [Export("queryDidFinishGathering:")]
        public void DidFinishGathering (NSNotification notification) {
            Console.WriteLine ("Finish Gathering Documents.");

            // Access the query and stop it from running
            var query = (NSMetadataQuery)notification.Object;
            query.DisableUpdates();
            query.StopQuery();

            // Release the notification
            NSNotificationCenter.DefaultCenter.RemoveObserver (this
                , NSMetadataQuery.DidFinishGatheringNotification
                , query);

            // Load the document that the query returned
            LoadDocument(query);
        }

        private void LoadDocument (NSMetadataQuery query) {
            Console.WriteLine ("Loading Document...");    

            // Take action based on the returned record count
            switch (query.ResultCount) {
            case 0:
                // Create a new document
                CreateNewDocument ();
                break;
            case 1:
                // Gain access to the url and create a new document from
                // that instance
                NSMetadataItem item = (NSMetadataItem)query.ResultAtIndex (0);
                var url = (NSUrl)item.ValueForAttribute (NSMetadataQuery.ItemURLKey);

                // Load the document
                OpenDocument (url);
                break;
            default:
                // There has been an issue
                Console.WriteLine ("Issue: More than one document found...");
                break;
            }
        }
        #endregion

        #region Public Methods

        public void OpenDocument(NSUrl url) {

            Console.WriteLine ("Attempting to open: {0}", url);
            Document = new GenericTextDocument (url);

            // Open the document
            Document.Open ( (success) => {
                if (success) {
                    Console.WriteLine ("Document Opened");
                } else
                    Console.WriteLine ("Failed to Open Document");
            });

            // Inform caller
            RaiseDocumentLoaded (Document);
        }

        public void CreateNewDocument() {
            // Create path to new file
            // var docsFolder = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
            var docsFolder = Path.Combine(iCloudUrl.Path, "Documents");
            var docPath = Path.Combine (docsFolder, TestFilename);
            var ubiq = new NSUrl (docPath, false);

            // Create new document at path
            Console.WriteLine ("Creating Document at:" + ubiq.AbsoluteString);
            Document = new GenericTextDocument (ubiq);

            // Set the default value
            Document.Contents = "(default value)";

            // Save document to path
            Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForCreating, (saveSuccess) => {
                Console.WriteLine ("Save completion:" + saveSuccess);
                if (saveSuccess) {
                    Console.WriteLine ("Document Saved");
                } else {
                    Console.WriteLine ("Unable to Save Document");
                }
            });

            // Inform caller
            RaiseDocumentLoaded (Document);
        }

        /// <summary>
        /// Saves the document.
        /// </summary>
        /// <returns><c>true</c>, if document was saved, <c>false</c> otherwise.</returns>
        public bool SaveDocument() {
            bool successful = false;

            // Save document to path
            Document.Save (Document.FileUrl, UIDocumentSaveOperation.ForOverwriting, (saveSuccess) => {
                Console.WriteLine ("Save completion: " + saveSuccess);
                if (saveSuccess) {
                    Console.WriteLine ("Document Saved");
                    successful = true;
                } else {
                    Console.WriteLine ("Unable to Save Document");
                    successful=false;
                }
            });

            // Return results
            return successful;
        }
        #endregion

        #region Override Methods
        public override void FinishedLaunching (UIApplication application)
        {

            // Start a new thread to check and see if the user has iCloud
            // enabled.
            new Thread(new ThreadStart(() => {
                // Inform caller that we are checking for iCloud
                CheckingForiCloud = true;

                // Checks to see if the user of this device has iCloud
                // enabled
                var uburl = NSFileManager.DefaultManager.GetUrlForUbiquityContainer(null);

                // Connected to iCloud?
                if (uburl == null)
                {
                    // No, inform caller
                    HasiCloud = false;
                    iCloudUrl =null;
                    Console.WriteLine("Unable to connect to iCloud");
                    InvokeOnMainThread(()=>{
                        var okAlertController = UIAlertController.Create ("iCloud Not Available", "Developer, please check your Entitlements.plist, Bundle ID and Provisioning Profiles.", UIAlertControllerStyle.Alert);
                        okAlertController.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
                        Window.RootViewController.PresentViewController (okAlertController, true, null);
                    });
                }
                else
                {    
                    // Yes, inform caller and save location the Application Container
                    HasiCloud = true;
                    iCloudUrl = uburl;
                    Console.WriteLine("Connected to iCloud");

                    // If we have made the connection with iCloud, start looking for documents
                    InvokeOnMainThread(()=>{
                        // Search for the default document
                        FindDocument ();
                    });
                }

                // Inform caller that we are no longer looking for iCloud
                CheckingForiCloud = false;

            })).Start();

        }

        // This method is invoked when the application is about to move from active to inactive state.
        // OpenGL applications should use this method to pause.
        public override void OnResignActivation (UIApplication application)
        {
        }

        // This method should be used to release shared resources and it should store the application state.
        // If your application supports background execution this method is called instead of WillTerminate
        // when the user quits.
        public override void DidEnterBackground (UIApplication application)
        {
            // Trap all errors
            try {
                // Values to include in the bookmark packet
                var resources = new string[] {
                    NSUrl.FileSecurityKey,
                    NSUrl.ContentModificationDateKey,
                    NSUrl.FileResourceIdentifierKey,
                    NSUrl.FileResourceTypeKey,
                    NSUrl.LocalizedNameKey
                };

                // Create the bookmark
                NSError err;
                Bookmark = Document.FileUrl.CreateBookmarkData (NSUrlBookmarkCreationOptions.WithSecurityScope, resources, iCloudUrl, out err);

                // Was there an error?
                if (err != null) {
                    // Yes, report it
                    Console.WriteLine ("Error Creating Bookmark: {0}", err.LocalizedDescription);
                }
            }
            catch (Exception e) {
                // Report error
                Console.WriteLine ("Error: {0}", e.Message);
            }
        }

        // This method is called as part of the transition from background to active state.
        public override void WillEnterForeground (UIApplication application)
        {
            // Is there any bookmark data?
            if (Bookmark != null) {
                // Trap all errors
                try {
                    // Yes, attempt to restore it
                    bool isBookmarkStale;
                    NSError err;
                    var srcUrl = new NSUrl (Bookmark, NSUrlBookmarkResolutionOptions.WithSecurityScope, iCloudUrl, out isBookmarkStale, out err);

                    // Was there an error?
                    if (err != null) {
                        // Yes, report it
                        Console.WriteLine ("Error Loading Bookmark: {0}", err.LocalizedDescription);
                    } else {
                        // Load document from bookmark
                        OpenDocument (srcUrl);
                    }
                }
                catch (Exception e) {
                    // Report error
                    Console.WriteLine ("Error: {0}", e.Message);
                }
            }

        }

        // This method is called when the application is about to terminate. Save data, if needed.
        public override void WillTerminate (UIApplication application)
        {
        }
        #endregion

        #region Events
        public delegate void DocumentLoadedDelegate(GenericTextDocument document);
        public event DocumentLoadedDelegate DocumentLoaded;

        internal void RaiseDocumentLoaded(GenericTextDocument document) {
            // Inform caller
            if (this.DocumentLoaded != null) {
                this.DocumentLoaded (document);
            }
        }
        #endregion
    }
}

Wichtig

Der obige Code enthält den Code aus dem Abschnitt Zum Ermitteln und Auflisten von Dokumenten oben. Es wird hier in seiner Gesamtheit dargestellt, wie es in einer tatsächlichen Anwendung erscheinen würde. Der Einfachheit halber funktioniert dieses Beispiel nur mit einer einzelnen, hartcodierten Datei (test.txt).

Der obige Code macht mehrere iCloud Drive-Tastenkombinationen verfügbar, um die Arbeit mit ihnen im Rest der Anwendung zu vereinfachen.

Fügen Sie als Nächstes jedem Ansichts- oder Ansichtscontainer, der die Dokumentauswahl oder die Arbeit mit cloudbasierten Dokumenten verwendet, den folgenden Code hinzu:

using CloudKit;
...

#region Computed Properties
/// <summary>
/// Returns the delegate of the current running application
/// </summary>
/// <value>The this app.</value>
public AppDelegate ThisApp {
    get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
}
#endregion

Dadurch wird eine Verknüpfung hinzugefügt, um auf die AppDelegate oben erstellten iCloud-Verknüpfungen zuzugreifen und auf diese zuzugreifen.

Nachdem dieser Code vorhanden ist, sehen wir uns die Implementierung des Dokumentauswahlansichtscontrollers in einer Xamarin iOS 8-Anwendung an.

Verwenden des Ansichtscontrollers für die Dokumentauswahl

Vor iOS 8 war der Zugriff auf Dokumente aus einer anderen Anwendung sehr schwierig, da es keine Möglichkeit gab, Dokumente außerhalb der Anwendung aus der App heraus zu ermitteln.

Vorhandenes Verhalten

Übersicht über vorhandenes Verhalten

Sehen wir uns den Zugriff auf ein externes Dokument vor iOS 8 an:

  1. Zuerst muss der Benutzer die Anwendung öffnen, die das Dokument ursprünglich erstellt hat.
  2. Das Dokument ist ausgewählt, und das UIDocumentInteractionController wird verwendet, um das Dokument an die neue Anwendung zu senden.
  3. Schließlich wird eine Kopie des ursprünglichen Dokuments im Container der neuen Anwendung platziert.

Von dort aus steht das Dokument für die zweite Anwendung zum Öffnen und Bearbeiten zur Verfügung.

Ermitteln von Dokumenten außerhalb des Containers einer App

In iOS 8 kann eine Anwendung problemlos auf Dokumente außerhalb ihres eigenen Anwendungscontainers zugreifen:

Ermitteln von Dokumenten außerhalb des Containers einer App

Mithilfe der neuen iCloud-Dokumentauswahl ( UIDocumentPickerViewController) kann eine iOS-Anwendung direkt erkennen und außerhalb des Anwendungscontainers darauf zugreifen. UIDocumentPickerViewController Stellt einen Mechanismus bereit, mit dem der Benutzer über Berechtigungen Zugriff auf die ermittelten Dokumente gewähren und diese bearbeiten kann.

Eine Anwendung muss sich dafür entscheiden, dass ihre Dokumente in der iCloud-Dokumentauswahl angezeigt werden und für andere Anwendungen verfügbar sind, um sie zu ermitteln und damit zu arbeiten. Damit eine Xamarin iOS 8-Anwendung ihren Anwendungscontainer freigibt, bearbeiten Sie die Info.plist Datei in einem Standardtext-Editor, und fügen Sie die folgenden zwei Zeilen am Ende des Wörterbuchs (zwischen den <dict>...</dict> Tags) hinzu:

<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>

Bietet UIDocumentPickerViewController eine großartige neue Benutzeroberfläche, mit der der Benutzer Dokumente auswählen kann. Gehen Sie wie folgt vor, um den Ansichtscontroller für die Dokumentauswahl in einer Xamarin iOS 8-Anwendung anzuzeigen:

using MobileCoreServices;
...

// Allow the Document picker to select a range of document types
        var allowedUTIs = new string[] {
            UTType.UTF8PlainText,
            UTType.PlainText,
            UTType.RTF,
            UTType.PNG,
            UTType.Text,
            UTType.PDF,
            UTType.Image
        };

        // Display the picker
        //var picker = new UIDocumentPickerViewController (allowedUTIs, UIDocumentPickerMode.Open);
        var pickerMenu = new UIDocumentMenuViewController(allowedUTIs, UIDocumentPickerMode.Open);
        pickerMenu.DidPickDocumentPicker += (sender, args) => {

            // Wireup Document Picker
            args.DocumentPicker.DidPickDocument += (sndr, pArgs) => {

                // IMPORTANT! You must lock the security scope before you can
                // access this file
                var securityEnabled = pArgs.Url.StartAccessingSecurityScopedResource();

                // Open the document
                ThisApp.OpenDocument(pArgs.Url);

                // IMPORTANT! You must release the security lock established
                // above.
                pArgs.Url.StopAccessingSecurityScopedResource();
            };

            // Display the document picker
            PresentViewController(args.DocumentPicker,true,null);
        };

pickerMenu.ModalPresentationStyle = UIModalPresentationStyle.Popover;
PresentViewController(pickerMenu,true,null);
UIPopoverPresentationController presentationPopover = pickerMenu.PopoverPresentationController;
if (presentationPopover!=null) {
    presentationPopover.SourceView = this.View;
    presentationPopover.PermittedArrowDirections = UIPopoverArrowDirection.Down;
    presentationPopover.SourceRect = ((UIButton)s).Frame;
}

Wichtig

Der Entwickler muss die StartAccessingSecurityScopedResource -Methode von NSUrl aufrufen, bevor auf ein externes Dokument zugegriffen werden kann. Die StopAccessingSecurityScopedResource -Methode muss aufgerufen werden, um die Sicherheitssperre freizugeben, sobald das Dokument geladen wurde.

Beispielausgabe

Hier ist ein Beispiel dafür, wie der obige Code eine Dokumentauswahl anzeigt, wenn sie auf einem iPhone-Gerät ausgeführt wird:

  1. Der Benutzer startet die Anwendung, und die Standard-Schnittstelle wird angezeigt:

    Die Standard-Schnittstelle wird angezeigt.

  2. Der Benutzer tippt oben auf dem Bildschirm auf die Aktionsschaltfläche und wird aufgefordert, einen Dokumentanbieter aus der Liste der verfügbaren Anbieter auszuwählen:

    Auswählen eines Dokumentanbieters aus der Liste der verfügbaren Anbieter

  3. Der Ansichtscontroller für die Dokumentauswahl wird für den ausgewählten Dokumentanbieter angezeigt:

    Der Ansichtscontroller für die Dokumentauswahl wird angezeigt.

  4. Der Benutzer tippt auf einen Dokumentordner , um dessen Inhalt anzuzeigen:

    Inhalt des Dokumentordners

  5. Der Benutzer wählt ein Dokument aus, und die Dokumentauswahl wird geschlossen.

  6. Die Standard-Schnittstelle wird erneut angezeigt, das Dokument wird aus dem externen Container geladen und dessen Inhalt angezeigt.

Die tatsächliche Anzeige des Ansichtscontrollers für die Dokumentauswahl hängt von den Dokumentanbietern ab, die der Benutzer auf dem Gerät installiert hat und welcher Dokumentauswahlmodus implementiert wurde. Im obigen Beispiel wird der offene Modus verwendet. Die anderen Modustypen werden unten ausführlich erläutert.

Verwalten externer Dokumente

Wie bereits erwähnt, konnte eine Anwendung vor iOS 8 nur auf Dokumente zugreifen, die Teil des Anwendungscontainers waren. In iOS 8 kann eine Anwendung aus externen Quellen auf Dokumente zugreifen:

Übersicht über die Verwaltung externer Dokumente

Wenn der Benutzer ein Dokument aus einer externen Quelle auswählt, wird ein Referenzdokument in den Anwendungscontainer geschrieben, der auf das ursprüngliche Dokument verweist.

Zur Unterstützung beim Hinzufügen dieser neuen Funktion zu vorhandenen Anwendungen wurden der NSMetadataQuery API mehrere neue Features hinzugefügt. In der Regel verwendet eine Anwendung den Ubiquitous Document Scope, um Dokumente auflisten zu können, die sich in ihrem Anwendungscontainer befinden. Bei Verwendung dieses Bereichs werden nur Dokumente innerhalb des Anwendungscontainers weiterhin angezeigt.

Wenn Sie den neuen Ubiquitous External Document Scope verwenden, werden Dokumente zurückgegeben, die sich außerhalb des Anwendungscontainers befinden, und die Metadaten dafür zurückgegeben. Zeigt NSMetadataItemUrlKey auf die URL, in der sich das Dokument tatsächlich befindet.

Manchmal möchte eine Anwendung nicht mit den Dokumenten arbeiten, auf die durch den Verweis verwiesen wird. Stattdessen möchte die App direkt mit dem Referenzdokument arbeiten. Beispielsweise kann die App das Dokument im Ordner der Anwendung auf der Benutzeroberfläche anzeigen oder es dem Benutzer ermöglichen, die Verweise innerhalb eines Ordners zu verschieben.

In iOS 8 wurde ein neues NSMetadataItemUrlInLocalContainerKey bereitgestellt, um direkt auf das Referenzdokument zuzugreifen. Dieser Schlüssel verweist auf den tatsächlichen Verweis auf das externe Dokument in einem Anwendungscontainer.

Wird NSMetadataUbiquitousItemIsExternalDocumentKey verwendet, um zu testen, ob ein Dokument außerhalb des Anwendungscontainers liegt oder nicht. Wird NSMetadataUbiquitousItemContainerDisplayNameKey verwendet, um auf den Namen des Containers zuzugreifen, der die originale Kopie eines externen Dokuments enthält.

Warum Dokumentverweise erforderlich sind

Der Standard Grund, warum iOS 8 Verweise für den Zugriff auf externe Dokumente verwendet, ist die Sicherheit. Keine Anwendung erhält Zugriff auf den Container einer anderen Anwendung. Nur die Dokumentauswahl kann dies tun, da der Prozess abgelaufen ist und über systemweiten Zugriff verfügt.

Die einzige Möglichkeit, zu einem Dokument außerhalb des Anwendungscontainers zu gelangen, besteht darin, die Dokumentauswahl zu verwenden, und wenn die von der Auswahl zurückgegebene URL Sicherheitsbereich ist. Die Sicherheitsbereichs-URL enthält gerade genug Informationen, um das Dokument zusammen mit den bereichsbezogenen Rechten auszuwählen, die erforderlich sind, um einer Anwendung Zugriff auf das Dokument zu gewähren.

Es ist wichtig zu beachten, dass die Sicherheitsinformationen verloren gehen und von der URL aus nicht mehr auf die Datei zugegriffen werden kann, wenn die Sicherheits-URL in eine Zeichenfolge serialisiert und dann deerialisiert wird. Die Dokumentverweisfunktion bietet einen Mechanismus, um zu den Dateien zurückzukehren, auf die von diesen URLs verwiesen wird.

Wenn die Anwendung also einen NSUrl von einem der Referenzdokumente abruft, ist der Sicherheitsbereich bereits angefügt und kann für den Zugriff auf die Datei verwendet werden. Aus diesem Grund wird dringend empfohlen, dass der Entwickler verwendet UIDocument , da er all diese Informationen und Prozesse für ihn verarbeitet.

Verwenden von Textmarken

Es ist nicht immer möglich, die Dokumente einer Anwendung aufzulisten, um zu einem bestimmten Dokument zurückzukehren, z. B. bei der Zustandswiederherstellung. iOS 8 bietet einen Mechanismus zum Erstellen von Lesezeichen, die direkt auf ein bestimmtes Dokument abzielen.

Mit dem folgenden Code wird ein Lesezeichen aus einer UIDocumentEigenschaft von 's FileUrl erstellt:

// Trap all errors
try {
    // Values to include in the bookmark packet
    var resources = new string[] {
        NSUrl.FileSecurityKey,
        NSUrl.ContentModificationDateKey,
        NSUrl.FileResourceIdentifierKey,
        NSUrl.FileResourceTypeKey,
        NSUrl.LocalizedNameKey
    };

    // Create the bookmark
    NSError err;
    Bookmark = Document.FileUrl.CreateBookmarkData (NSUrlBookmarkCreationOptions.WithSecurityScope, resources, iCloudUrl, out err);

    // Was there an error?
    if (err != null) {
        // Yes, report it
        Console.WriteLine ("Error Creating Bookmark: {0}", err.LocalizedDescription);
    }
}
catch (Exception e) {
    // Report error
    Console.WriteLine ("Error: {0}", e.Message);
}

Die vorhandene Lesezeichen-API wird verwendet, um ein Lesezeichen für ein vorhandenes NSUrl zu erstellen, das gespeichert und geladen werden kann, um direkten Zugriff auf eine externe Datei zu ermöglichen. Mit dem folgenden Code wird ein oben erstelltes Lesezeichen wiederhergestellt:

if (Bookmark != null) {
    // Trap all errors
    try {
        // Yes, attempt to restore it
        bool isBookmarkStale;
        NSError err;
        var srcUrl = new NSUrl (Bookmark, NSUrlBookmarkResolutionOptions.WithSecurityScope, iCloudUrl, out isBookmarkStale, out err);

        // Was there an error?
        if (err != null) {
            // Yes, report it
            Console.WriteLine ("Error Loading Bookmark: {0}", err.LocalizedDescription);
        } else {
            // Load document from bookmark
            OpenDocument (srcUrl);
        }
    }
    catch (Exception e) {
        // Report error
        Console.WriteLine ("Error: {0}", e.Message);
    }
}

Öffnen im Vergleich zum Importmodus und der Dokumentauswahl

Der Ansichtscontroller für die Dokumentauswahl verfügt über zwei verschiedene Betriebsmodi:

  1. Öffnen-Modus : Wenn der Benutzer ein externes Dokument auswählt, erstellt die Dokumentauswahl in diesem Modus ein Lesezeichen für den Sicherheitsbereich im Anwendungscontainer.

    Ein Sicherheitslesezeichen im Anwendungscontainer

  2. Importmodus : Wenn der Benutzer ein externes Dokument auswählt, erstellt die Dokumentauswahl in diesem Modus kein Lesezeichen, sondern kopiert die Datei in einen temporären Speicherort, und bietet der Anwendung Zugriff auf das Dokument an diesem Speicherort:

    Die Dokumentauswahl kopiert die Datei an einen temporären Speicherort und bietet der Anwendung Zugriff auf das Dokument an diesem Speicherort.
    Sobald die Anwendung aus irgendeinem Grund beendet wird, wird der temporäre Speicherort geleert und die Datei entfernt. Wenn die Anwendung Zugriff auf die Datei behalten muss, sollte sie eine Kopie erstellen und in ihrem Anwendungscontainer ablegen.

Der offene Modus ist nützlich, wenn die Anwendung mit einer anderen Anwendung zusammenarbeiten und alle änderungen, die am Dokument vorgenommen wurden, mit dieser Anwendung teilen möchte. Der Importmodus wird verwendet, wenn die Anwendung ihre Änderungen an einem Dokument nicht für andere Anwendungen freigeben möchte.

Ein Dokument extern gestalten

Wie bereits erwähnt, hat eine iOS 8-Anwendung keinen Zugriff auf Container außerhalb ihres eigenen Anwendungscontainers. Die Anwendung kann lokal in einen eigenen Container oder in einen temporären Speicherort schreiben und dann einen speziellen Dokumentmodus verwenden, um das resultierende Dokument außerhalb des Anwendungscontainers an einen vom Benutzer ausgewählten Speicherort zu verschieben.

Gehen Sie wie folgt vor, um ein Dokument an einen externen Speicherort zu verschieben:

  1. Erstellen Sie zunächst ein neues Dokument an einem lokalen oder temporären Speicherort.
  2. Erstellen Sie eine NSUrl , die auf das neue Dokument verweist.
  3. Öffnen Sie einen neuen Ansichtscontroller für die Dokumentauswahl, und übergeben Sie ihn NSUrl mit dem Modus von MoveToService .
  4. Sobald der Benutzer einen neuen Speicherort ausgewählt hat, wird das Dokument von seinem aktuellen Speicherort an den neuen Speicherort verschoben.
  5. Ein Referenzdokument wird in den Anwendungscontainer der App geschrieben, sodass die erstellende Anwendung weiterhin auf die Datei zugreifen kann.

Der folgende Code kann verwendet werden, um ein Dokument an einen externen Speicherort zu verschieben: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.MoveToService);

Das vom obigen Prozess zurückgegebene Referenzdokument entspricht genau dem, das vom Geöffneten Modus der Dokumentauswahl erstellt wurde. Es gibt jedoch Situationen, in denen die Anwendung ein Dokument verschieben möchte, ohne einen Verweis darauf zu behalten.

Verwenden Sie den ExportToService Modus, um ein Dokument zu verschieben, ohne einen Verweis zu generieren. Ein Beispiel: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.ExportToService);

Wenn Sie den ExportToService Modus verwenden, wird das Dokument in den externen Container kopiert, und die vorhandene Kopie wird am ursprünglichen Speicherort belassen.

Dokumentanbietererweiterungen

Mit iOS 8 möchte Apple, dass der Endbenutzer auf jedes seiner cloudbasierten Dokumente zugreifen kann, unabhängig davon, wo sie tatsächlich vorhanden sind. Um dieses Ziel zu erreichen, bietet iOS 8 einen neuen Mechanismus zur Dokumentanbietererweiterung.

Was ist eine Dokumentanbietererweiterung?

Einfach gesagt, ist eine Dokumentanbietererweiterung eine Möglichkeit für einen Entwickler oder einen Drittanbieter, einen alternativen Dokumentspeicher für eine Anwendung bereitzustellen, auf den genau auf die gleiche Weise wie der vorhandene iCloud-Speicherort zugegriffen werden kann.

Der Benutzer kann einen dieser alternativen Speicherorte in der Dokumentauswahl auswählen und die gleichen Zugriffsmodi (Öffnen, Importieren, Verschieben oder Exportieren) verwenden, um mit Dateien an diesem Speicherort zu arbeiten.

Dies wird mithilfe von zwei verschiedenen Erweiterungen implementiert:

  • Dokumentauswahlerweiterung : Stellt eine UIViewController Unterklasse bereit, die eine grafische Benutzeroberfläche bereitstellt, über die der Benutzer ein Dokument aus einem alternativen Speicherort auswählen kann. Diese Unterklasse wird als Teil des Ansichtscontrollers für die Dokumentauswahl angezeigt.
  • Dateierweiterung bereitstellen : Dies ist eine Nicht-UI-Erweiterung, die sich mit der tatsächlichen Bereitstellung der Dateiinhalte befasst. Diese Erweiterungen werden über Die Dateikoordination ( NSFileCoordinator ) bereitgestellt. Dies ist ein weiterer wichtiger Fall, in dem eine Dateikoordination erforderlich ist.

Das folgende Diagramm zeigt den typischen Datenfluss bei der Arbeit mit Dokumentanbietererweiterungen:

Dieses Diagramm zeigt den typischen Datenfluss bei der Arbeit mit Dokumentanbietererweiterungen.

Der folgende Prozess läuft ab:

  1. Die Anwendung stellt einen Dokumentauswahlcontroller bereit, mit dem der Benutzer eine Datei auswählen kann, mit der gearbeitet werden soll.
  2. Der Benutzer wählt einen alternativen Dateispeicherort aus, und die benutzerdefinierte UIViewController Erweiterung wird aufgerufen, um die Benutzeroberfläche anzuzeigen.
  3. Der Benutzer wählt eine Datei aus diesem Speicherort aus, und die URL wird an die Dokumentauswahl zurückgegeben.
  4. Die Dokumentauswahl wählt die URL der Datei aus und gibt sie an die Anwendung zurück, damit der Benutzer daran arbeiten kann.
  5. Die URL wird an den Dateikoordinator übergeben, um den Inhalt der Dateien an die Anwendung zurückzugeben.
  6. Der Dateikoordinator ruft die benutzerdefinierte Dateianbietererweiterung auf, um die Datei abzurufen.
  7. Der Inhalt der Datei wird an den Dateikoordinator zurückgegeben.
  8. Der Inhalt der Datei wird an die Anwendung zurückgegeben.

Sicherheit und Lesezeichen

In diesem Abschnitt erfahren Sie, wie Sicherheit und dauerhafter Dateizugriff über Lesezeichen mit Dokumentanbietererweiterungen funktionieren. Im Gegensatz zum iCloud-Dokumentanbieter, der Sicherheit und Lesezeichen automatisch im Anwendungscontainer speichert, sind Dokumentanbietererweiterungen nicht Teil des Dokumentverweissystems.

Beispiel: In einer Unternehmenseinstellung, die einen eigenen unternehmensweiten sicheren Datenspeicher bereitstellt, möchten Administratoren nicht, dass auf vertrauliche Unternehmensinformationen von den öffentlichen iCloud-Servern zugegriffen oder verarbeitet wird. Daher kann das integrierte Dokumentverweissystem nicht verwendet werden.

Das Lesezeichensystem kann weiterhin verwendet werden, und es liegt in der Verantwortung der Dateianbietererweiterung, eine als Lesezeichen markierte URL ordnungsgemäß zu verarbeiten und den Inhalt des Dokuments zurückzugeben, auf das von ihr verwiesen wird.

Aus Sicherheitsgründen verfügt iOS 8 über eine Isolationsebene, die die Informationen darüber speichert, welche Anwendung Zugriff auf welchen Bezeichner in welchem Dateianbieter hat. Beachten Sie, dass der gesamte Dateizugriff durch diese Isolationsebene gesteuert wird.

Das folgende Diagramm zeigt den Datenfluss bei der Arbeit mit Lesezeichen und einer Dokumentanbietererweiterung:

Dieses Diagramm zeigt den Datenfluss bei der Arbeit mit Lesezeichen und einer Dokumentanbietererweiterung.

Der folgende Prozess läuft ab:

  1. Die Anwendung wechselt in den Hintergrund und muss ihren Zustand beibehalten. Sie ruft NSUrl auf, um ein Lesezeichen für eine Datei im alternativen Speicher zu erstellen.
  2. NSUrl ruft die Dateianbietererweiterung auf, um eine persistente URL zum Dokument abzurufen.
  3. Die Dateianbietererweiterung gibt die URL als Zeichenfolge an zurück NSUrl .
  4. Der NSUrl packt die URL in einem Lesezeichen und gibt sie an die Anwendung zurück.
  5. Wenn die Anwendung aus dem Hintergrund erwacht und den Zustand wiederherstellen muss, übergibt sie das Lesezeichen an NSUrl .
  6. NSUrl ruft die Dateianbietererweiterung mit der URL der Datei auf.
  7. Der Dateierweiterungsanbieter greift auf die Datei zu und gibt den Speicherort der Datei an zurück NSUrl .
  8. Der Dateispeicherort wird mit Sicherheitsinformationen gebündelt und an die Anwendung zurückgegeben.

Von hier aus kann die Anwendung auf die Datei zugreifen und wie gewohnt damit arbeiten.

Schreiben von Dateien

In diesem Abschnitt wird die Funktionsweise des Schreibens von Dateien an einen alternativen Speicherort mit einer Dokumentanbietererweiterung erläutert. Die iOS-Anwendung verwendet die Dateikoordination, um Informationen im Anwendungscontainer auf dem Datenträger zu speichern. Kurz nachdem die Datei erfolgreich geschrieben wurde, wird die Dateianbietererweiterung über die Änderung benachrichtigt.

An diesem Punkt kann die Dateianbietererweiterung damit beginnen, die Datei an den alternativen Speicherort hochzuladen (oder die Datei als modifiziert und upload erforderlich markieren).

Erstellen neuer Dokumentanbietererweiterungen

Das Erstellen neuer Dokumentanbietererweiterungen liegt außerhalb des Rahmens dieses einführungsartikels. Diese Informationen werden hier bereitgestellt, um zu zeigen, dass eine Anwendung basierend auf den Erweiterungen, die ein Benutzer auf sein iOS-Gerät geladen hat, Zugriff auf Dokumentspeicherorte außerhalb des von Apple bereitgestellten iCloud-Speicherorts haben kann.

Der Entwickler sollte sich dieser Tatsache bewusst sein, wenn er die Dokumentauswahl verwendet und mit externen Dokumenten arbeitet. Sie sollten nicht davon ausgehen, dass diese Dokumente in iCloud gehostet werden.

Weitere Informationen zum Erstellen eines Speicheranbieters oder einer Dokumentauswahlerweiterung finden Sie im Dokument Einführung in App-Erweiterungen .

Migrieren zu iCloud Drive

Unter iOS 8 können Benutzer das vorhandene iCloud-Dokumentensystem weiterhin verwenden, das in iOS 7 (und früheren Systemen) verwendet wird, oder sie können vorhandene Dokumente zum neuen iCloud Drive-Mechanismus migrieren.

Unter Mac OS X Yosemite bietet Apple keine Abwärtskompatibilität, sodass alle Dokumente zu iCloud Drive migriert werden müssen, da sie sonst nicht mehr geräteübergreifend aktualisiert werden.

Nachdem das Konto eines Benutzers zu iCloud Drive migriert wurde, können nur Geräte, die iCloud Drive verwenden, Änderungen auf diesen Geräten an Dokumente weitergeben.

Wichtig

Entwickler sollten sich bewusst sein, dass die in diesem Artikel behandelten neuen Features nur verfügbar sind, wenn das Benutzerkonto zu iCloud Drive migriert wurde.

Zusammenfassung

In diesem Artikel wurden die Änderungen an vorhandenen iCloud-APIs behandelt, die zur Unterstützung von iCloud Drive und des neuen Ansichtscontrollers für die Dokumentauswahl erforderlich sind. Es wurde die Dateikoordination behandelt und warum sie bei der Arbeit mit cloudbasierten Dokumenten wichtig ist. Es wurde das Setup behandelt, das erforderlich ist, um cloudbasierte Dokumente in einer Xamarin.iOS-Anwendung zu aktivieren, und es wurde ein einführender Einblick in das Arbeiten mit Dokumenten außerhalb des Anwendungscontainers einer App mithilfe des Dokumentauswahl-Ansichtscontrollers gegeben.

Darüber hinaus behandelte dieser Artikel kurz Dokumentanbietererweiterungen und warum entwickler beim Schreiben von Anwendungen, die cloudbasierte Dokumente verarbeiten können, darauf achten sollte.