Compartilhar via


Seletor de documentos no Xamarin.iOS

O Seletor de Documentos permite que documentos sejam compartilhados entre aplicativos. Esses documentos podem ser armazenados no iCloud ou em um diretório de aplicativo diferente. Os documentos são compartilhados por meio do conjunto de Extensões do Provedor de Documentos que o usuário instalou em seu dispositivo.

Devido à dificuldade de manter os documentos sincronizados entre aplicativos e a nuvem, eles introduzem uma certa quantidade de complexidade necessária.

Requisitos

O seguinte é necessário para concluir as etapas apresentadas neste artigo:

  • Xcode 7 e iOS 8 ou mais recente – As APIs Xcode 7 e iOS 8 ou mais recentes da Apple precisam ser instaladas e configuradas no computador do desenvolvedor.
  • Visual Studio ou Visual Studio para Mac – A versão mais recente do Visual Studio para Mac deve ser instalada.
  • Dispositivo iOS – Um dispositivo iOS com iOS 8 ou superior.

Alterações no iCloud

Para implementar os novos recursos do Seletor de Documentos, as seguintes alterações foram feitas no Serviço iCloud da Apple:

  • O Daemon do iCloud foi completamente reescrito usando o CloudKit.
  • Os recursos existentes do iCloud foram renomeados para iCloud Drive.
  • O suporte para o sistema operacional Microsoft Windows foi adicionado ao iCloud.
  • Foi adicionada uma pasta do iCloud no Mac OS Finder.
  • Os dispositivos iOS podem acessar o conteúdo da pasta do Mac OS iCloud.

Importante

A Apple fornece ferramentas para ajudar os desenvolvedores a lidar adequadamente com o GDPR (Regulamento Geral sobre a Proteção de Dados) da União Europeia.

O que é um documento?

Ao se referir a um documento no iCloud, ele é uma entidade única e autônoma e deve ser percebido como tal pelo usuário. Um usuário pode desejar modificar o documento ou compartilhá-lo com outros usuários (usando e-mail, por exemplo).

Existem vários tipos de arquivos que o usuário reconhecerá imediatamente como Documentos, como arquivos do Pages, Keynote ou Numbers. No entanto, o iCloud não se limita a este conceito. Por exemplo, o estado de um jogo (como uma partida de xadrez) pode ser tratado como um documento e armazenado no iCloud. Esse arquivo pode ser passado entre os dispositivos de um usuário e permitir que ele pegue um jogo de onde parou em um dispositivo diferente.

Lidando com documentos

Antes de se aprofundar no código necessário para usar o Seletor de Documentos com o Xamarin, este artigo abordará as práticas recomendadas para trabalhar com Documentos do iCloud e várias das modificações feitas nas APIs existentes necessárias para oferecer suporte ao Seletor de Documentos.

Usando a coordenação de arquivos

Como um arquivo pode ser modificado de vários locais diferentes, a coordenação deve ser usada para evitar a perda de dados.

Usando a coordenação de arquivos

Vamos dar uma olhada na ilustração acima:

  1. Um dispositivo iOS usando coordenação de arquivos cria um novo documento e o salva na pasta do iCloud.
  2. O iCloud salva o arquivo modificado na nuvem para distribuição a todos os dispositivos.
  3. Um Mac anexado vê o arquivo modificado na Pasta do iCloud e usa a Coordenação de Arquivos para copiar as alterações no arquivo.
  4. Um dispositivo que não usa a Coordenação de Arquivos faz uma alteração no arquivo e o salva na Pasta do iCloud. Essas alterações são replicadas instantaneamente para os outros dispositivos.

Suponha que o dispositivo iOS original ou o Mac estava editando o arquivo, agora suas alterações são perdidas e substituídas pela versão do arquivo do dispositivo não coordenado. Para evitar a perda de dados, a Coordenação de Arquivos é imprescindível ao trabalhar com documentos baseados em nuvem.

Usando UIDocument

