Xamarin.ios의 문서 선택기Document Picker in Xamarin.iOS

문서 선택기를 사용 하면 앱 간에 문서를 공유할 수 있습니다.The Document Picker allows documents to be shared between apps. 이러한 문서는 iCloud 또는 다른 앱의 디렉터리에 저장 될 수 있습니다.These documents may be stored in iCloud or in a different app’s directory. 문서는 사용자가 장치에 설치한 문서 공급자 확장 집합을 통해 공유 됩니다.Documents are shared via the set of Document Provider Extensions the user has installed on their device.

앱과 클라우드 간에 문서를 동기화 된 상태로 유지 하는 어려움 때문에 필요한 복잡성을 특정 하 게 소개 합니다.Because of the difficulty of keeping documents synchronized across apps and the cloud, they introduce a certain amount of necessary complexity.

요구 사항Requirements

이 문서에 제공 된 단계를 완료 하려면 다음이 필요 합니다.The following is required to complete the steps presented in this article:

  • Xcode 7 및 ios 8 이상 – Apple의 Xcode 7 및 ios 8 이상 api를 개발자의 컴퓨터에 설치 하 고 구성 해야 합니다.Xcode 7 and iOS 8 or newer – Apple's Xcode 7 and iOS 8 or newer APIs need to be installed and configured on the developer's computer.
  • Visual Studio 또는 Mac용 Visual Studio – Mac용 Visual Studio 최신 버전을 설치 해야 합니다.Visual Studio or Visual Studio for Mac – The latest version of Visual Studio for Mac should be installed.
  • Ios 장치 – ios 8 이상을 실행 하는 ios 장치입니다.iOS Device – An iOS device running iOS 8 or above.

ICloud의 변경 내용Changes to iCloud

문서 선택의 새 기능을 구현 하기 위해 Apple의 iCloud 서비스가 다음과 같이 변경 되었습니다.To implement the new features of the Document Picker, the following changes have been made to Apple's iCloud Service:

  • ICloud 데몬이 CloudKit를 사용 하 여 완전히 다시 작성 되었습니다.The iCloud Daemon has been completely rewritten using CloudKit.
  • 기존 iCloud 기능의 이름이 iCloud 드라이브로 바뀌었습니다.The existing iCloud features have been renamed iCloud Drive.
  • Microsoft Windows OS에 대 한 지원이 iCloud에 추가 되었습니다.Support for Microsoft Windows OS has been added to iCloud.
  • ICloud 폴더가 Mac OS Finder에 추가 되었습니다.An iCloud folder has been added in the Mac OS Finder.
  • iOS 장치는 Mac OS iCloud 폴더의 내용에 액세스할 수 있습니다.iOS devices can access the contents of the Mac OS iCloud folder.

중요

Apple에서는 개발자가 유럽 연합의 GDPR(일반 데이터 보호 규정)을 제대로 처리하는 데 도움이 되는 도구를 제공합니다.Apple provides tools to help developers properly handle the European Union's General Data Protection Regulation (GDPR).

문서 란 무엇 인가요?What is a Document?

ICloud의 문서를 참조 하는 경우이는 단일 독립 실행형 엔터티 이며 사용자가 해당 문서를 인식 해야 합니다.When referring to a Document in iCloud, it is a single, stand-alone entity and should be perceived as such by the user. 사용자가 문서를 수정 하거나 전자 메일을 사용 하 여 다른 사용자와 공유할 수 있습니다.A user may wish to modify the document or share it with other users (by using email, for example).

사용자가 문서 (예: 페이지, 키 노트 또는 숫자 파일)로 즉시 인식할 수 있는 여러 형식의 파일이 있습니다.There are several types of files that the user will immediately recognize as Documents, such as Pages, Keynote or Numbers files. 그러나 iCloud는 이러한 개념으로 제한 되지 않습니다.However, iCloud is not limited to this concept. 예를 들어 게임의 상태 (예: 체스 일치)를 문서로 처리 하 고 iCloud에 저장할 수 있습니다.For example, the state of a game (such as a Chess match) can be treated as a document and stored in iCloud. 이 파일은 사용자의 장치 간에 전달 될 수 있으며, 다른 장치에서 남은 게임을 선택할 수 있습니다.This file could be passed between a user's devices and allow them to pick up a game where they left off on a different device.

문서 처리Dealing with Documents

Xamarin과 함께 문서 선택기를 사용 하는 데 필요한 코드를 살펴보기 전에이 문서에서는 iCloud 문서 작업에 대 한 모범 사례와 문서 선택기를 지 원하는 데 필요한 기존 Api에 대 한 몇 가지 수정 사항을 소개 합니다.Before diving into the code required to use the Document Picker with Xamarin, this article is going to cover the best practices for working with iCloud Documents, and several of the modifications made to existing APIs required to support the Document Picker.

파일 조정 사용Using File Coordination

파일은 여러 위치에서 수정할 수 있으므로 데이터 손실을 방지 하려면 조정을 사용 해야 합니다.Because a file can be modified from several different locations, coordination must be used to prevent data loss.

위의 그림을 살펴보겠습니다.Let's take a look at the above illustration:

  1. 파일 조정을 사용 하는 iOS 장치는 새 문서를 만들어 iCloud 폴더에 저장 합니다.An iOS device using file coordination creates a new Document and saves it to the iCloud Folder.
  2. iCloud는 모든 장치에 배포 하기 위해 수정 된 파일을 클라우드에 저장 합니다.iCloud saves the modified file to the cloud for distribution to every device.
  3. 연결 된 Mac은 iCloud 폴더에서 수정 된 파일을 확인 하 고 파일 조정을 사용 하 여 변경 내용을 파일에 복사 합니다.An attached Mac sees the modified file in the iCloud Folder and uses File Coordination to copy down the changes to the file.
  4. 파일 조정을 사용 하지 않는 장치에서는 파일을 변경 하 고 iCloud 폴더에 저장 합니다.A device not using File Coordination makes a change to the file and saves it to the iCloud Folder. 이러한 변경 내용은 다른 장치에 즉시 복제 됩니다.These changes are instantly replicated to the other devices.

원본 iOS 장치 또는 Mac에서 파일을 편집 한다고 가정 하면 변경 내용이 손실 되 고 조정 되지 않은 장치에서 파일의 버전으로 덮어쓰여집니다.Assume the original iOS device or the Mac was editing the file, now their changes are lost and overwritten with the version of the file from the uncoordinated device. 데이터 손실을 방지 하기 위해 클라우드 기반 문서를 사용할 때 파일 조정을 사용 해야 합니다.To prevent data loss, File Coordination is a must when working with cloud-based Documents.

UIDocument 사용Using UIDocument

UIDocument는 개발자를 위한 모든 작업을 수행 하 여 작업을 간단 하 게 하거나 macOS에서 NSDocument 합니다.UIDocument makes things simple (or NSDocument on macOS) by doing all of the heavy lifting for the developer. 응용 프로그램의 UI를 차단 하지 않도록 백그라운드 큐와 기본 제공 파일 조정을 제공 합니다.It provides built in File Coordination with background queues to keep from blocking the application's UI.

