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.
  • ICloud에 Microsoft Windows OS에 대 한 지원이 추가 되었습니다.Support for Microsoft Windows OS has been added to iCloud.
  • Mac OS 파인더에서 iCloud 폴더를 추가 되었습니다.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. 예를 들어, (예: Chess 일치) 게임의 상태 문서로 처리 고 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 간편 하 게 작업 (또는 NSDocument macos) 개발자에 대 한 모든 주요 작업을 수행 하 여 합니다.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.

다음 코드의 서브 클래스를 만들고 UIDocument 저장 하 고 iCloud에서 텍스트를 검색할 수 있는 일반 텍스트 기반 문서를 구현 하려면: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. 전에 지연이 NSMetadataQuery 응용 프로그램 컨테이너에 수정 사항을 확인 하 고 필요한 만듭니다 NSMetadata 레코드입니다.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. 응용 프로그램 컨테이너에 이미 있는 파일에 대 한 이전 처럼 NSMetadataQuery 기존 NSMetadata 레코드 미리 만들고 스풀링됩니다.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. 수정 하 고 호출 응용 프로그램 컨테이너에서 후크를 볼 NSMetadataQuery 필요한 만들려면 NSMetadata 레코드입니다.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

다음과 같은 새로운 기능에 추가한 NSMetadataQuery ios 8: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 메서드 NSUrl_PromisedItems API를 NSUrlThumbnailDictionary, 반환 됩니다.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. 호출 하 여는 GetFileAttributesToWrite 메서드는 UIDocument 미리 보기 설정을 자동으로 저장 됩니다 문서 파일이 되 고 합니다.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 응용 프로그램에서 사용할 수 있습니다, iCloud 지원 응용 프로그램 및 Apple을 통해 사용 하도록 설정 해야 합니다.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 앱 서비스를 포함 하는 앱 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
    }
}

중요

위의 코드는 위의 Discovering 및 나열 하는 문서 섹션에서 코드를 포함합니다.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와 문서 선택기에에서 표시 되며 다른 응용 프로그램에 검색 하 고 작업을 사용할 수 있습니다.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;
}

중요

개발자를 호출 해야 합니다는 StartAccessingSecurityScopedResource 메서드는 NSUrl 외부 문서에 액세스할 수 있습니다.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. 위의 예제에는 오픈 모드를 사용 하는, 다른 모드 형식 아래에서 자세히 설명 됩니다.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);
    }
}

Vs를 엽니다. 가져오기 모드와 문서 선택기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. 새 문서 선택기 뷰 컨트롤러를 열고 전달 된 NSUrl 모드를 사용 하 여 MoveToService 입니다.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

Apple는 iOS 8 사용 하 여 최종 사용자가 실제로 있는 위치에 관계 없이 클라우드 기반 문서에 액세스할 수 있으려면를 하려고 합니다.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?

간단히 말해서 문서 공급자 확장 방법이 개발자 또는 제 3 자에 대 한 기존 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을 처리 하 고 여기에서 가리키는 문서의 내용을 반환 파일 공급자 확장 프로그램의 책임입니다.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 대체 storage에서 파일에 책갈피를 만들 수 있습니다.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 장치에 로드 된 확장에 따라 응용 프로그램에 액세스할 수 iCloud 위치를 제공 하는 Apple 외부의 문서 저장소 위치가 제공 됩니다.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의 경우 사용자는 문서 시스템이 기존 iCloud를 사용 하 여 iOS 7 (및 이전 시스템)에서 사용 하거나 새 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.