UIDocument torna as coisas simples (ou NSDocument no macOS) fazendo todo o trabalho pesado para o desenvolvedor. Ele fornece coordenação de arquivos integrada com filas em segundo plano para evitar o bloqueio da interface do usuário do aplicativo.

UIDocument expõe várias APIs de alto nível que facilitam o esforço de desenvolvimento de um aplicativo Xamarin para qualquer finalidade que o desenvolvedor exija.

O código a seguir cria uma subclasse de UIDocument para implementar um documento genérico baseado em texto que pode ser usado para armazenar e recuperar texto do iCloud:

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

A GenericTextDocument classe apresentada acima será usada ao longo deste artigo ao trabalhar com o Seletor de Documentos e documentos externos em um aplicativo Xamarin.iOS 8.

Coordenação de arquivos assíncronos

O iOS 8 fornece vários novos recursos de Coordenação de Arquivos Assíncronos por meio das novas APIs de Coordenação de Arquivos. Antes do iOS 8, todas as APIs de coordenação de arquivos existentes eram totalmente síncronas. Isso significava que o desenvolvedor era responsável por implementar sua própria fila em segundo plano para impedir que a Coordenação de Arquivos bloqueasse a interface do usuário do aplicativo.

A nova NSFileAccessIntent classe contém uma URL apontando para o arquivo e várias opções para controlar o tipo de coordenação necessária. O código a seguir demonstra mover um arquivo de um local para outro usando intenções:

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

Descobrindo e listando documentos

A maneira de descobrir e listar documentos é usando as APIs existentes NSMetadataQuery . Esta seção abordará novos recursos adicionados que tornam o NSMetadataQuery trabalho com documentos ainda mais fácil do que antes.

Comportamento existente

Antes do iOS 8, era lento para pegar alterações de arquivos locais, NSMetadataQuery tais como: exclui, cria e renomeia.

Visão geral das alterações no arquivo local NSMetadataQuery

No diagrama acima:

  1. Para arquivos que já existem no Contêiner de Aplicativos, NSMetadataQuery tem registros existentes NSMetadata pré-criados e spooled para que eles fiquem instantaneamente disponíveis para o aplicativo.
  2. O aplicativo cria um novo arquivo no contêiner de aplicativo.
  3. Há um atraso antes NSMetadataQuery de ver a modificação no contêiner de aplicativo e cria o registro necessário NSMetadata .

Devido ao atraso na criação do registro, o aplicativo teve que ter duas fontes de dados abertas: uma para alterações de NSMetadata arquivo local e outra para alterações baseadas em nuvem.

Costura

No iOS 8, NSMetadataQuery é mais fácil usar diretamente com um novo recurso chamado Stitching:

NSMetadataQuery com um novo recurso chamado Stitching

Usando costura no diagrama acima:

  1. Como antes, para arquivos que já existem no Contêiner de Aplicativos, NSMetadataQuery tem registros existentes NSMetadata pré-criados e spooled.
  2. O aplicativo cria um novo arquivo no contêiner de aplicativo usando a coordenação de arquivos.
  3. Um gancho no contêiner de aplicativo vê a modificação e chama NSMetadataQuery para criar o registro necessário NSMetadata .
  4. O NSMetadata registro é criado diretamente após o arquivo e é disponibilizado para o aplicativo.

Usando o Stitching, o aplicativo não precisa mais abrir uma fonte de dados para monitorar alterações de arquivo locais e baseadas em nuvem. Agora, o aplicativo pode contar diretamente NSMetadataQuery .

Importante

A costura só funciona se o Aplicativo estiver usando a Coordenação de Arquivos, conforme apresentado na seção acima. Se a Coordenação de Arquivos não estiver sendo usada, as APIs terão como padrão o comportamento existente anterior ao iOS 8.

Novos recursos de metadados do iOS 8

