本节由CocoaChina翻译组成员星夜暮晨(博客)翻译自苹果官方文档 App Extension Programming Guide - Document Provider一节,敬请勘误。
在iOS中,所有使用可远程存储常用文件格式的应用程序应当考虑创建Document Provider应用扩展。这个应用扩展(有时简称为文档提供程序)允许其他应用程序来访问您应用程序所管理的文件。此外,与特定文件类型密切相关的应用程序可能会受益于为他们的文档创建文档选择器。在这里,作为特定类型文档的本地存储库,Document Provider能够让用户将所有这些文件收集到一个地方。
用Document Provider应用扩展管理文档,能够让所有应用程序借助文档选择器view controller来访问这些文档。当涉及到管理和共享文档的操作时,这种组合给用户带来了很大的灵活性。
初识Document Provider扩展
Document Provider应用扩展作为您应用程序管理的文件和用户设备上其他应用程序的接口。它允许其他应用程序导入或打开文件、上传并根据需要从服务器上下载文件。应用程序也可以导出或移动文件到您应用扩展的共享容器中。
Document Provider应用扩展包含两个独立的部分:文档选择器View Controller扩展和文件提供程序(File Provider)扩展。当主应用程序为您的文档提供程序提供文档选择器view controller时,系统将自动显示该接口。这个接口应当让用户浏览并能在您的文档提供程序中选择文档和目标位置。这个应用扩展还可以在没有任何额外支持的情况下,执行基本的导入和导出操作。
要支持打开和移动操作,您还必须创建一个文件提供程序扩展(File Provider Extension)。这个应用扩展授予主应用程序访问沙箱之外文件的权限。它也能为远程文件创建占位符、当需要的时候下载本地副本以及上传由主应用程序进行的任何更改。
理想情况下,您的文档提供程序应当支持上述的四个操作,以便让用户在使用您的文档工作时拥有最大的灵活性。然而,提供这样一个强大的、用户体验良好的文档提供程序将是一个不简单的任务。
如果您只想在您的应用程序中共享文档,您可以创建一个UIDocumentPickerViewController对象来导出或移动文件。或者,您也可以使用iCloud来共享文档。
要选择加入对iCloud的支持,请打开Xcode的Capabilities窗格,然后激活iCloud。接下来,打开应用程序的info.plist文件。您将需要为您的iCloud容器添加一个条目,然后决定您希望如何分享这些容器。样本条目如下所示:
NSUbiquitousContainers iCloud.com.example.MyApp NSUbiquitousContainerIsDocumentScopePublic - <true/>
NSUbiquitousContainerSupportedFolderLevels Any NSUbiquitousContainerName MyApp
这些设置给iCloud提供了访问存储在您应用程序的iCloud容器中的文件的权限。关于有效键值的详细说明,请参见Information Property List Key Reference中的Cocoa Keys。
重要
当在iOS 8.0中使用iCloud服务时,请不要用文件演示器(File Presenters)或者UIDocument类来访问文件。您可以使用文件协作器(file coordinators)、Posix锁(Posix Locks)、Core Data或者SQLite。
开始之前
请确保文档提供程序应用扩展可以提供您打算提供的功能。最好的文档提供程序是作为其他应用程序的公开文档库而存在的。如果您只是想分享自己应用程序的文件,那么文档提供程序并不是正确的选择。
如果需要了解其他您可以创建的应用程序扩展,请参阅Table1-1
文档选择器View Controller应用扩展
文档选择器View Controller应用扩展给用户提供了导入、导出、打开和移动操作的接口,用户可以借助或者直接在您扩展的共享容器中进行这些操作。要创建文档选择器View Controller扩展(有时简称为文档选择器),需要继承UIDocumentPickerExtensionViewController类。当用户从UIDocumentMenuViewController对象中选择文档提供程序,亦或者是当主应用程序直接用UIDocumentPickerViewController对象打开您的文档提供程序时,这个子类将被实例化。
在这两种情况下,主应用程序提供了一个文件选择器view controller。然后,系统将在应用程序的view controller中嵌入文档选择器扩展。该应用程序的view controller提供了一个有文档提供程序的名字、位置选择器以及一个“完成”按钮的导航栏。您的应用扩展必须实现用户界面的其他部分。下图显示了这些UI元素的相对位置。
文档选择器View Controller的布局
生命周期
1.Host应用程序展示UIDocumentMenuViewController。
2.用户从列表中选择您的document provider。
3.您的 UIDocumentPickerViewExtensionViewController
子类被实例化。
4.在您的应用扩展中调用prepareForPresentationInMode:方法。应用扩展必须根据给定的模式来显示相应的用户界面。打开和导入相对于移动和导出来说,往往需要一组不同的控制模式。因此,您的应用扩展应当检查模式以提供正确的用户界面。
UIDocumentPickerExtensionViewController对象作为您用户界面的根视图控制器;因此,它往往可以很方便的作为容器控制器。然后,您可以为每个模式创建一个单独的子视图控制器,您的应用扩展只需在prepareForPresentationInMode:方法中呈现合适的子视图控制器。
5.您的应用扩展将呈现在host app中。
6.当用户做出了选择,您的应用扩展将调用其dismissGrantingAccessToURL:方法。这种方法将释放用户界面,并将所提供的URL返回至host app中,并调用其-[UIDocumentPickerViewControllerDelegate documentPicker:didPickDocumentAtURL:]
方法.
7.释放UIDocumentPickerExtensionViewController实例。
创建文档选择器View Controller应用扩展
要在Xcode中创建一个新的文档选择器,请使用文档选择器应用扩展模板在您的iOS项目中创建一个新的对象。有关添加应用扩展的详细信息,请参阅App Extension编程指南(iOS8/OS X v10.10):创建应用扩展(中文,英文)
当创建文档选择器应用扩展时,您可以同时创建相应的文件提供程序扩展的选项。欲了解更多信息,请参阅本文的Creating the File Provider Extension。
文档选择器扩展模板为您的项目增加了UIDocumentPickerExtensionViewController子类。同时,它还为您的文档选择器的用户界面增加了一个storyboard和一个info.plist文件。
设置所需的属性列表中的条目
为了使系统可以自动识别并加载您的应用扩展,其属性列表必须包含以下项目:
NSExtension NSExtensionAttributes UIDocumentPickerModes UIDocumentPickerModeImport UIDocumentPickerModeOpen UIDocumentPickerModeExportToService UIDocumentPickerModeMoveToService UIDocumentPickerSupportedFileTypes public.content NSExtensionMainStoryboard MainInterface NSExtensionPointIdentifier com.apple.fileprovider-ui
这些条目由文档选择器应用扩展模板自动设置。最好只有在当您打算更改应用扩展的默认行为时,再对其进行修改。很特殊的是,UIDocumentPickerModes数组包含所有文档选择器支持的模式条目。如果您不打算实现文件提供程序的应用扩展,删除 UIDocumentPickerModeOpen
以及UIDocumentPickerModeMoveToService条目。
和上面一样,如果您想创建一个安全的下拉列表以便用户可以将文件导出到您的扩展,那么需要注意的是,用户不能打开、浏览,或者以其他方式查看他们——除非删除 UIDocumentPickerModeExportToService
中的所有模式。
UIDocumentPickerSupportedFileTypes
数组包含了您应用扩展所支持的统一类型标识符的列表。只有当文件类型被转移来匹配至少一个在数组中所列的UTI值时,您的应用扩展才能作为一个选项而出现。默认情况下,public.content的UTI匹配所有的文档类型。
NSExtensionMainStoryboard条目保存您应用扩展的故事板名称。storyboard的初始视图必须是UIDocumentPickerExtensionViewController子类。您可以编辑此键值来更改您的应用扩展是如何初始化其视图控制器的以及是如何创建其视图层次结构的。
举个例子,如果您用NSExtensionPrincipalClass的键值(其为UIDocumentPickerExtensionViewController子类的名称)来替换NSExtensionMainStoryboard的值,应用扩展接下来将直接加载视图控制器。这种方法允许您使用.xib文件来加载用户界面,或者以编程方式创建用户界面。
子类化UIDocumentPickerExtensionViewController
文档选择器扩展模板提供了一个简单的UIDocumentPickerExtensionViewController子类。和大多数视图控制器一样,您可以修改该子类来管理用户界面并响应用户交互。不过,仍然有一些UIDocumentPickerExtensionViewController类的具体方法和特性需要注意。
如果有必要,那么重写此方法来设置其所需的所有资源。特别是当您的应用程序为不同的模式使用了不同的视图层次结构的时候,请确保在这个方法实现中设置了正确的视图层次结构。
调用此方法来关闭该文档选择器的视图控制器以及所提供的授权访问的网址。每种模式都有自己所要求的URL。有关其完整的详细信息,请参阅Dismissing the User Interface
这个只读属性返回文档选择器的模式。只有在系统调用prepareForPresentationInMode:方法后它才有效。
这个只读属性包含了在导出或移动模式下的原始文件的URL。如果不在这两个模式下调用,它则会返回nil值。
这个只读属性包含了在导入或打开模式下的有效UTI数组。如果不在这两个模式下调用,它则会返回nil值。
这个只读属性包含了返回文件提供程序扩展的providerIdentifier方法的值。如果没有文件提供程序扩展,那么它将返回nil。
这个只读属性包含了返回文件提供程序扩展的documentStorageURL方法的值。如果没有文件提供程序扩展,那么它将返回nil。
创建用户界面
文档选择器应用扩展的主要目的是让用户选择文件来导入或者打开,以及选择导出和移动操作的目标位置。
当用户执行导入或打开操作时,您的应用扩展应该创建一个显示所有可用文件的列表并将其展示给用户。用户应当只能够选择在validTypes属性中符合的UTI所对应文件。如果其他文件都包含在列表当中,那么它们必须清楚地标记为不可用。您同样也可以提供关于文件的可用元数据,包括大小、创建日期,以及其为本地文件还是远程文件。您甚至可以创建和显示文件的缩略图。有关使用元数据和缩略图的详细信息,请参阅NSURL Class Reference。
您的文档选择器可提供一个简单的显示所有可用文件的列表,也可以显示一个具有复杂层次结构的目录和子目录。这一切都取决于您的应用程序需求。无论如何,当用户选择一个文件后,请关闭该界面并将该URL返回给主应用程序。
要实现导出和移动操作,需要让用户选择文件的目标位置。对于简单的应用扩展来说,您可能只是提供了一个确认按钮。更复杂的应用扩展一般都会让用户能够浏览目录的层次结构,甚至创建自己的子目录。当用户选择了目标位置之后,就关闭该界面。
您也可以直接在文档选择器应用扩展中决定如何处理登录、下载以及其他类似的任务。只有两个地方能够让您和用户直接交互:一是在关联应用程序中,二是在文档选择器应用扩展中。这意味着所有的用户账户管理、错误通知以及进程更新都必须通过这两个部件中的一个来进行处理。
如果您想要在关联应用程序中处理这些任务,那么您可以使用通知和标记来通知用户。应用扩展能够连接到您的服务器并请求相应的推送通知。这个通知随后会在后台启动关联应用程序,让其保持运行以便做出相应的响应。关联应用程序同时也能够使用本地通知和标记以提醒用户某些重要事件。然而,用户要么必须选中某个通知,要么必须打开关联应用程序,才能使其在前台激活。因此,这种方法需要用户的积极参与,因为用户可以选择取消、忽略,甚至停用这些通知和标记。
通常情况下,您可以借助直接使用文档选择器应用扩展来处理上述任务,以便给用户提供更好的体验。欲了解更多信息,请参阅本章的Providing a Great User Experience in an Uncertain World
解除用户界面
当用户进行了恰当的选择操作之后,请调用dismissGrantingAccessToURL:方法并返回一个格式正确的URL。这个URL必须符合以下所有条件:
1.导入文档选择器模式:为选定的文件提供URL。这个URL必须必须指向文档选择器应用扩展能够访问的本地文件。当用户选择了一个远程文件,您的应用扩展应当在调用dismissGrantingAccessToURL:方法前,下载该文件并在本地保存一个副本。或者,如果您还提供了文件提供程序的应用扩展,那么您可以提供一个满足开放运行要求的URL,并让文件提供程序自行下载。
2.打开文档选择器模式:为选定的文件提供URL。如果文件并不存在于该位置,那么您的文件提供程序应用扩展将被调用,以创建一个占位符或者根据需要直接生成该文件。该URL必须指向被documentStorageURL属性提及的目录层次结构中的某个位置。这个属性只是调用文档提供程序的documentStorageURL方法并返回其值。
3.导出文档选择器模式:提供用户选择的目标位置的URL。这个URL只需要在文档选择器应用扩展中进行访问。系统将保存一个来自该URL的文档副本,并返回该URL到主应用程序来表示其操作成功。主应用程序不能通过该URL来访问该文档。
4.移动文档选择器模式:提供用户选择的目标位置的URL。这个URL需要被documentStorageURL属性提及的层次结构所包含。系统移动文档到URL,并返回该URL到主应用程序。然后,主应用程序能够在这个新的URL来访问文档。
File Provider应用扩展
文件提供程序应用扩展允许在主应用程序的沙箱外使用打开和移动操作来访问文件。该应用扩展(有时被简称为文件提供程序)还允许主应用程序在不使用文档选择器的视图控制器的情况下下载文件。这个功能可让主应用程序访问之前打开的、使用安全URL书签的文档,即使这些文件不再存储在设备上。
文件提供程序应用扩展使用占位符来表示远程文件。当主应用程序试图使用协同读取来访问占位符之一的时候,应用扩展将开始下载该文件。当下载结束的时候,协同读取操作仍然会继续工作。而如果下载失败,错误将被传回到文件协同器当中。
该应用扩展还能在文件发生变化时收到通知,让您能够将更改传回您的远程服务器。当主应用程序不再编辑文档时,应用扩展同样也能收到通知。借助这一点,该应用扩展可以删除该文件,并用占位符将其代替,以释放存储空间。
创建文件提供程序应用扩展
您可以创建文件提供程序应用扩展并作为文档选择器应用扩展模板的一部分。详情请参阅本文的 Creating the Document Picker Extension章节。如果您加入了文件提供程序应用扩展,模板将会创建一个为整个应用扩展创建一个独立的对象。它还为该对象创建了一个NSFileProviderExtension子类以及info.plist文件中所需的条目。
设置所需的属性列表中条目
为了使系统可以自动识别并加载您的应用扩展,其属性列表必须包含以下项目:
NSExtension NSExtensionAttributes NSExtensionFileProviderDocumentGroup com.apple.devpubs NSExtensionPointIdentifier com.apple.fileprovider-nonui NSExtensionPrincipalClass FileProvider
这些条目由文档选择器应用扩展模板自动创建。最好只有在当您打算更改应用扩展的默认行为时,再对其进行修改。
NSExtensionPrincipalClass键必须包含NSFileProviderExtension子类的名称。系统会自动实例化这个类,不管它是否需要提供文档到主应用程序当中。
为了让文档选择器以及文件提供程序应用扩展都能够访问共享容器,NSExtensionFileProviderDocumentGroup条目必须包含该共享容器的标识符。通过使用应用扩展的documentStorageURL方法来进行这个操作。如果您改变了分享容器的标识符,那么请确保要同时更新这个设置。
设置共享容器
默认情况下,应用扩展模板搭建了一个能够被文档选择器应用扩展和文件提供程序应用扩展都能够访问的共享容器。虽然在通常情况下,您可能想同时将这个共享容器提供给关联应用程序来使用。
打开Xcode的Capabilities面板,然后为您的关联应用程序激活App Groups。为共享组添加标识符。您也可以从文件提供程序应用扩展对象中复制该标识符。
激活App Groups就增加了com.apple.security.application-groups访问该对象的权利。
com.apple.security.application-groups com.example.domain.MyFirstDocumentPickerExtension
有关应用程序组的详细信息,请参阅Entitlement Key Reference中的Adding an App to an App Group。
NSFileProviderExtension子类
NSFileProviderExtension类提供了许多不同的方法——有的方法是千万不能被重写的,有些方法可能要被重写,同时还有几个您是必须得重写的。这些方法描述如下:
不能重写的类方法
writePlaceholderAtURL:withMetadata:error:
每当您需要创建一个占位符时调用此方法。使用placeholderURLForURL:来生成基于本地文件URL的正确URL。您所提供的元数据在很大程度上取决于文档选择器的用户界面需求,常用的选项包括了文件大小、文件名以及缩略图。
这个方法将文件的URL映射到其相应占位符的URL中。您通常会在调用writePlaceholderAtURL:withMetadata:error:方法前,调用此方法来产生占位符的URL。
可能会重写的类方法
这些方法应该适用于大多数应用扩展的默认实现。但是,您可能希望重写这些方法来微调应用扩展的行为。
NSFileProviderExtension子类的唯一标识符。默认情况下,此方法返回关联应用程序(containing app)的绑定标识符(bundle identifier)。
至少有四个独立的进程可以尝试访问由该应用扩展在任意时刻所提供的文件。因此,您必须使用文件协同器来控制所有的读写操作。
文档选择器应用扩展和文件提供程序应用扩展都应该将提供商的标识传递给文件协同器的setPurposeIdentifier:方法。共享目的标识符将允许应用扩展相互协同,防止它们之间可能出现的死锁行为。
所有提供文件的根URL。该URL对该应用扩展来说是可写入的,并且它应该是在被UIDocumentPickerExtensionViewController和containing app所共享的容器中。
默认情况下,此方法返回的是被UIDocumentPickerExtensionViewController和 NSFileProviderExtension
应用扩展所分享的应用程序组容器目录下的子目录。通过使用在文档提供程序应用扩展的info.plist文件中指定的NSExtensionFileProviderDocumentGroup键值来指定分享的容器。
persistentIdentifierForItemAtURL:
定义了URL及其持续性标识符之间的映射。默认情况下,该标识符只是相对于由documentStorageURL方法返回的URL的路径。您能够重写该方法来提供不同的映射。
URLForItemWithPersistentIdentifier:
这个是persistentIdentifierForItemAtURL:的逆操作。它提供了给定标识符的URL。
必须重写的类方法
您必须重写这些方法,即使您只提供了一个空方法。不要在您的声明中调用super。
providePlaceholderAtURL:completionHandler:
当文件被访问时系统将调用此方法。providePlaceholderAtURL:completionHandler:和startProvidingItemAtURL:completionHandler:两个方法都作为文档选择器视图控制器或者协同读取程序的用户交互被触发。
要确定到底哪个方法被触发以及他们触发的顺序,这取决于用户访问的意图。例如,协同读取使用NSFileCoordinatorReadingImmediatelyAvailableMetadataOnly选项仅仅只是触发创建占位符的操作。这样一来,您的应用扩展不应该创建这些方法的任何从属状态。它们可以以任何次序被调用。
startProvidingItemAtURL:completionHandler:
当这个方法被调用时,您的应用扩展应当开始下载、创建或者以其他方式来让某个本地文件准备就绪。一旦该文件可用,就调用提供的完成处理程序。如果在此过程中发生任何错误,就将错误信息传递给完成处理程序。系统接下来就会将错误信息饭回到初始协同读取程序中。
当主应用程序完成协同写入的操作之后,系统将会调用这个方法。您可以重写此方法以将文件造成的更改上传回您的服务器,或者是以其他方式对更改做出回应。
只要没有进程正在访问所提供的URL,那么系统将会调用此方法。您可以重写此方法从本地文件系统中删除文档以释放存储空间。
注意
如果您的应用扩展决定删除文件以释放空间,那么就必须调用placeholderURLForURL:和writePlaceholderAtURL:withMetadata:error:来创建占位符以替换这些文件。
在瞬息万变的世界中提供出色的用户体验
即使是最简单的任务,网络仍然也会给其正常运行带来不确定性和意想不到的问题。您必须对网络环境差、连接速度慢、服务器错误,甚至是文件系统的错误进行处理。您的文档提供程序应用扩展必须小心地处理这些问题。
此外,您的应用扩展并不具备完全控制其环境的能力。当它被启动时,您根本不知道主应用程序会是什么。可能有多个进程会访问您提供的文件,而且您的应用扩展必须有效地传递这些进程以及任何可能出现的错误到用户正在使用的主应用程序中。
请记住,您的文档提供程序扩展应用对整个设备具有广泛的影响,因为所有拥有文档选择程序视图控制器的应用程序都可以访问它。因此,您需要提供一个坚实、出色、可靠的用户体验。
文件协同
重要:
当在iOS 8.0中使用iCloud时,请使用UIDocument类或者NSFileProviderExtension类访问文件。在iOS 8.0中,请不要使用NSFileCoordinator类。
由于有多个进程可以访问这些文件,所以请使用文件协同器来执行所有的读取和写入操作。本方法适用于关联应用程序、文档选择器应用扩展、文件提供程序应用扩展以及主应用程序。
对于文档选择器和文件提供程序,您必须设置文件协同器的目的标识符。这两种应用扩展都提供了providerIdentifier方法。在执行协同读取或协同写入操作之前,将这个方法的返回值传递给文件协同器的purposeIdentifier属性。通过共享目的标识符,这两个应用扩展可以互相配合,从而防止它们之间出现任何可能的死锁现象。
文件协同起着许多重要的作用。首先,它保证了每个进程可以安全地读取和写入所提供的文件。但是,由于文件协同也可以作为其他某些动作的触发器,协同读取会导致占位符被创建或者从远程服务器中下载文件。协同写入同样可能会触发上传到远程服务器的操作。最后,文件协同器允许错误信息跨过进程的界限进行传播。
下载文件
即使下载一个很小的文件也可能会花上很长的时间。当您在您办公室的Wi-Fi环境下进行测试时,应用或许会运行的非常正常。但是如果当用户在地下停车场里面打开您的文档提供程序时,您的应用的运行效果或许就不会如您所愿了。
由于下载操作本身是一个不可靠的操作,因此尽可能地提供有用的反馈。例如,让用户知道哪些文件是本地的,哪些是远程的。让用户们知道,文件正在被下载以及下载的进度。最后,当问题发生时弹出有意义的错误信息。
由于用户只能访问关联应用程序以及文档选择器应用扩展的用户界面,因此您可能需要提供一个能够直接从文档选择器中下载文件的用户界面。在文档选择器中下载文件比在文件提供程序中下载文件有如下几个好处:
1.您可以显示该文件的大小,告知用户文件需要下载的时间。
2.您可以显示下载过程的进度。
3.您可以完全控制如何处理错误。
然而,从文档选择器中下载数据仍然存在着一些它自身带来的问题。如果用户关闭了文档选择器,系统可能会终止您的应用扩展。
您可以使用NSURLSession在后台传输下载的文件,但要确保设置了被应用扩展和关联应用程序所共享容器中的NSURLSessionConfiguration对象的sharedContainerIdentifier属性。这确保了结果可以通过应用扩展或关联应用程序在必要时进行访问。
后台传输下载将执行一个单独的进程,即使您的文档选择器被终止,下载操作仍然可以继续。当下载完成后且如果您的文档选择器未运行,系统会在后台启动其关联应用程序,并调用application:handleEventsForBackgroundURLSession:completionHandler:方法。
关联应用程序(containing app)可以使用本地通知和标记来提醒用户。如果用户在下载完成前重新打开文档选择器,您可以用您的后台传输程序重新连接,将当前的状态呈现给用户,并直接处理下载操作的结束。
即使您在文档选择器应用扩展中下载文档,您仍然需要支持文件提供程序提供的startProvidingItemAtURL:completionHandler:下载方法。主应用程序可能无法始终通过文档选择器来访问您的文件。当用户每次打开某个文件,主应用程序可以为该文件保存一个在安全范围内的书签。这个书签让主应用程序直接打开该文件。然而,如果文件提供程序早已删除了本地副本以释放存储空间,主应用程序就必须重新下载一个新的副本。
当在文件提供程序应用扩展中下载文件时,您并没有权限来访问用户界面。如果出现错误,则无法直接显示错误信息。相反的是,您可以传递一个NSError对象到startProvidingItemAtURL:completionHandler:方法的完成处理程序中。系统随后将会将此错误信息传回给主应用程序的协同读取器。
同样,也没有办法来将下载进度返回给用户。触发下载的协同读取并不会在下载完成后保持运行。如果处理不当,下载可能会给用户带来意外的延时。
这意味着您可能要小心地根据存储空间的大小来权衡,以避免不必要的下载操作。如果您的应用扩展过于急切地用文件提供程序应用扩展的stopProvidingItemAtURL:方法来将文件替换为占位符,那么您的用户可能会为应用程序突然需要重新下载他们刚刚操作的文件而感到十分惊讶。另外,如果您知道用户需要一个给定的文件,那么您可以在关联应用程序的共享容器中事先将这个文件下载好。这可以让这个文件在用户需要它的时候就立即可用。
检测和处理冲突
每当用户在多个设备上修改文件时,冲突就会变得不可避免。因此要在冲突发生时,准备检测和处理冲突。比如说,当关联应用程序或者文件提供程序应用扩展正在下载一个文件的更新版本,您必须检查是否有任何本地修改该更新文件的冲突。同样,当您上传本地更改到服务器时,服务器必须能够检测并处理任何可能会被发现的冲突。
没有办法能够直接将这些冲突通知给主应用程序。相反,您的应用扩展应当连接服务器。您不仅应当上传本地更改到服务器并在那儿处理冲突,更应当让服务器能够发送推送通知给关联应用程序,让应用程序来处理冲突。
登录和注销
请仔细考虑您的文档选择器应用扩展是如何让用户登录或注销您的服务的。
当您的文档选择器应用扩展首次显示时,通常应该提示用户登录。不过,您同样也想要保存用户的身份凭据。正如前面所述,文件提供程序应用扩展可能无需通过文档选择器来下载或上传文件。因此,它需要访问用户的身份凭据。
使用钥匙串访问组将用户的身份凭据保存进共享的钥匙串中。在Xcode的Capabilities面板中,为关联应用程序和其应用扩展激活钥匙串分享服务。确保所有的对象都使用了相同的组标识符。接下来,当您创建了一个共享钥匙串,请在项目的属性字典中添加kSecAttrAccessGroup键。其键值必须和您的共享标识符相同。
有关保存数据到钥匙串的详细信息,请参阅iOS Keychain Services Tasks
当用户注销时,请删除他们的登录身份凭据并移除任何他们不能够再访问的文件占位符。您可能还需要删除所有存储在服务器上文件的本地副本。一般情况下,用户应该只有在重新登录后才能访问这些文件。
联系客服