UIDocument는 개발자가 필요로 하는 모든 목적을 위해 Xamarin 응용 프로그램의 개발 노력을 용이 하 게 하는 여러 개의 높은 수준의 Api를 노출 합니다.UIDocument exposes multiple, high-level APIs that ease the development effort of a Xamarin application for any purpose the developer requires.

다음 코드는 iCloud에서 텍스트를 저장 하 고 검색 하는 데 사용할 수 있는 일반 텍스트 기반 문서를 구현 하 UIDocument의 서브 클래스를 만듭니다.The following code creates a subclass of UIDocument to implement a generic text-based document that can be used to store and retrieve text from 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
    }
}

위에 표시 된 GenericTextDocument 클래스는 Xamarin.ios 8 응용 프로그램에서 문서 선택기 및 외부 문서를 사용할 때이 문서 전체에서 사용 됩니다.The GenericTextDocument class presented above will be used throughout this article when working with the Document Picker and external Documents in a Xamarin.iOS 8 application.

비동기 파일 조정Asynchronous File Coordination

iOS 8은 새로운 파일 조정 Api를 통해 몇 가지 새로운 비동기 파일 조정 기능을 제공 합니다.iOS 8 provides several new Asynchronous File Coordination features via the new File Coordination APIs. IOS 8 이전에는 기존의 모든 파일 조정 Api가 완전히 동기화 되었습니다.Before iOS 8, all existing File Coordination APIs were totally synchronous. 즉, 개발자는 파일 조정이 응용 프로그램의 UI를 차단 하지 않도록 자체 백그라운드 큐를 구현 해야 했습니다.This meant the developer was responsible for implementing their own background queuing to prevent File Coordination from blocking the application's UI.

NSFileAccessIntent 클래스에는 파일을 가리키는 URL과 필요한 조정 유형을 제어 하는 몇 가지 옵션이 포함 되어 있습니다.The new NSFileAccessIntent class contains a URL pointing to the file and several options to control the type of coordination required. 다음 코드에서는 의도를 사용 하 여 한 위치에서 다른 위치로 파일을 이동 하는 방법을 보여 줍니다.The following code demonstrates moving a file from one location to another using intents:

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

문서 검색 및 나열Discovering and Listing Documents

문서를 검색 하 고 나열 하는 방법은 기존 NSMetadataQuery Api를 사용 하는 것입니다.The way to discover and list Documents is by using the existing NSMetadataQuery APIs. 이 섹션에서는 이전 보다 훨씬 쉽게 문서 작업을 수행 하는 NSMetadataQuery에 추가 된 새로운 기능에 대해 설명 합니다.This section will cover new features added to NSMetadataQuery that make working with Documents even easier than before.

기존 동작Existing Behavior

IOS 8 이전에는 NSMetadataQuery 삭제, 만들기 및 이름 변경 등의 픽업 로컬 파일 변경에 대 한 속도가 느립니다.Prior to iOS 8, NSMetadataQuery was slow to pickup local file changes such as: deletes, creates and renames.

위의 다이어그램에서:In the above diagram:

  1. 응용 프로그램 컨테이너에 이미 있는 파일의 경우, NSMetadataQuery에는 응용 프로그램에서 즉시 사용할 수 있도록 미리 생성 된 레코드와 스풀링된 기존 NSMetadata 레코드가 있습니다.For files that already exist in the Application Container, NSMetadataQuery has existing NSMetadata records pre-created and spooled so they are instantly available to the application.
  2. 응용 프로그램은 응용 프로그램 컨테이너에 새 파일을 만듭니다.The application creates a new file in the Application Container.
  3. 응용 프로그램 컨테이너에 대 한 수정 내용을 확인 하 고 필요한 NSMetadata 레코드를 만드는 NSMetadataQuery 하기 전에 지연이 발생 합니다.There is a delay before NSMetadataQuery sees the modification to the Application Container and creates the required NSMetadata record.

NSMetadata 레코드 만들기의 지연으로 인해 응용 프로그램에는 로컬 파일 변경에 대 한 데이터 소스와 클라우드 기반 변경 내용 중 하나를 열어 두는 두 개의 데이터 원본이 있습니다.Because of the delay in the creation of the NSMetadata record, the application had to have two data sources open: one for local file changes and one for cloud based changes.

중철Stitching

IOS 8에서는 중철 이라는 새로운 기능을 사용 하 여 NSMetadataQuery을 더 쉽게 사용할 수 있습니다.In iOS 8, NSMetadataQuery is easier to use directly with a new feature called Stitching:

위의 다이어그램에서 중철 사용:Using Stitching in the above diagram:

  1. 이전 처럼 응용 프로그램 컨테이너에 이미 있는 파일의 경우 기존 NSMetadata 레코드를 미리 만들고 스풀링 NSMetadataQuery 있습니다.As before, for files that already exist in the Application Container, NSMetadataQuery has existing NSMetadata records pre-created and spooled.
  2. 응용 프로그램은 파일 조정을 사용 하 여 응용 프로그램 컨테이너에 새 파일을 만듭니다.The application creates a new file in the Application Container using File Coordination.
  3. 응용 프로그램 컨테이너의 후크는 필요한 NSMetadata 레코드를 만들기 위한 수정 및 호출 NSMetadataQuery를 확인 합니다.A hook in the Application Container sees the modification and calls NSMetadataQuery to create the required NSMetadata record.
  4. NSMetadata 레코드는 파일 바로 뒤에 생성 되며 응용 프로그램에서 사용할 수 있게 됩니다.The NSMetadata record is created directly after the file and is made available to the application.

중철를 사용 하 여 응용 프로그램은 더 이상 로컬 및 클라우드 기반 파일 변경 내용을 모니터링 하기 위해 데이터 원본을 열 필요가 없습니다.By using Stitching the application no longer has to open a data source to monitor local and cloud based file changes. 이제 응용 프로그램이 NSMetadataQuery를 직접 사용할 수 있습니다.Now the application can rely on NSMetadataQuery directly.

중요

중철는 응용 프로그램이 위의 섹션에서 설명한 대로 파일 조정을 사용 하는 경우에만 작동 합니다.Stitching only works if the Application is using File Coordination as presented in the section above. 파일 조정을 사용 하지 않는 경우 Api는 기존 사전 iOS 8 동작을 기본값으로 사용 합니다.If File Coordination is not being used, the APIs default to the existing pre iOS 8 behavior.

새 iOS 8 메타 데이터 기능New iOS 8 Metadata Features