Os seguintes novos recursos foram adicionados ao NSMetadataQuery iOS 8:

  • NSMetatadataQuery agora pode listar documentos não locais armazenados na nuvem.
  • Novas APIs foram adicionadas para acessar informações de metadados nos documentos baseados em nuvem.
  • Há uma nova NSUrl_PromisedItems API que irá acessar os atributos de arquivo de arquivos que podem ou não ter seu conteúdo disponível localmente.
  • Use o GetPromisedItemResourceValue método para obter informações sobre um determinado arquivo ou use o GetPromisedItemResourceValues método para obter informações sobre mais de um arquivo ao mesmo tempo.

Dois novos sinalizadores de coordenação de arquivos foram adicionados para lidar com metadados:

  • NSFileCoordinatorReadImmediatelyAvailableMetadataOnly
  • NSFileCoordinatorWriteContentIndependentMetadataOnly

Com os sinalizadores acima, o conteúdo do arquivo Document não precisa estar disponível localmente para que eles sejam usados.

O segmento de código a seguir mostra como usar NSMetadataQuery para consultar a existência de um arquivo específico e compilar o arquivo se ele não existir:

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

Miniaturas de documentos

A Apple acha que a melhor experiência do usuário ao listar documentos para um aplicativo é usar visualizações. Isso dá contexto aos usuários finais, para que eles possam identificar rapidamente o documento com o qual desejam trabalhar.

Antes do iOS 8, a exibição de visualizações de documentos exigia uma implementação personalizada. Uma novidade no iOS 8 são os atributos do sistema de arquivos que permitem que o desenvolvedor trabalhe rapidamente com miniaturas de documentos.

Recuperando miniaturas de documentos

Ao chamar os métodos orGetPromisedItemResourceValues, NSUrl_PromisedItems a GetPromisedItemResourceValue API, a NSUrlThumbnailDictionary, é retornada. A única chave atualmente neste dicionário é o NSThumbnial1024X1024SizeKey e sua correspondência UIImage.

Salvando miniaturas de documentos

A maneira mais fácil de salvar uma miniatura é usando UIDocumento . Ao chamar o GetFileAttributesToWrite método do UIDocument e definir a miniatura, ele será salvo automaticamente quando o arquivo Document estiver. O Daemon do iCloud verá essa alteração e a propagará para o iCloud. No Mac OS X, as miniaturas são geradas automaticamente para o desenvolvedor pelo plug-in Quick Look.

Com as noções básicas de trabalho com documentos baseados no iCloud, juntamente com as modificações na API existente, estamos prontos para implementar o Controlador de Exibição do Seletor de Documentos em um aplicativo móvel Xamarin iOS 8.

Ativando o iCloud no Xamarin

Para que o Seletor de Documentos possa ser usado em um aplicativo Xamarin.iOS, o suporte ao iCloud precisa ser ativado tanto em seu aplicativo quanto via Apple.

As etapas a seguir explicam o processo de provisionamento para o iCloud.

  1. Crie um contêiner do iCloud.
  2. Crie uma ID de Aplicativo que contenha o Serviço de Aplicativo do iCloud.
  3. Crie um perfil de provisionamento que inclua essa ID do aplicativo.

O guia Trabalhando com recursos percorre as duas primeiras etapas. Para criar um perfil de provisionamento, siga as etapas no guia Perfil de provisionamento .

As etapas a seguir explicam o processo de configuração do aplicativo para o iCloud:

Faça o seguinte:

  1. Abra o projeto no Visual Studio para Mac ou Visual Studio.

  2. No Gerenciador de Soluções, clique com o botão direito do mouse no projeto e selecione Opções.

  3. Na caixa de diálogo Opções, selecione Aplicativo iOS, verifique se o Identificador de pacote corresponde ao que foi definido na ID do aplicativo criada acima para o aplicativo.

  4. Selecione Assinatura de pacote do iOS, selecione a Identidade do desenvolvedor e o perfil de provisionamento criados acima.

  5. Clique no botão OK para salvar as alterações e fechar a caixa de diálogo.

  6. Clique com o botão direito do mouse Entitlements.plist no Gerenciador de Soluções para abri-lo no editor.

    Importante

    No Visual Studio, talvez seja necessário abrir o editor de Direitos clicando com o botão direito do mouse nele, selecionando Abrir com... e selecionando Editor de Lista de Propriedades

  7. Marque Ativar iCloud , Documentos do iCloud, Armazenamento de chave-valor e CloudKit .

  8. Verifique se o contêiner existe para o aplicativo (conforme criado acima). Exemplo: iCloud.com.your-company.AppName

  9. Salve as alterações no arquivo.

