31

我正在开发一个支持 iCloud 的应用程序,用户将能够通过 iCloud Drive 导入和导出文件。在使用UIDocumentPickerViewController(iOS 8) 或 Finder (OS X Yosemite) 浏览 iCloud Drive 时,我可以看到由其他支持 iCloud-Drive 的应用程序创建/拥有的目录,例如 Automator、Keynote 或 TextEdit。

我希望我们的应用程序也能在 iCloud Drive 中公开其无处不在的文档目录,但还没有弄清楚。在上述一些应用程序的Info.plist文件中,我发现了这个键:

<key>NSUbiquitousContainers</key>
<dict>
    <key>com.apple.TextEdit</key>
    <dict>
        <key>NSUbiquitousContainerIsDocumentScopePublic</key>
        <true/>
        <key>NSUbiquitousContainerSupportedFolderLevels</key>
        <string>Any</string>
    </dict>
</dict>

这些键也记录在这里,但我还没有找到关于更广泛主题的任何其他文档。编辑/注意:虽然它不包含我的问题的答案,但文档选择器编程指南是一个有用的资源。

我尝试将上述键/值添加到我们的应用程序中,但没有看到任何效果。我注意到/尝试过的事情:

  • 对于 3rd 方应用程序,iCloud 容器是这样构建的:iCloud.$(CFBundleIdentifier). 我不确定为什么 TextEdit 只使用纯包标识符,但对于我们的标识符,我尝试了两种方法,即有前缀和没有iCloud.前缀。我还认识到您需要对捆绑标识符进行硬编码(即不要使用iCloud.$(CFBundleIdentifier)),因为似乎只有 PLIST 的值在构建时才被解析,而不是键。

  • 我以编程方式(到)添加了一个子目录,<containerPath>/Documents因此容器不为空。但是,这无关紧要,因为所有其他应用程序的目录最初也是空的。

  • 出现在 iCloud Drive 中的某些 Apple 应用程序在其 中没有这些条目Info.plist,例如 Numbers 和 Pages。

  • iCloud 设置正确,我可以使用[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];.

  • 我登录到启用了 iCloud Drive 的 iCloud 帐户。我可以在UIDocumentPickerViewController.

  • 我使用 iOS 8 beta 5 模拟器(和 Yosemite beta 5 在 Mac 上查看 iCloud Drive 目录)(编辑/注意:这同样适用于 beta 6)

这就是我的权利文件的样子(仅相关部分)

<key>com.apple.developer.icloud-container-identifiers</key>
<array>
    <string>iCloud.$(CFBundleIdentifier)</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
    <string>CloudDocuments</string>
</array>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array/>

我已经在 Capabilities 部分使用 Xcode 的 UI 进行了设置。我不明白为什么最后一个键没有条目,但添加<string>iCloud.$(CFBundleIdentifier)</string>没有帮助。相反,它使 Xcode 在 Capabilities UI 中抱怨,所以我将其删除。编辑/注意:在 Xcode beta 6 中,这已被修复,即需要设置普遍存在的容器标识符,Xcode 可以为您修复它。

原始问题:那么......这是一个错误吗?它还不工作吗?我做错了吗?我在发行说明中找不到已知问题。

编辑:

我尝试过的另外两件事:

  • NSUbiquitousContainerName按照 Erikmitk 的建议,将(可选)键(+ 值)添加到特定于容器的字典中。

  • 仅将NSUbiquitousContainerIsDocumentScopePublic键/值添加到 PLIST 根字典而不是特定于容器的字典,就像在WWDC 示例应用程序之一中所做的那样(查找 NewBox)。

4

12 回答 12

19

我的应用程序遇到了类似的问题。我能够通过执行以下操作来完成这项工作:

  1. 根据此处的文档https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/FileProvider.html将设置添加NSUbiquitousContainers到我的Info.plist文件中。以下是相关代码:

    <dict>
        <!-- ... other top-level Info.plist settings ... -->
        <key>NSUbiquitousContainers</key>
        <dict>
            <key>iCloud.com.example.MyApp</key>
            <dict>
                <key>NSUbiquitousContainerIsDocumentScopePublic</key>
                <true/>
                <key>NSUbiquitousContainerSupportedFolderLevels</key>
                <string>Any</string>
                <key>NSUbiquitousContainerName</key>
                <string>MyApp</string>
            </dict>
        </dict>
    </dict>
    
  2. 重要的!然后我将上面的NSUbiquitousContainerSupportedFolderLevels字符串值从更改AnyOne

    <key>NSUbiquitousContainerSupportedFolderLevels</key>
    <string>One</string>
    
  3. 接下来,也是最后,我不得不更改CFBundleVersion为更高的版本。我也将它撞到了CFBundleShortVersionString一个新版本。

构建并运行之后,带有我的应用程序图标的文件夹正确地出现在 iCloud Drive 中!希望这可以帮助!

于 2015-04-27T03:42:07.763 回答
15

当您编辑 Info.plist 时,也许您忘记增加捆绑包版本号?这是WWDC session #234的要求。

于 2014-08-15T15:02:41.947 回答
8

关键是调用[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];(或使用另一个容器标识符,如果它不是默认的标识符)至少一次(不是每次启动,但可能是每个版本,或者在更改相应的 PLIST 条目之一时)以初始化目录。我认为这一步需要与增加捆绑版本号相结合,正如 roop 的回答中所建议的那样。