IOS 8의 NSMetadataQuery에는 다음과 같은 새로운 기능이 추가 되었습니다.The following new features have been added to NSMetadataQuery in iOS 8:

  • 이제 클라우드에 저장 된 로컬이 아닌 문서를 나열할 수 NSMetatadataQuery.NSMetatadataQuery can now list non-local documents stored in the cloud.
  • 클라우드 기반 문서에서 메타 데이터 정보에 액세스 하기 위해 새 Api가 추가 되었습니다.New APIs have been added to access metadata information on the cloud-based documents.
  • 로컬에서 사용 가능한 콘텐츠를 사용 하거나 사용 하지 않을 수 있는 파일의 파일 특성에 액세스 하는 새로운 NSUrl_PromisedItems API가 있습니다.There is a new NSUrl_PromisedItems API that will to access the file attributes of files that may or may not have their content available locally.
  • GetPromisedItemResourceValue 메서드를 사용 하 여 지정 된 파일에 대 한 정보를 가져오거나 GetPromisedItemResourceValues 메서드를 사용 하 여 한 번에 두 개 이상의 파일에 대 한 정보를 가져옵니다.Use the GetPromisedItemResourceValue method to get information about a given file or use the GetPromisedItemResourceValues method to get information on more than one file at a time.

메타 데이터를 처리 하기 위해 두 개의 새로운 파일 조정 플래그가 추가 되었습니다.Two new file coordination flags have been added for dealing with metadata:

  • NSFileCoordinatorReadImmediatelyAvailableMetadataOnly
  • NSFileCoordinatorWriteContentIndependentMetadataOnly

위의 플래그를 사용 하면 문서 파일의 콘텐츠를 사용 하기 위해 로컬에서 사용할 필요가 없습니다.With the above flags, the contents of the Document file do not need to be available locally for them to be used.

다음 코드 세그먼트에서는 NSMetadataQuery 사용 하 여 특정 파일의 존재 여부를 쿼리하고 파일이 없는 경우 파일을 빌드하는 방법을 보여 줍니다.The following code segment shows how to use NSMetadataQuery to query for the existence of a specific file and build the file if it doesn't exist:

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

문서 미리 보기Document Thumbnails

Apple은 응용 프로그램에 대 한 문서를 나열할 때 최상의 사용자 환경을 미리 보기를 사용 하는 것으로 생각 합니다.Apple feels that the best user experience when listing documents for an application is to use previews. 그러면 최종 사용자 컨텍스트가 제공 되므로 작업 하려는 문서를 빠르게 식별할 수 있습니다.This gives the end users context, so they can quickly identify the document that they want to work with.

IOS 8 이전에는 문서 미리 보기에 사용자 지정 구현이 필요 했습니다.Prior to iOS 8, showing document previews required a custom implementation. IOS 8의 새로운 기능은 개발자가 문서 미리 보기를 빠르게 사용할 수 있도록 하는 파일 시스템 특성입니다.New to iOS 8 are file system attributes that allow the developer to quickly work with Document Thumbnails.

문서 축소판 그림 검색Retrieving Document Thumbnails

GetPromisedItemResourceValue 또는 GetPromisedItemResourceValues 메서드를 호출 하 여 NSUrlThumbnailDictionary``NSUrl_PromisedItems API를 반환 합니다.By calling the GetPromisedItemResourceValue or GetPromisedItemResourceValues methods, NSUrl_PromisedItems API, a NSUrlThumbnailDictionary, is returned. 현재이 사전의 유일한 키는 NSThumbnial1024X1024SizeKey와 일치 하는 UIImage입니다.The only key currently in this dictionary is the NSThumbnial1024X1024SizeKey and its matching UIImage.

문서 미리 보기 저장Saving Document Thumbnails

축소판 그림을 저장 하는 가장 쉬운 방법은 UIDocument를 사용 하는 것입니다.The easiest way to save a thumbnail is by using UIDocument. UIDocumentGetFileAttributesToWrite 메서드를 호출 하 고 미리 보기를 설정 하면 문서 파일이 인 경우 자동으로 저장 됩니다.By calling the GetFileAttributesToWrite method of the UIDocument and setting the thumbnail, it will automatically be saved when the Document file is. ICloud 데몬에는이 변경 내용이 표시 되 고 iCloud로 전파 됩니다.The iCloud Daemon will see this change and propagate it to iCloud. Mac OS X에서 빠른 보기 플러그 인을 통해 개발자에 대 한 미리 보기가 자동으로 생성 됩니다.On Mac OS X, thumbnails are automatically generated for the developer by the Quick Look plugin.

기존 API에 대 한 수정 사항과 함께 iCloud 기반 문서로 작업 하는 기본 사항을 사용 하 여 Xamarin iOS 8 모바일 응용 프로그램에서 문서 선택 보기 컨트롤러를 구현할 준비가 되었습니다.With the basics of working with iCloud based Documents in place, along with the modifications to existing API, we are ready to implement the Document Picker View Controller in a Xamarin iOS 8 Mobile Application.

Xamarin에서 iCloud 사용Enabling iCloud in Xamarin

문서 선택기를 Xamarin.ios 응용 프로그램에서 사용할 수 있으려면 먼저 응용 프로그램과 Apple을 통해 iCloud 지원을 사용 하도록 설정 해야 합니다.Before the Document Picker can be used in a Xamarin.iOS Application, iCloud support needs to be enabled both in your application and via Apple.

다음 단계에서는 iCloud에 대 한 프로 비전 프로세스를 연습 합니다.The following steps walkthrough the process of provisioning for iCloud.

  1. ICloud 컨테이너를 만듭니다.Create an iCloud Container.
  2. ICloud App Service를 포함 하는 앱 ID를 만듭니다.Create an App ID that contains the iCloud App Service.
  3. 이 앱 ID를 포함 하는 프로 비전 프로필을 만듭니다.Create a Provisioning profile that includes this App ID.

기능 사용 가이드는 처음 두 단계를 안내 합니다.The Working with Capabilities guide walks through the first two steps. 프로 비전 프로필을 만들려면 프로 비전 프로필 가이드의 단계를 따릅니다.To create a provisioning profile, follow the steps in the Provisioning Profile guide.

다음 단계에서는 iCloud 용 응용 프로그램을 구성 하는 프로세스를 설명 합니다.The following steps walkthrough the process of configuring your application for iCloud:

다음을 수행합니다.Do the following:

  1. Mac용 Visual Studio 또는 Visual Studio에서 프로젝트를 엽니다.Open the project in Visual Studio for Mac or Visual Studio.

  2. 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭 하 고 옵션을 선택 합니다.In the Solution Explorer, right-click the project and select Options.

  3. 옵션 대화 상자에서 IOS 응용 프로그램을 선택 하 고 번들 식별자 가 응용 프로그램에 대해 위에서 만든 앱 ID 에 정의 된 것과 일치 하는지 확인 합니다.In the Options Dialog Box select iOS Application, ensure that the Bundle Identifier matches the one that was defined in App ID created above for the application.

  4. IOS 번들 서명을 선택 하 고 위에서 만든 개발자 Id프로 비전 프로필 을 선택 합니다.Select iOS Bundle Signing, select the Developer Identity and the Provisioning Profile created above.

  5. 확인 단추를 클릭 하 여 변경 내용을 저장 하 고 대화 상자를 닫습니다.Click the OK button to save the changes and close the dialog box.

  6. 솔루션 탐색기 에서 Entitlements.plist를 마우스 오른쪽 단추로 클릭 하 여 편집기에서 엽니다.Right-click on Entitlements.plist in the Solution Explorer to open it in the editor.

    중요

    Visual Studio에서 마우스 오른쪽 단추를 클릭 하 고 연결 프로그램 ... 을 선택 하 여 자격 편집기를 열어야 할 수도 있습니다.In Visual Studio you may need to open the Entitlements editor by right-clicking on it, selecting Open With… 속성 목록 편집기를 선택 합니다.and selecting Property List Editor

  7. ICloud, Icloud 문서 , 키-값 저장소cloudkit 사용 을 선택 합니다.Check Enable iCloud , iCloud Documents , Key-value storage and CloudKit .

  8. 위에서 만든 응용 프로그램에 대 한 컨테이너가 있는지 확인 합니다.Ensure the Container exists for the application (as created above). 예: iCloud.com.your-company.AppNameExample: iCloud.com.your-company.AppName

  9. 파일의 변경 내용을 저장합니다.Save the changes to the file.

자격에 대 한 자세한 내용은 자격 사용 가이드를 참조 하세요.For more information on Entitlements refer to the Working with Entitlements guide.

위의 설정이 적용 되 면 응용 프로그램은 이제 클라우드 기반 문서와 새 문서 선택 보기 컨트롤러를 사용할 수 있습니다.With the above setup in place, the application can now use cloud-based documents and the new Document Picker View Controller.

일반 설정 코드Common Setup Code

문서 선택 보기 컨트롤러를 시작 하기 전에 몇 가지 표준 설정 코드가 필요 합니다.Before getting started with the Document Picker View Controller, there is some standard setup code required. 응용 프로그램의 AppDelegate.cs 파일을 수정 하 여 시작 하 고 다음과 같이 만듭니다.Start by modifying the application's AppDelegate.cs file and make it look like the following:

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

중요

위의 코드에는 위의 문서 검색 및 나열 섹션의 코드가 포함 되어 있습니다.The above code includes the code from the Discovering and Listing Documents section above. 실제 응용 프로그램에 표시 되는 것 처럼 전체에 표시 됩니다.It is presented here in its entirety, as it would appear in an actual application. 간단히 하기 위해이 예제는 하드 코드 된 단일 파일 (test.txt) 에서만 작동 합니다.For simplicity, this example works with a single, hard-coded file (test.txt) only.

위의 코드는 응용 프로그램의 나머지 부분에서 보다 쉽게 작업할 수 있도록 몇 가지 iCloud 드라이브 바로 가기를 제공 합니다.The above code exposes several iCloud Drive shortcuts to make them easier to work with in the rest of the application.

다음으로, 문서 선택기를 사용 하거나 클라우드 기반 문서로 작업 하는 모든 뷰 또는 뷰 컨테이너에 다음 코드를 추가 합니다.Next, add the following code to any view or view container that will be using the Document Picker or working with cloud-based documents:

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

그러면 AppDelegate에 대 한 바로 가기가 추가 되 고 위에서 만든 iCloud 바로 가기에 액세스할 수 있습니다.This adds a shortcut to get to the AppDelegate and access the iCloud shortcuts created above.

이 코드를 사용 하 여 Xamarin iOS 8 응용 프로그램에서 문서 선택기 보기 컨트롤러를 구현 하는 방법을 살펴보겠습니다.With this code in place, let's take a look at implementing the Document Picker View Controller in a Xamarin iOS 8 application.

문서 선택기 보기 컨트롤러 사용Using the Document Picker View Controller

IOS 8 이전에는 앱 내에서 응용 프로그램 외부의 문서를 검색할 수 있는 방법이 없기 때문에 다른 응용 프로그램의 문서에 액세스 하는 것은 매우 어렵습니다.Prior to iOS 8, it was very difficult to access Documents from another application because there was no way to discover documents outside of the application from within the app.

기존 동작Existing Behavior

IOS 8 이전의 외부 문서에 액세스 하는 방법을 살펴보겠습니다.Let's take a look at accessing an external document prior to iOS 8:

  1. 먼저 사용자는 처음에 문서를 만든 응용 프로그램을 열어야 합니다.First the user would have to open the application that originally created the Document.
  2. 문서를 선택 하 고 UIDocumentInteractionController를 사용 하 여 문서를 새 응용 프로그램으로 보냅니다.The Document is selected and the UIDocumentInteractionController is used to send the Document to the new application.
  3. 마지막으로, 원래 문서의 복사본이 새 응용 프로그램의 컨테이너에 배치 됩니다.Finally, a copy of the original Document is placed in the new application's Container.

이 문서에서 두 번째 응용 프로그램을 열고 편집할 수 있습니다.From there the Document is available for the second application to open and edit.

앱 컨테이너 외부에서 문서 검색Discovering Documents Outside of an App's Container

IOS 8에서 응용 프로그램은 자체 응용 프로그램 컨테이너 외부의 문서에 쉽게 액세스할 수 있습니다.In iOS 8, an application is able to access Documents outside of its own Application Container with ease:

새 iCloud 문서 선택기 (UIDocumentPickerViewController)를 사용 하 여 iOS 응용 프로그램은 응용 프로그램 컨테이너 외부에서 직접 검색 하 고 액세스할 수 있습니다.Using the new iCloud Document Picker ( UIDocumentPickerViewController), an iOS application can directly discover and access outside of its Application Container. UIDocumentPickerViewController은 사용자가 권한을 통해 검색 된 문서에 대 한 액세스를 부여 하 고 편집 하는 메커니즘을 제공 합니다.The UIDocumentPickerViewController provides a mechanism for the user to grant access to and edit those discovered Documents via permissions.

응용 프로그램은 해당 문서가 iCloud 문서 선택기에 표시 되 고 다른 응용 프로그램에서 해당 문서를 검색 하 고 사용할 수 있도록 옵트인 (opt in) 해야 합니다.An application must opt-in to have its Documents show up in the iCloud Document Picker and be available for other applications to discover and work with them. Xamarin iOS 8 응용 프로그램이 해당 응용 프로그램 컨테이너를 공유 하 게 하려면 표준 텍스트 편집기에서 파일 Info.plist 파일을 편집 하 고 <dict>...</dict> 태그 사이에 다음 두 줄을 사전 아래쪽에 추가 합니다.To have a Xamarin iOS 8 application share its Application Container, edit it Info.plist file in a standard text editor and add the following two lines to the bottom of the dictionary (between the <dict>...</dict> tags):

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

UIDocumentPickerViewController에서는 사용자가 문서를 선택할 수 있는 유용한 새 UI를 제공 합니다.The UIDocumentPickerViewController provides a great new UI that allows the user to choose documents. Xamarin iOS 8 응용 프로그램에서 문서 선택 보기 컨트롤러를 표시 하려면 다음을 수행 합니다.To display the Document Picker View Controller in a Xamarin iOS 8 application, do the following:

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