Para obter mais informações sobre Direitos, consulte o guia Trabalhando com Direitos .

Com a configuração acima, o aplicativo agora pode usar documentos baseados em nuvem e o novo Controlador de Exibição do Seletor de Documentos.

Código de instalação comum

Antes de começar a usar o Controlador de Exibição do Seletor de Documentos, é necessário algum código de instalação padrão. Comece modificando o arquivo do AppDelegate.cs aplicativo e faça com que ele tenha a seguinte aparência:

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

Importante

O código acima inclui o código da seção Descobrindo e listando documentos acima. Ele é apresentado aqui na íntegra, como apareceria em um pedido real. Para simplificar, este exemplo funciona apenas com um único arquivo embutido em código (test.txt).

O código acima expõe vários atalhos do iCloud Drive para torná-los mais fáceis de trabalhar no restante do aplicativo.

Em seguida, adicione o seguinte código a qualquer modo de exibição ou contêiner de exibição que usará o Seletor de Documentos ou trabalhará com documentos baseados em nuvem:

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

Isso adiciona um atalho para acessar os atalhos do AppDelegate iCloud criados acima.

Com esse código em vigor, vamos dar uma olhada na implementação do Document Picker View Controller em um aplicativo Xamarin iOS 8.

Usando o controlador de exibição do seletor de documentos

Antes do iOS 8, era muito difícil acessar documentos de outro aplicativo porque não havia como descobrir documentos fora do aplicativo de dentro do aplicativo.

Comportamento existente

Visão geral do comportamento existente

Vamos dar uma olhada no acesso a um documento externo anterior ao iOS 8:

  1. Primeiro, o usuário teria que abrir o aplicativo que originalmente criou o documento.
  2. O documento é selecionado e o UIDocumentInteractionController é usado para enviar o documento para o novo aplicativo.
  3. Finalmente, uma cópia do documento original é colocada no contêiner do novo aplicativo.

A partir daí, o documento fica disponível para o segundo aplicativo ser aberto e editado.

Descobrindo documentos fora do contêiner de um aplicativo

No iOS 8, um aplicativo é capaz de acessar documentos fora de seu próprio contêiner de aplicativos com facilidade:

Descobrindo documentos fora do contêiner de um aplicativo

Usando o novo Seletor de Documentos do iCloud ( UIDocumentPickerViewController), um aplicativo iOS pode descobrir e acessar diretamente fora de seu Contêiner de Aplicativos. O UIDocumentPickerViewController fornece um mecanismo para que o usuário conceda acesso e edite os documentos descobertos por meio de permissões.

Um aplicativo deve optar por fazer com que seus Documentos apareçam no Seletor de Documentos do iCloud e estejam disponíveis para que outros aplicativos os descubram e trabalhem com eles. Para que um aplicativo Xamarin iOS 8 compartilhe seu Contêiner de Aplicativos, edite-o Info.plist em um editor de texto padrão e adicione as duas linhas a seguir à parte inferior do dicionário (entre as <dict>...</dict> tags):

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

O UIDocumentPickerViewController fornece uma ótima nova interface do usuário que permite ao usuário escolher documentos. Para exibir o Controlador de Exibição do Seletor de Documentos em um aplicativo Xamarin iOS 8, faça o seguinte:

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

Importante

O desenvolvedor deve chamar o StartAccessingSecurityScopedResource método do antes que NSUrl um documento externo possa ser acessado. O StopAccessingSecurityScopedResource método deve ser chamado para liberar o bloqueio de segurança assim que o documento for carregado.