我注意到我的问题在这方面可能令人困惑,因为我提到能够使用相关 API 以编程方式查看文档目录*。但是,我稍后从应用程序中删除了该代码,可能是在正确设置其余部分之前。我不打算直接写入文档目录,只通过文档选择器。因此,没有任何需要获取 URL。

如果您只需要一个 Document Picker 来读取/存储 iCloud Drive 或其他应用程序的文档目录中的文件,则无需调用URLForUbiquityContainerIdentifier:. 仅当您希望您的应用程序拥有自己的普遍存在的容器(并可能在 iCloud Drive 和文档选择器中公开它)时,原始帖子中提到的步骤和调用URLForUbiquityContainerIdentifier:是必要的。

*当提到文档目录时,我总是指的是 ubiquity 容器中的那个,而不是本地的那个。

于 2014-08-19T09:09:54.127 回答
4

看来,改变它CFBundleVersion会让它工作。

我想你可以试试。我从Apple Developer Forums得到这个。

希望这对你有用。

于 2016-10-03T06:36:12.720 回答
3

整个上午都在闲逛,阅读所有帖子,进行所有更改,最终对我有用的关键是,作为又一个代码制作者声明,更改捆绑 ID。我认为一旦它为捆绑包创建了一个容器,您就无法返回并更改它的可见性以使其出现在 Finder 中。我尝试了所有不同的 info.plist 值,但在我更改为新的包名称并强制系统创建一个新包之前,没有任何效果。顺便说一句,我没有在任何地方看到这一点,但包名称、NSUbiquitousContainer 名称和 NSUbiquitousContainerName 都可以不同——这就是我在我的案例中所做的。在花了这么多时间之后,我想我会继续在 GitHub 上放一个简单的示例应用程序,以防任何人在调试 Finder 中出现的 iCloud 文件夹时仍然遇到问题 - 你可以在这里找到它。自述文件中概述了所有必需的步骤。

于 2017-03-12T19:55:25.710 回答
2

在我的情况下(Xcode 7 和 iOS 9),经过多次尝试后,唯一使它起作用的就是使用新的包标识符(您不必更改云容器标识符,只需确保选择容器您想在 Apple Developer Member Center 中使用并在 Xcode 中指定自定义容器而不是默认容器)。

事实上,这意味着您第一次运行应用程序时,必须设置 info.plist 的 NSUbiquitousContainers 部分。如果您之后将其设置为第二步,它将无法正常工作...

于 2015-09-26T20:05:47.977 回答
1

此文档页面上的 .plist 条目有一个附加条目:

<key>NSUbiquitousContainerName</key>
<string>MyApp</string>

也许缺少的名字禁止它出现。

于 2014-08-08T13:07:26.157 回答
1

找不到任何文档,但反复试验,我发现:

[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:@"com.apple.CloudDocs"]; 

为您提供驱动器的基本 URL,如选择器中所示。使用这个基本 URL,我能够将文件保存在我的应用程序中,并在优胜美地的 iCloud 驱动器上看到它。

编辑 14.8.14

我试过你的 plist 设置:

<key>NSUbiquitousContainers</key>
<dict>
    <key>iCloud.net.redacted.docTest</key>
    <dict>
        <key>NSUbiquitousContainerIsDocumentScopePublic</key>
        <true/>
        <key>NSUbiquitousContainerSupportedFolderLevels</key>
        <string>Any</string>
    </dict>
</dict>

在我的一次性测试应用程序“docTest”中,它确实在 Yosemite 和文档选择器中公开了空的 Documents 目录。

截图http://spring-appstudio.com/picker-view.png

于 2014-08-13T20:15:12.713 回答
1

只是想强调为我修复它的 OP 发现之一:

我还认识到您需要对捆绑标识符进行硬编码(即,不要使用iCloud.$(CFBundleIdentifier)),因为在构建时似乎只解析了 PLIST 的值,而不是键。

您需要对捆绑包 ID 进行硬编码。同时更新版本。

(在我完成所有答案之前,我没有在问题中注意到这一点)。

于 2016-04-28T16:42:12.757 回答
1

好吧,它没有记录在任何地方,但尝试Documents在容器中添加文件夹并将文件存储在那里。

在这个 Apple Developer Forum 主题的回复中找到了这个提示。

于 2020-02-11T17:44:06.027 回答
0

我的 OSX 应用程序也出现了同样的问题。

似乎 NSUbiquitousContainers 设置仅适用于 iCloud 容器的创建时间。所以我尝试使用新的 Apple ID(用于准备干净的 iCloud 环境),它就可以工作了。

于 2014-09-02T04:06:28.000 回答
0

我知道这是一个旧线程,但以防万一有人遇到同样的问题:让我的 Container 文件夹在 iCloud Drive 中可见的唯一方法是让我的应用程序创建一个临时文件在文档文件夹中。一旦我这样做了,容器文件夹(以及我创建的文件)就会出现在我的 Mac 上。如果确实是这种情况,我必须创建一个文件以使该文件夹可见,那么这会有点烦人,因为我的应用程序是只读应用程序(仅读取用户添加到容器文件夹的文件)。首次启动应用程序时,容器文件夹需要可见。我想我将不得不检测第一次发射。

于 2018-01-05T17:32:51.953 回答