중요

개발자는 외부 문서에 액세스할 수 있으려면 먼저 NSUrlStartAccessingSecurityScopedResource 메서드를 호출 해야 합니다.The developer must call the StartAccessingSecurityScopedResource method of the NSUrl before an external document can be accessed. 문서가 로드 되는 즉시 보안 잠금을 해제 하려면 StopAccessingSecurityScopedResource 메서드를 호출 해야 합니다.The StopAccessingSecurityScopedResource method must be called to release the security lock as soon as the document has been loaded.

샘플 출력Sample Output

다음은 iPhone 장치에서 실행 될 때 위의 코드가 문서 선택기를 표시 하는 방법의 예입니다.Here is an example of how the code above would display a Document Picker when run on an iPhone device:

  1. 사용자가 응용 프로그램을 시작 하면 기본 인터페이스가 표시 됩니다.The user starts the application and the main interface is displayed:

  2. 사용자가 화면 위쪽에 있는 작업 단추를 탭 하면 사용 가능한 공급자 목록에서 문서 공급자 를 선택 하 라는 메시지가 표시 됩니다.The user taps the Action Button at the top of the screen and is asked to select a Document Provider from the list of available providers:

  3. 선택한 문서 공급자에 대해 문서 선택기 보기 컨트롤러가 표시 됩니다.The Document Picker View Controller is displayed for the selected Document Provider:

  4. 사용자는 문서 폴더 를 탭 하 여 해당 내용을 표시 합니다.The user taps on a Document Folder to display its contents:

  5. 사용자가 문서 를 선택 하면 문서 선택 이 닫힙니다.The user selects a Document and the Document Picker is closed.

  6. 주 인터페이스는 다시 표시 되 고, 문서 는 외부 컨테이너에서 로드 되 고 콘텐츠는 표시 됩니다.The main interface is redisplayed, the Document is loaded from the external Container and its contents displayed.

문서 선택기 보기 컨트롤러의 실제 표시는 사용자가 장치에 설치 하 고 문서 선택기 모드가 구현 된 문서 공급자에 따라 달라 집니다.The actual display of the Document Picker View Controller depends on the Document Providers that the user has installed on the device and which Document Picker Mode has been implement. 위의 예에서는 Open 모드를 사용 하 고 있으며, 다른 모드 유형에 대해서는 아래에서 자세히 설명 합니다.The above example is using the Open Mode, the other mode types will be discussed in detail below.

외부 문서 관리Managing External Documents

위에서 설명한 것 처럼 iOS 8 이전에 응용 프로그램은 응용 프로그램 컨테이너의 일부인 문서에만 액세스할 수 있었습니다.As discussed above, prior to iOS 8, an application could only access documents that were a part of its Application Container. IOS 8에서 응용 프로그램은 외부 소스에서 문서에 액세스할 수 있습니다.In iOS 8 an application can access Documents from external sources:

사용자가 외부 소스에서 문서를 선택 하면 원본 문서를 가리키는 참조 문서가 응용 프로그램 컨테이너에 기록 됩니다.When the user selects a Document from an external source, a Reference Document is written to the Application Container that points to the original Document.

이 새로운 기능을 기존 응용 프로그램에 추가 하는 데 도움이 되도록 NSMetadataQuery API에 몇 가지 새로운 기능이 추가 되었습니다.To assist in adding this new ability into existing applications, several new features have been added to the NSMetadataQuery API. 일반적으로 응용 프로그램은 응용 프로그램 컨테이너 내에 상주 하는 문서를 나열 하는 데 사용할 수 있는 문서 범위를 사용 합니다.Typically, an application uses the Ubiquitous Document Scope to list documents that live within its Application Container. 이 범위를 사용 하면 응용 프로그램 컨테이너 내의 문서만 계속 표시 됩니다.Using this scope, only documents within the Application Container will continue to be displayed.

새 데이터를 사용 하는 외부 문서 범위를 사용 하면 응용 프로그램 컨테이너 외부에 있는 문서를 반환 하 고 그에 대 한 메타 데이터를 반환 합니다.Using the new Ubiquitous External Document Scope will return Documents that live outside the Application Container and return the metadata for them. NSMetadataItemUrlKey는 문서가 실제로 위치한 URL을 가리킵니다.The NSMetadataItemUrlKey will point to the URL where the Document is actually located.

응용 프로그램에서 참조 하는 문서에 대 한 작업을 수행 하지 않으려는 경우가 있습니다.Sometimes an application doesn't want to work with the Documents being pointed to by th reference. 대신, 앱이 참조 문서를 직접 사용 하려고 합니다.Instead, the app wants to work with the Reference Document directly. 예를 들어, 응용 프로그램은 UI의 응용 프로그램 폴더에 문서를 표시 하거나 사용자가 폴더 내에서 참조를 이동할 수 있도록 합니다.For example, the app may want to display the document in the Application's folder in the UI, or to allow the user to move the references around inside a folder.

IOS 8에서는 참조 문서에 직접 액세스 하기 위해 새 NSMetadataItemUrlInLocalContainerKey 제공 됩니다.In iOS 8, a new NSMetadataItemUrlInLocalContainerKey has been provided to access the Reference Document directly. 이 키는 응용 프로그램 컨테이너의 외부 문서에 대 한 실제 참조를 가리킵니다.This key points to the actual reference to the external document in an Application Container.

NSMetadataUbiquitousItemIsExternalDocumentKey는 문서가 응용 프로그램 컨테이너 외부에 있는지 여부를 테스트 하는 데 사용 됩니다.The NSMetadataUbiquitousItemIsExternalDocumentKey is used to test whether or not a document is external to an Application's Container. NSMetadataUbiquitousItemContainerDisplayNameKey는 외부 문서의 원래 복사본을 보유 하는 컨테이너의 이름에 액세스 하는 데 사용 됩니다.The NSMetadataUbiquitousItemContainerDisplayNameKey is used to access the name of the Container that is housing the original copy of an external Document.

문서 참조가 필요한 이유Why Document References are Required

IOS 8에서 외부 문서에 액세스 하기 위해 참조를 사용 하는 주된 이유는 보안입니다.The main reason that iOS 8 uses references to access external Documents is security. 응용 프로그램에 다른 응용 프로그램의 컨테이너에 대 한 액세스 권한이 부여 되지 않았습니다.No application is given access to any other application's Container. 가 out-of-process로 실행 되 고 시스템 전체에 액세스할 수 있으므로 문서 선택기만이 작업을 수행할 수 있습니다.Only the Document Picker can do that, because is running out-of-process and has system wide access.