Saída de exemplo

Aqui está um exemplo de como o código acima exibiria um Seletor de Documentos quando executado em um dispositivo iPhone:

  1. O usuário inicia o aplicativo e a interface principal é exibida:

    A interface principal é exibida

  2. O usuário toca no botão Ação na parte superior da tela e é solicitado a selecionar um Provedor de Documentos na lista de provedores disponíveis:

    Selecione um Provedor de Documentos na lista de provedores disponíveis

  3. O Controlador de Exibição do Seletor de Documentos é exibido para o Provedor de Documentos selecionado:

    O Controlador de Exibição do Seletor de Documentos é exibido

  4. O usuário toca em uma Pasta de Documentos para exibir seu conteúdo:

    O conteúdo da pasta de documentos

  5. O usuário seleciona um documento e o seletor de documentos é fechado.

  6. A interface principal é reexibida, o documento é carregado do contêiner externo e seu conteúdo exibido.

A exibição real do Controlador de Exibição do Seletor de Documentos depende dos Provedores de Documentos que o usuário instalou no dispositivo e do Modo de Seletor de Documentos que foi implementado. O exemplo acima está usando o Modo Aberto, os outros tipos de modo serão discutidos em detalhes abaixo.

Gerenciando documentos externos

Como discutido acima, antes do iOS 8, um aplicativo só podia acessar documentos que faziam parte de seu contêiner de aplicativos. No iOS 8, um aplicativo pode acessar documentos de fontes externas:

Visão geral do gerenciamento de documentos externos

Quando o usuário seleciona um documento de uma fonte externa, um documento de referência é gravado no contêiner de aplicativo que aponta para o documento original.

Para ajudar a adicionar essa nova capacidade aos aplicativos existentes, vários novos recursos foram adicionados à NSMetadataQuery API. Normalmente, um aplicativo usa o escopo de documento ubíquo para listar documentos que vivem em seu contêiner de aplicativo. Usando esse escopo, somente os documentos dentro do contêiner de aplicativo continuarão a ser exibidos.

O uso do novo Escopo de Documento Externo Ubíquo retornará Documentos que moram fora do Contêiner de Aplicativo e retornará os metadados para eles. O NSMetadataItemUrlKey apontará para a URL onde o documento está realmente localizado.

Às vezes, um aplicativo não quer trabalhar com os documentos que estão sendo apontados por referência. Em vez disso, o aplicativo deseja trabalhar diretamente com o Documento de Referência. Por exemplo, o aplicativo pode querer exibir o documento na pasta do aplicativo na interface do usuário ou permitir que o usuário mova as referências dentro de uma pasta.

No iOS 8, um novo NSMetadataItemUrlInLocalContainerKey foi fornecido para acessar o Documento de Referência diretamente. Essa chave aponta para a referência real ao documento externo em um contêiner de aplicativo.

O NSMetadataUbiquitousItemIsExternalDocumentKey é usado para testar se um documento é ou não externo ao contêiner de um aplicativo. O NSMetadataUbiquitousItemContainerDisplayNameKey é usado para acessar o nome do contêiner que está hospedando a cópia original de um documento externo.

Por que as referências de documentos são obrigatórias

A principal razão pela qual o iOS 8 usa referências para acessar documentos externos é a segurança. Nenhum aplicativo tem acesso ao Contêiner de qualquer outro aplicativo. Somente o Seletor de Documentos pode fazer isso, porque está ficando fora do processo e tem acesso em todo o sistema.

A única maneira de acessar um documento fora do Contêiner de Aplicativo é usando o Seletor de Documentos e se a URL retornada pelo seletor for Escopo de Segurança. A URL com escopo de segurança contém apenas informações suficientes para selecionar o documento, juntamente com os direitos de escopo necessários para conceder a um aplicativo acesso ao documento.