응용 프로그램 컨테이너 외부의 문서를 가져오는 유일한 방법은 문서 선택기를 사용 하 고, 선택에서 반환 된 URL은 보안 범위가 지정 된 경우입니다.The only way to get to a document outside of the Application Container is by using the Document Picker, and if the URL returned by the picker is Security Scoped. 보안 범위 URL에는 문서에 대 한 응용 프로그램 액세스 권한을 부여 하는 데 필요한 범위 지정 권한과 함께 문서를 선택 하는 데 필요한 정보만 포함 되어 있습니다.The Security Scoped URL contains just enough information to selected the document along with the scoped rights required to grant an application access to the document.

보안 범위가 지정 된 URL을 문자열로 serialize 한 다음 deserialize 하는 경우 보안 정보가 손실 되 고 URL에서 파일에 액세스할 수 없게 됩니다.It is important to note that if the Security Scoped URL was serialized into a string and then de-serialized, the Security Information would be lost and the file would be inaccessible from the URL. 문서 참조 기능은 이러한 Url에서 가리키는 파일을 다시 가져오는 메커니즘을 제공 합니다.The Document Reference feature provides a mechanism to get back to the files pointed to by these URLs.

따라서 응용 프로그램이 참조 문서 중 하나에서 NSUrl를 가져오는 경우 이미 보안 범위가 연결 되어 있으며 파일에 액세스 하는 데 사용할 수 있습니다.So if the application acquires an NSUrl from one of the Reference Documents, it already has the security scope attached and can be used to access the file. 따라서 개발자는이 모든 정보 및 프로세스를 처리 하기 때문에 UIDocument를 사용 하는 것이 좋습니다.For this reason, it is highly suggested that the developer use UIDocument because it handles all of this information and processes for them.

책갈피 사용Using Bookmarks

상태 복원을 수행 하는 경우와 같이 특정 문서에 다시 가져오기 위해 응용 프로그램의 문서를 열거 하는 것은 항상 불가능 합니다.It is not always feasible to enumerate an application's Documents to get back to a specific Document, for example, when doing state restoration. iOS 8은 지정 된 문서를 직접 대상으로 지정 하는 책갈피를 만드는 메커니즘을 제공 합니다.iOS 8 provides a mechanism to create Bookmarks that directly target a given Document.

다음 코드에서는 UIDocumentFileUrl 속성에서 책갈피를 만듭니다.The following code will create a Bookmark from a UIDocument's FileUrl property:

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

기존 책갈피 API는 외부 파일에 대 한 직접 액세스를 제공 하기 위해 저장 하 고 로드할 수 있는 기존 NSUrl에 대해 책갈피를 만드는 데 사용 됩니다.The existing Bookmark API is used to create a Bookmark against an existing NSUrl that can be saved and loaded to provide direct access to an external file. 다음 코드는 위에서 만든 책갈피를 복원 합니다.The following code will restore a bookmark that was created above:

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

열기 및 가져오기 모드와 문서 선택기Open vs. Import Mode and the Document Picker

문서 선택기 뷰 컨트롤러는 두 가지 작업 모드를 제공 합니다.The Document Picker View Controller features two different modes of operation:

  1. 열기 모드 –이 모드에서 사용자가 및 외부 문서를 선택 하면 문서 선택기는 응용 프로그램 컨테이너에 보안 범위가 지정 된 책갈피를 만듭니다.Open Mode – In this mode, when the user selects and external Document, the Document Picker will create a Security Scoped Bookmark in the Application Container.

  2. 가져오기 모드 –이 모드에서 사용자가 및 외부 문서를 선택 하면 문서 선택기에서 책갈피를 만들지 않고 파일을 임시 위치에 복사한 다음이 위치의 문서에 대 한 액세스를 응용 프로그램에 제공 합니다.Import Mode – In this mode, when the user selects and external Document, the Document Picker will not create a Bookmark, but instead, copy the file into a Temporary Location and provide the application access to the Document at this location:


    응용 프로그램이 어떤 이유로 든 종료 되 면 임시 위치가 비워지고 파일이 제거 됩니다.Once the application terminates for any reason, the Temporary Location is emptied and the file removed. 응용 프로그램은 파일에 대 한 액세스를 유지 해야 하는 경우 복사본을 만들어 응용 프로그램 컨테이너에 저장 해야 합니다.If the application needs to maintain access to the file, it should make a copy and place it in its Application Container.

열기 모드는 응용 프로그램에서 다른 응용 프로그램과 공동 작업을 수행 하 고 문서의 모든 변경 내용을 해당 응용 프로그램과 공유 하려는 경우에 유용 합니다.The Open Mode is useful when the application wishes to collaborate with another application and share any changes made to the document with that application. 가져오기 모드는 응용 프로그램에서 다른 응용 프로그램과의 문서 수정 내용을 공유 하지 않으려는 경우에 사용 됩니다.The Import Mode is used when the application does not want to share its modifications to a Document with other applications.

외부 문서 만들기Making a Document External

위에서 설명한 것 처럼 iOS 8 응용 프로그램은 자체 응용 프로그램 컨테이너 외부의 컨테이너에 액세스할 수 없습니다.As noted above, an iOS 8 application does not have access to containers outside of its own Application Container. 응용 프로그램은 로컬 또는 임시 위치에 자신의 컨테이너에 쓸 수 있으며, 특별 한 문서 모드를 사용 하 여 응용 프로그램 컨테이너 외부의 결과 문서를 사용자가 선택한 위치로 이동할 수 있습니다.The application can write to its own container locally or into a Temporary Location, then use a special document mode to move the resulting Document outside of the Application Container to a user chosen location.

문서를 외부 위치로 이동 하려면 다음을 수행 합니다.To move a Document to an external location, do the following:

  1. 먼저 로컬 또는 임시 위치에 새 문서를 만듭니다.First create a new Document in a local or temporary location.
  2. 새 문서를 가리키는 NSUrl를 만듭니다.Create a NSUrl that points to the new Document.
  3. 새 문서 선택기 보기 컨트롤러를 열고 MoveToService 모드로 NSUrl 전달 합니다.Open a new Document Picker View Controller and pass it the NSUrl with the Mode of MoveToService .
  4. 사용자가 새 위치를 선택 하면 문서가 현재 위치에서 새 위치로 이동 됩니다.Once the user chooses a new location, the Document will be moved from its current location to the new location.
  5. 응용 프로그램을 만드는 중에도 파일에 액세스할 수 있도록 참조 문서는 앱의 응용 프로그램 컨테이너에 기록 됩니다.A Reference Document will be written to the app's Application Container so that the file can still be accessed by the creating application.

다음 코드를 사용 하 여 문서를 외부 위치로 이동할 수 있습니다. var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.MoveToService);The following code can be used to move a Document to an external location: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.MoveToService);

위의 프로세스에서 반환 된 참조 문서는 문서 선택기의 열기 모드로 만든 참조 문서와 동일 합니다.The Reference Document returned by the above process is exactly the same as one created by the Open Mode of the Document Picker. 그러나 응용 프로그램에서 문서에 대 한 참조를 유지 하지 않고 문서를 이동 하려는 경우가 있습니다.However, there are times that the application might wish to move a Document without keeping a reference to it.