É importante observar que, se a URL com escopo de segurança fosse serializada em uma cadeia de caracteres e, em seguida, desserializada, as informações de segurança seriam perdidas e o arquivo ficaria inacessível a partir da URL. O recurso Referência de Documento fornece um mecanismo para voltar aos arquivos apontados por essas URLs.

Portanto, se o aplicativo adquirir um NSUrl de um dos Documentos de Referência, ele já tem o escopo de segurança anexado e pode ser usado para acessar o arquivo. Por esse motivo, é altamente recomendável que o desenvolvedor use UIDocument porque ele lida com todas essas informações e processos para eles.

Usar indicadores

Nem sempre é viável enumerar os Documentos de um aplicativo para voltar a um Documento específico, por exemplo, ao fazer a restauração de estado. O iOS 8 fornece um mecanismo para criar Favoritos que visam diretamente um determinado Documento.

O código a seguir criará um Bookmark a partir de uma UIDocumentpropriedade 's FileUrl :

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

A API de Marcador existente é usada para criar um Marcador em relação a um existente NSUrl que pode ser salvo e carregado para fornecer acesso direto a um arquivo externo. O código a seguir restaurará um indicador que foi criado acima:

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

Abrir vs. Modo de Importação e o Seletor de Documentos

O Controlador de Exibição do Seletor de Documentos apresenta dois modos diferentes de operação:

  1. Modo Aberto – Nesse modo, quando o usuário seleciona um Documento externo, o Seletor de Documentos criará um Indicador com Escopo de Segurança no Contêiner de Aplicativo.

    Um indicador com escopo de segurança no contêiner do aplicativo

  2. Modo de Importação – Nesse modo, quando o usuário seleciona um Documento externo, o Seletor de Documentos não cria um Indicador, mas copia o arquivo em um Local Temporário e fornece ao aplicativo acesso ao Documento neste local:

    O Seletor de Documentos copiará o arquivo em um Local Temporário e fornecerá ao aplicativo acesso ao Documento neste local
    Quando o aplicativo é encerrado por qualquer motivo, o Local Temporário é esvaziado e o arquivo removido. Se o aplicativo precisar manter o acesso ao arquivo, ele deverá fazer uma cópia e colocá-lo em seu contêiner de aplicativo.

O Modo Aberto é útil quando o aplicativo deseja colaborar com outro aplicativo e compartilhar quaisquer alterações feitas no documento com esse aplicativo. O Modo de Importação é usado quando o aplicativo não deseja compartilhar suas modificações em um documento com outros aplicativos.

Tornando um documento externo

Como mencionado acima, um aplicativo iOS 8 não tem acesso a contêineres fora de seu próprio contêiner de aplicativo. O aplicativo pode gravar em seu próprio contêiner localmente ou em um local temporário e, em seguida, usar um modo de documento especial para mover o documento resultante fora do contêiner de aplicativo para um local escolhido pelo usuário.

Para mover um documento para um local externo, faça o seguinte:

  1. Primeiro, crie um novo documento em um local local ou temporário.
  2. Crie um NSUrl que aponte para o novo Documento.
  3. Abra um novo Controlador de Exibição do Seletor de MoveToService Documentos e passe-o NSUrl com o Modo de .
  4. Depois que o usuário escolher um novo local, o documento será movido de seu local atual para o novo local.
  5. Um documento de referência será gravado no contêiner de aplicativo do aplicativo para que o arquivo ainda possa ser acessado pelo aplicativo de criação.

O código a seguir pode ser usado para mover um documento para um local externo: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.MoveToService);

O Documento de Referência retornado pelo processo acima é exatamente o mesmo criado pelo Modo Aberto do Seletor de Documentos. No entanto, há momentos em que o aplicativo pode desejar mover um documento sem manter uma referência a ele.

Para mover um documento sem gerar uma referência, use o ExportToService modo. Exemplo: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.ExportToService);

Ao usar o ExportToService modo, o documento é copiado para o contêiner externo e a cópia existente é deixada em seu local original.