참조를 생성 하지 않고 문서를 이동 하려면 ExportToService 모드를 사용 합니다.To move a Document without generating a reference, use the ExportToService Mode. 예: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.ExportToService);Example: var picker = new UIDocumentPickerViewController (srcURL, UIDocumentPickerMode.ExportToService);

ExportToService 모드를 사용 하는 경우 문서는 외부 컨테이너에 복사 되 고 기존 복사본은 원래 위치에 남아 있습니다.When using the ExportToService mode, the Document is copied to the external Container and the existing copy is left in its original location.

문서 공급자 확장Document Provider Extensions

IOS 8을 사용 하는 경우 Apple은 최종 사용자가 실제로 존재 하는 위치에 관계 없이 클라우드 기반 문서에 액세스할 수 있도록 원합니다.With iOS 8, Apple wants the end user to be able to access any of their cloud-based documents, no matter where they actually exist. 이러한 목표를 달성 하기 위해 iOS 8은 새로운 문서 공급자 확장 메커니즘을 제공 합니다.To achieve this goal, iOS 8 provides a new Document Provider Extension mechanism.

문서 공급자 확장 이란?What is a Document Provider Extension?

간단히 말해서, 문서 공급자 확장은 개발자 또는 타사에서 기존 iCloud 저장소 위치와 정확히 같은 방식으로 액세스할 수 있는 응용 프로그램 대체 문서 저장소에 제공 하는 방법입니다.Simply stated, a Document Provider Extension is a way for a developer, or a third-party, to provide to an application alternative document storage that can be accessed in the exact same way as the existing iCloud storage location.

사용자는 문서 선택기에서 이러한 대체 저장소 위치 중 하나를 선택할 수 있으며, 동일한 액세스 모드 (열기, 가져오기, 이동 또는 내보내기)를 사용 하 여 해당 위치의 파일 작업을 수행할 수 있습니다.The user can select one of these alternative storage locations from the Document Picker and they can use the exact same access modes (Open, Import, Move or Export) to work with files in that location.

이는 두 가지 확장을 사용 하 여 구현 됩니다.This is implemented using two different extensions:

  • 문서 선택기 확장 – 사용자가 대체 저장소 위치에서 문서를 선택할 수 있는 그래픽 인터페이스를 제공 하는 UIViewController 하위 클래스를 제공 합니다.Document Picker Extension – Provides a UIViewController subclass that provides a graphical interface for the user to choose a document from an alternative storage location. 이 하위 클래스는 문서 선택기 보기 컨트롤러의 일부로 표시 됩니다.This subclass will be displayed as part of the Document Picker View Controller.
  • 파일 제공 확장명 – 실제로 파일 내용을 제공 하는 것을 처리 하는 비 UI 확장입니다.File Provide Extension – This is a non-UI extension that deals with actually providing the files contents. 이러한 확장은 파일 조정 (NSFileCoordinator)을 통해 제공 됩니다.These extensions are provided through File Coordination ( NSFileCoordinator ). 이는 파일 조정이 필요한 또 다른 중요 한 사례입니다.This is another important case where File Coordination is required.

다음 다이어그램에서는 문서 공급자 확장을 사용 하는 경우 일반적인 데이터 흐름을 보여 줍니다.The following diagram shows the typical data flow when working with Document Provider Extensions:

다음 프로세스가 발생 합니다.The following process occurs:

  1. 응용 프로그램은 사용자가 사용할 파일을 선택할 수 있는 문서 선택기 컨트롤러를 제공 합니다.The application presents a Document Picker Controller to allow the user to select a file to work with.
  2. 사용자가 대체 파일 위치를 선택 하 고 사용자 지정 UIViewController 확장을 호출 하 여 사용자 인터페이스를 표시 합니다.The user selects an alternative file location and the custom UIViewController extension is called to display the user interface.
  3. 사용자가이 위치에서 파일을 선택 하면 URL이 문서 선택기로 다시 전달 됩니다.The user selects a file from this location and the URL is passed back to the Document Picker.
  4. 문서 선택기는 파일의 URL을 선택 하 고 사용자가 작업할 수 있도록 응용 프로그램에 반환 합니다.The Document Picker selects the file's URL and returns it to the application for the user to work on.
  5. URL은 파일의 콘텐츠를 응용 프로그램에 반환 하기 위해 파일 코디네이터로 전달 됩니다.The URL is passed to the File Coordinator to return the files contents to the application.
  6. 파일 코디네이터는 사용자 지정 파일 공급자 확장명을 호출 하 여 파일을 검색 합니다.The File Coordinator calls the custom File Provider Extension to retrieve the file.
  7. 파일의 내용이 파일 코디네이터로 반환 됩니다.The contents of the file are returned to the File Coordinator.
  8. 파일의 내용이 응용 프로그램에 반환 됩니다.The contents of the file are returned to the application.

보안 및 책갈피Security and Bookmarks

이 섹션에서는 책갈피를 통한 보안 및 영구 파일 액세스와 문서 공급자 확장의 작동 방식을 간략히 살펴봅니다.This section will take a quick look at how security and persistent file access through Bookmarks works with Document Provider Extensions. 응용 프로그램 컨테이너에 보안과 책갈피를 자동으로 저장 하는 iCloud 문서 공급자와 달리 문서 공급자 확장은 문서 참조 시스템에 포함 되지 않기 때문에 그렇지 않습니다.Unlike the iCloud Document Provider, which automatically saves Security and Bookmarks to the Application Container, Document Provider Extensions don't because they are not a part of the Document Reference System.

예: 회사 전체의 보안 데이터 저장소를 제공 하는 엔터프라이즈 설정에서 관리자는 기밀 회사 정보를 공용 iCloud 서버에서 액세스 하거나 처리 하지 않도록 합니다.For example: in an Enterprise setting that provides its own company-wide secure datastore, administrators don't want confidential corporate information accessed or processed by the public iCloud Servers. 따라서 기본 제공 문서 참조 시스템은 사용할 수 없습니다.Therefore, the built-in Document Reference System cannot be used.

책갈피 시스템은 여전히 사용할 수 있으며, 책갈피 된 URL을 올바르게 처리 하 고 해당 URL이 가리키는 문서의 내용을 반환 하는 파일 공급자 확장의 책임입니다.The Bookmark system can still be used and it is the responsibility of the File Provider Extension to correctly process a bookmarked URL and return the contents of the Document pointed to by it.

보안을 위해 iOS 8에는 어떤 응용 프로그램에 액세스 하는 응용 프로그램에 대 한 정보를 유지 하는 격리 계층이 파일 공급자 내에 있습니다.For security purposes, iOS 8 has an Isolation Layer that persists the information about which application has access to which identifier inside which File Provider. 모든 파일 액세스는이 격리 계층에 의해 제어 됩니다.It should be noted that all file access is controlled by this Isolation Layer.

다음 다이어그램에서는 책갈피와 문서 공급자 확장을 사용 하 여 작업할 때의 데이터 흐름을 보여 줍니다.The following diagram shows the data flow when working with Bookmarks and a Document Provider Extension:

다음 프로세스가 발생 합니다.The following process occurs:

  1. 응용 프로그램이 백그라운드에서 시작 하 여 상태를 유지 해야 하는 경우The application is about to enter the background and needs to persist its state. NSUrl를 호출 하 여 대체 저장소에 파일에 대 한 책갈피를 만듭니다.It calls NSUrl to create a bookmark to a file in alternative storage.
  2. NSUrl는 파일 공급자 확장을 호출 하 여 문서에 대 한 영구 URL을 가져옵니다.NSUrl calls the File Provider Extension to get a persistent URL to the Document.
  3. 파일 공급자 확장은 URL을 NSUrl에 대 한 문자열로 반환 합니다.The File Provider Extension returns the URL as a string to the NSUrl .
  4. NSUrl는 URL을 책갈피로 묶어 응용 프로그램에 반환 합니다.The NSUrl bundles the URL into a Bookmark and returns it to the application.
  5. 응용 프로그램이 백그라운드에서 시작 하 여 상태를 복원 해야 하는 경우에는 NSUrl에 책갈피를 전달 합니다.When the Application awakes from being in the background and needs to restore state, it passes the Bookmark to NSUrl .
  6. NSUrl는 파일의 URL을 사용 하 여 파일 공급자 확장명을 호출 합니다.NSUrl calls the File Provider Extension with the URL of the file.
  7. 파일 확장명 공급자는 파일에 액세스 하 고 NSUrl 파일의 위치를 반환 합니다.The File Extension Provider accesses the file and returns the location of the file to NSUrl .
  8. 파일 위치는 보안 정보와 함께 제공 되며 응용 프로그램으로 반환 됩니다.The file location is bundled with security information and returned to the application.

여기에서 응용 프로그램은 파일에 액세스 하 고 정상적으로 작업할 수 있습니다.From here, the application can access the file and work with it as normal.

파일 쓰기Writing Files

이 섹션에서는 문서 공급자 확장을 사용 하 여 대체 위치에 파일을 작성 하는 방법을 간략히 살펴봅니다.This section will take a quick look at how writing files to an alternative location with a Document Provider Extension works. IOS 응용 프로그램은 파일 조정을 사용 하 여 응용 프로그램 컨테이너 내에서 디스크에 정보를 저장 합니다.The iOS application will use File Coordination to save information to disk inside the Application Container. 파일이 성공적으로 작성 되 고 나면 파일 공급자 확장에 변경 내용이 알려집니다.Shortly after the file has been successfully written, the File Provider Extension will be notified of the change.

이 시점에서 파일 공급자 확장은 대체 위치에 파일을 업로드 하기 시작할 수 있습니다 (또는 파일을 더티로 표시 하 고 업로드를 요구).At this point, the File Provider Extension can start uploading the file to the alternative location (or mark the file as dirty and requiring upload).

새 문서 공급자 확장 만들기Creating New Document Provider Extensions

새 문서 공급자 확장을 만드는 과정은이 소개 문서에서 다루지 않습니다.Creating new Document Provider Extensions is outside of the scope of this introductory article. 이 정보는 사용자가 iOS 장치에서 로드 한 확장에 따라 응용 프로그램이 Apple에서 제공 하는 iCloud 위치 외부의 문서 저장소 위치에 액세스할 수 있음을 보여 주기 위해 여기에 제공 됩니다.This information is provided here to show that, based on the extensions a user has loaded in their iOS device, an application may have access to Document storage locations outside of the Apple provided iCloud location.

개발자는 문서 선택기를 사용 하 고 외부 문서를 사용할 때 이러한 사실을 알고 있어야 합니다.The developer should be aware of this fact when using the Document Picker and working with external Documents. 이러한 문서는 iCloud에서 호스트 되는 것으로 가정 하면 안 됩니다.They should not assume those Document are hosted in iCloud.

저장소 공급자 또는 문서 선택기 확장을 만드는 방법에 대 한 자세한 내용은 앱 확장 소개 문서를 참조 하세요.For more information on creating a Storage Provider or Document Picker Extension, please see the Introduction to App Extensions document.

ICloud 드라이브로 마이그레이션Migrating to iCloud Drive

IOS 8에서 사용자는 iOS 7 (및 이전 시스템)에서 사용 되는 기존 iCloud 문서 시스템을 계속 사용 하거나 기존 문서를 새 iCloud 드라이브 메커니즘으로 마이그레이션하도록 선택할 수 있습니다.On iOS 8, users can choose to continue using the existing iCloud Documents System used in iOS 7 (and prior systems) or they can choose to migrate existing Documents to the new iCloud Drive mechanism.

Mac OS X Yosemite에서 Apple은 이전 버전과의 호환성을 제공 하지 않으므로 모든 문서를 iCloud 드라이브로 마이그레이션해야 하며 더 이상 장치 간에 업데이트 되지 않습니다.On Mac OS X Yosemite, Apple does not provide the backwards compatibility so all documents must be migrated to iCloud Drive or they will no longer be updated across devices.

사용자 계정이 iCloud 드라이브로 마이그레이션된 후에는 iCloud 드라이브를 사용 하는 장치만 해당 장치에서 문서에 변경 내용을 전파할 수 있습니다.After a user's account has been migrated to iCloud Drive, only devices using iCloud Drive will be able to propagate changes to Documents across those devices.

중요

이 문서에서 다루는 새로운 기능은 사용자 계정이 iCloud 드라이브로 마이그레이션된 경우에만 사용할 수 있다는 것을 알고 있어야 합니다.Developers should be aware that the new features covered in this article are only available if the user's account has been migrated to iCloud Drive.

요약Summary

이 문서에서는 iCloud 드라이브 및 새 문서 선택기 보기 컨트롤러를 지 원하는 데 필요한 기존 iCloud Api에 대 한 변경 내용을 설명 했습니다.This article has covered the changes to existing iCloud APIs required to support iCloud Drive and the new Document Picker View Controller. 파일 조정을 수행 하 고 클라우드 기반 문서로 작업할 때 중요 한 이유입니다.It has covered File Coordination and why it is important when working with cloud-based documents. Xamarin.ios 응용 프로그램에서 클라우드 기반 문서를 사용 하도록 설정 하는 데 필요한 설정에 대해 설명 하 고, 문서 선택기 보기 컨트롤러를 사용 하 여 앱의 응용 프로그램 컨테이너 외부 문서에 대 한 작업을 소개 합니다.It has covered the setup required to enable cloud-based documents in a Xamarin.iOS Application and given an introductory look at working with documents outside an app's Application Container using the Document Picker View Controller.

또한이 문서에서는 문서 공급자 확장 및 클라우드 기반 문서를 처리할 수 있는 응용 프로그램을 작성할 때 개발자가 알아야 하는 이유에 대해 간략하게 설명 합니다.In addition, this article briefly covered Document Provider Extensions and why the developer should be aware of them when writing applications that can handle cloud-based documents.