Extensões do provedor de documentos

Com o iOS 8, a Apple quer que o usuário final possa acessar qualquer um de seus documentos baseados em nuvem, não importa onde eles realmente existam. Para atingir esse objetivo, o iOS 8 fornece um novo mecanismo de Extensão do Provedor de Documentos.

O que é uma extensão de provedor de documentos?

Simplificando, uma Extensão de Provedor de Documentos é uma maneira de um desenvolvedor, ou um terceiro, fornecer a um aplicativo armazenamento de documentos alternativo que pode ser acessado exatamente da mesma maneira que o local de armazenamento existente do iCloud.

O usuário pode selecionar um desses locais de armazenamento alternativos no Seletor de Documentos e pode usar exatamente os mesmos modos de acesso (Abrir, Importar, Mover ou Exportar) para trabalhar com arquivos nesse local.

Isso é implementado usando duas extensões diferentes:

  • Extensão do Seletor de Documentos – Fornece uma UIViewController subclasse que fornece uma interface gráfica para o usuário escolher um documento de um local de armazenamento alternativo. Essa subclasse será exibida como parte do Controlador de Exibição do Seletor de Documentos.
  • File Provide Extension - Esta é uma extensão não-UI que lida com realmente fornecer o conteúdo dos arquivos. Essas extensões são fornecidas através da Coordenação de Arquivos ( NSFileCoordinator ). Este é outro caso importante em que a Coordenação de Arquivos é necessária.

O diagrama a seguir mostra o fluxo de dados típico ao trabalhar com extensões de provedor de documentos:

Este diagrama mostra o fluxo de dados típico ao trabalhar com extensões de provedor de documento

Ocorre o seguinte processo:

  1. O aplicativo apresenta um controlador de seletor de documentos para permitir que o usuário selecione um arquivo para trabalhar.
  2. O usuário seleciona um local de arquivo alternativo e a extensão personalizada UIViewController é chamada para exibir a interface do usuário.
  3. O usuário seleciona um arquivo desse local e a URL é passada de volta para o Seletor de Documentos.
  4. O Seletor de Documentos seleciona a URL do arquivo e a retorna ao aplicativo para o usuário trabalhar.
  5. A URL é passada para o Coordenador de Arquivos para retornar o conteúdo dos arquivos ao aplicativo.
  6. O Coordenador de Arquivos chama a Extensão de Provedor de Arquivos personalizada para recuperar o arquivo.
  7. O conteúdo do arquivo é retornado ao Coordenador de Arquivos.
  8. O conteúdo do arquivo é retornado ao aplicativo.

Segurança e Favoritos

Esta seção examinará rapidamente como a segurança e o acesso persistente a arquivos por meio de Favoritos funcionam com as Extensões de Provedor de Documentos. Ao contrário do Provedor de Documentos do iCloud, que salva automaticamente a Segurança e os Marcadores no Contêiner de Aplicativos, as Extensões do Provedor de Documentos não o fazem porque não fazem parte do Sistema de Referência de Documentos.

Por exemplo: em uma configuração Enterprise que fornece seu próprio armazenamento de dados seguro em toda a empresa, os administradores não querem que informações corporativas confidenciais sejam acessadas ou processadas pelos Servidores iCloud públicos. Portanto, o sistema interno de referência de documento não pode ser usado.

O sistema Bookmark ainda pode ser usado e é responsabilidade da Extensão do Provedor de Arquivos processar corretamente uma URL marcada e retornar o conteúdo do Documento apontado por ela.

Para fins de segurança, o iOS 8 tem uma Camada de Isolamento que persiste as informações sobre qual aplicativo tem acesso a qual identificador dentro de qual Provedor de Arquivos. Deve-se notar que todo o acesso ao arquivo é controlado por essa camada de isolamento.

O diagrama a seguir mostra o fluxo de dados ao trabalhar com Marcadores e uma Extensão de Provedor de Documentos:

Este diagrama mostra o fluxo de dados ao trabalhar com Marcadores e uma Extensão de Provedor de Documentos

Ocorre o seguinte processo:

  1. O aplicativo está prestes a entrar em segundo plano e precisa manter seu estado. Ele chama NSUrl para criar um marcador para um arquivo no armazenamento alternativo.
  2. NSUrl chama a Extensão do Provedor de Arquivos para obter uma URL persistente para o Documento.
  3. A extensão do provedor de arquivos retorna a URL como uma cadeia de caracteres para o NSUrl .
  4. O NSUrl agrupa a URL em um Marcador e a retorna ao aplicativo.
  5. Quando o aplicativo desperta de estar em segundo plano e precisa restaurar o estado, ele passa o indicador para NSUrl .
  6. NSUrl chama a extensão do provedor de arquivos com a URL do arquivo.
  7. O provedor de extensão de arquivo acessa o arquivo e retorna o local do arquivo para NSUrl .
  8. O local do arquivo é empacotado com informações de segurança e retornado ao aplicativo.

A partir daqui, o aplicativo pode acessar o arquivo e trabalhar com ele normalmente.

Gravando arquivos

Esta seção examinará rapidamente como funciona gravar arquivos em um local alternativo com uma Extensão de Provedor de Documentos. O aplicativo iOS usará a Coordenação de Arquivos para salvar informações em disco dentro do Contêiner de Aplicativos. Logo após o arquivo ter sido gravado com êxito, a extensão do provedor de arquivos será notificada da alteração.

Neste ponto, a extensão do provedor de arquivos pode começar a carregar o arquivo para o local alternativo (ou marcar o arquivo como sujo e exigindo upload).

Criando novas extensões de provedor de documentos

A criação de novas extensões de provedor de documentos está fora do escopo deste artigo introdutório. Essas informações são fornecidas aqui para mostrar que, com base nas extensões que um usuário carregou em seu dispositivo iOS, um aplicativo pode ter acesso a locais de armazenamento de documentos fora do local do iCloud fornecido pela Apple.

O desenvolvedor deve estar ciente desse fato ao usar o Seletor de Documentos e trabalhar com Documentos externos. Eles não devem assumir que esses documentos estão hospedados no iCloud.

Para obter mais informações sobre como criar um provedor de armazenamento ou uma extensão do seletor de documentos, consulte o documento Introdução às extensões de aplicativo.

Migrando para o iCloud Drive

No iOS 8, os usuários podem optar por continuar usando o Sistema de Documentos do iCloud existente usado no iOS 7 (e sistemas anteriores) ou podem optar por migrar os Documentos existentes para o novo mecanismo do iCloud Drive.

No Mac OS X Yosemite, a Apple não fornece a compatibilidade com versões anteriores, portanto, todos os documentos devem ser migrados para o iCloud Drive ou não serão mais atualizados entre dispositivos.

Depois que a conta de um usuário for migrada para o iCloud Drive, somente os dispositivos que usam o iCloud Drive poderão propagar alterações no Documentos nesses dispositivos.

Importante

Os desenvolvedores devem estar cientes de que os novos recursos abordados neste artigo só estarão disponíveis se a conta do usuário tiver sido migrada para o iCloud Drive.

Resumo

Este artigo abordou as alterações nas APIs existentes do iCloud necessárias para oferecer suporte ao iCloud Drive e ao novo Controlador de Exibição do Seletor de Documentos. Ele abordou a Coordenação de Arquivos e por que ela é importante ao trabalhar com documentos baseados em nuvem. Ele cobriu a configuração necessária para habilitar documentos baseados em nuvem em um aplicativo Xamarin.iOS e deu uma visão introdutória sobre como trabalhar com documentos fora do contêiner de aplicativos de um aplicativo usando o controlador de exibição do seletor de documentos.

Além disso, este artigo abordou brevemente as extensões do provedor de documentos e por que o desenvolvedor deve estar ciente delas ao escrever aplicativos que podem lidar com documentos baseados em nuvem.