Exposing an app's ubiquitous container to iCloud Drive in iOS 8 - icloud

I'm developing an iCloud-enabled app where users will be able to import and export files via iCloud Drive. When browsing iCloud Drive, either using the UIDocumentPickerViewController (iOS 8) or the Finder (OS X Yosemite), I can see directories created/owned by other iCloud-Drive-enabled apps, such as, Automator, Keynote, or TextEdit.
I want our app to expose its ubiquitous documents directory in iCloud Drive, too, but haven't been able to figure it out yet. Within some of the aforementioned apps' Info.plist files, I've discovered this key:
<key>NSUbiquitousContainers</key>
<dict>
<key>com.apple.TextEdit</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
These keys are also documented here, but I haven't found any other documentation on the broader subject. Edit/Note: Although it does not contain the answer to my questions, the Document Picker Programming Guide is a helpful resource.
I've tried adding the above-mentioned keys/values to our app but didn't see any effect. Things I've noticed/tried:
For 3rd party apps, iCloud containers are constructed this way: iCloud.$(CFBundleIdentifier). I'm not sure why TextEdit only uses the pure bundle identifier, but for our identifier, I've tried both approaches, i.e., with and without the iCloud. prefix. I've also recognised that you need to hard-code the bundle identifier (i.e., don't use iCloud.$(CFBundleIdentifier)) as only the PLIST's values seem to be resolved at build time, but not the keys.
I've added a sub-directory programmatically (to <containerPath>/Documents) so the container is not empty. However, this shouldn't matter as all the other apps' directories were initially empty, too.
Some Apple apps that appear in iCloud Drive do not have these entries in their Info.plist, e.g., Numbers and Pages.
iCloud is set up correctly and I can programmatically look into the ubiquity container using the URL returned by [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];.
I am logged into an iCloud account where iCloud Drive is enabled. I can see my iCloud Drive content in the UIDocumentPickerViewController.
I use the iOS 8 beta 5 simulator (and Yosemite beta 5 to view the iCloud Drive directory on the Mac) (Edit/Note: This equally applies to beta 6)
This is how my Entitlements file looks like (relevant parts only)
<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/>
I've set this up using Xcode's UI in the Capabilities section. I don't get why the last key doesn't have an entry, but adding <string>iCloud.$(CFBundleIdentifier)</string> doesn't help. Instead, it makes Xcode complain in the Capabilities UI, so I've removed it. Edit/Note: In Xcode beta 6, this has been fixed, i.e., the ubiquity container identifier needs to be set and Xcode can fix that for you.
Original Questions: So... is it a bug? Does it not work yet? Am I doing it wrong? I couldn't find a known issue in the release notes.
Edit:
Two more things that I've tried:
Adding the (optional) NSUbiquitousContainerName key (+ value) to the container-specific dictionary, as suggested by Erikmitk.
Adding only the NSUbiquitousContainerIsDocumentScopePublic key/value to the PLIST root dictionary rather than the container-specific dictionary, as it's done in one of the WWDC sample apps (look for NewBox).

I was experiencing a similar problem with my application. I was able to make this work by doing the following:
Add the NSUbiquitousContainers setting to my Info.plist file according to documentation here https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/FileProvider.html. Here is the relevant code:
<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>
Important! I then changed the above NSUbiquitousContainerSupportedFolderLevels string value from Any to One
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>One</string>
Next, and last, I had to change CFBundleVersion to a higher version. I also bumped the CFBundleShortVersionString to a new version as well.
Built and ran and after that, the folder with my applications icon appeared properly in iCloud Drive! Hope this helps!

When you edited the Info.plist, maybe you forgot to bump up the bundle version number? This is a requirement as per WWDC session #234.

The catch is to call [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; (or with another container identifier if it's not the default one) at least once (not per launch, but presumably per version, or when changing one of the respective PLIST entries) in order to initialize the directory. I reckon this step needs to be combined with an increase of the bundle version number, as suggested in roop's answer.
I notice my question may have been confusing in that respect, as I mentioned being able to look into the documents directory* programmatically using the API in question. However, I removed that code from the app later, maybe before getting the rest of the setup right. I'm not going to write into the documents directory directly, only through the Document Picker. Therefore, there hasn't been any need to get the URL.
If you just need a Document Picker to read/store files from/in iCloud Drive or other apps' document directories, there's no need to call URLForUbiquityContainerIdentifier:. Only if you want your app to have its own ubiquity container (and potentially expose it in iCloud Drive and the Document Picker), the steps mentioned in the original post and the call to URLForUbiquityContainerIdentifier: are necessary.
*When mentioning the documents directory, I'm always referring to the one in the ubiquity container, not the local one.

It seems, changing the CFBundleVersion will let it work.
I think you can try it. I got this from Apple Developer Forums.
Hope this work for you.

After dorking around with this all morning, reading all the posts, making all the changes, the key thing that finally worked for me was, as Yet Another Code Maker stated, changing the bundle ID. I think once it has created a container for a bundle, you can't go back and change the visibility of it to have it appear in Finder. I had tried all the different info.plist values but nothing worked until I changed to a new bundle name and forced the system to create a new one. By the way, I didn't see this noted anywhere but the bundle name, the NSUbiquitousContainer name and the NSUbiquitousContainerName can all be different - which is what I did in my case. After spending so much time on this, I figured I would go ahead and put a simple sample app on GitHub in case anyone is still having problems debugging their iCloud folder appearing in Finder - you can find it here. All the required steps are outlined in the README.

In my case (Xcode 7 and iOS 9), the only thing which made it works, after multiple tries, was just use a new bundle identifier (you don't have to change the cloud container identifier, just be sure to select the container you want to use in the Apple Developer Member Centre and to specify in Xcode a custom container instead of the default).
In fact, that means the first time you run your application, the NSUbiquitousContainers section of the info.plist has to be set up. If you set it afterwards as a second step, it won't work...

Well, it's not documented anywhere but try to add Documents folder in the container and store your files there.
Found this hint in replies in this Apple Developer Forum thread.

The .plist entry on this documentation page has an additional entry:
<key>NSUbiquitousContainerName</key>
<string>MyApp</string>
Maybe the missing name is prohibiting it from showing up.

Couldn't find any documentation, but trial and error, I found that:
[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:#"com.apple.CloudDocs"];
Gives you the base URL for the drive as seen in the picker. Using this base URL I was able to save files in my app and see it on the iCloud drive within Yosemite.
Edit 14.8.14
I tried your plist settings:
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.net.redacted.docTest</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
In my little throwaway test app "docTest" it does indeed expose the empty Documents directory in Yosemite and in the document picker.
Screenshot http://spring-appstudio.com/picker-view.png

Just wanted to emphasize one of the OP's discoveries that fixed it for me:
I've also recognised that you need to hard-code the bundle identifier (i.e., don't use iCloud.$(CFBundleIdentifier)) as only the PLIST's values seem to be resolved at build time, but not the keys.
You need to hard code the bundle id. Also update the version.
(I didn't notice this in the question until I went through all the answers).

Same problem occurred to my OSX app.
It is seemed that NSUbiquitousContainers setting works only in the creation time of the iCloud containers. So I tried with new Apple ID(for preparing clean iCloud environment), it becomes to work.

I know this is an old thread but just in case someone runs into the same issue: Only way for me to get my Container folder to be visible in iCloud Drive (after trying all the above suggestions) was to have my app create a temporary file in the Documents folder. As soon as I did that the Container Folder (and the file I created) showed up on my Mac. If this is really the case that I have to create a file to make this folder visible then this would be a bit annoying because my app is a read only app (only reads files added by the user to the Container Folder). The Container Folder needs to be visible as soon as the app is launched for the first time. I guess I will have to detect the first launch.

Related

Is there an update/change flag in the current version (v4) of gspread?

Is there an indicator or flag in gspread that indicates whether or not a change has been made to a sheet or worksheet? This appears to have been present as an attribute called updated before version 2.0, or maybe that served a different purpose?
You're looking for Detect Changes guide in Drive API.
For Google Drive apps that need to keep track of changes to files, the
Changes collection provides an efficient way to detect changes to all
files, including those that have been shared with a user. The
collection works by providing the current state of each file, if and
only if the file has changed since a given point in time.
There's a github code demo for testing purposes.

Wix multi-disc layout requirement - Caching and locating media

First time asking a question here, and might not be my last. This is in regards to WiX 3.8
My company is starting to go into the installer business, and one of the requirements I have been tasked to do is to create a multi-disc installation for our product. I have used WiX before for simple patches, but now we want to create a full installation. Some of the requirements include:
Creating external cab files for multiple discs [Which I enabled with setting the 'EmbedCab' property in the media tag to 'no' and setting the disc ID's to each file element with Compression to low]
The finished build will have the 5 discs in separate folders, with the respected external cab files in each [Media tag 'layout' set to destination]
Executing the .msi file inside the 'Disc1' folder [Which works...almost]
The problem I am running into is that when the .msi file is located on the hard disk, either outside the Disc layouts or inside the 'Disc1' subfolder, it cannot find the other .cab files. The requirement I have is that I need to find a way to be able to only prompt for a disc if and only if after searching inside the next subfolder 'Disc2' and finding the next .cab file to install. Therefore it can not only look in the root where the .msi is located, but also check the subfolders for the required cab files. (This almost mimic's InstallShield, but I REALLY don't want to go that route.)
The second issue I have is regards to the bootstrapper. The .exe file needs to embed the .msi file as per the requirement. However, even when disabling caching of the msi file, the bootstrapper seems to start caching all the other .cab files (we are talking about a 20GB installation). Even disabling repair and rollback, the bootstrapper continues to try to cache the cab files into the PackageCache area on my system.
I've looked online and read the WiX books to help find a solution, but I seem to finally hit a dead end. Can anyone give me any thoughts or insight to help with this issue?
Some things I have tried so far:
- Using a custom action (C++) to perform a 'ResolveSource' to try to change the 'SourceDir' property to continue installation
- Thought about making a custom bootstrapper to disable the package caching event entirely, but I have no idea where to start.
Any advice, direction or even a sample to help would be greatly appreciated.
Thanks!

VS2010 does not find #include via environmental variable

I'm currently running into a problem that drives me a little bit mad. I hope it's a little stupid mistake on my side.
For convenience, I added an environmental variable in Windows 7, VS_BOOST_INCLUDE_HEADER with the value set to D:\01_Programs\boost_1_55_0\. My VC C++ include directories contain $(VS_BOOST_INCLUDE_HEADER).
Remark: I changed that variable this morning, but I've rebooted my computer since than multiple times.
Now my VS project complains it can't find any of the boost includes anymore, e.g. <boost/asio.hpp>. If I add the whole path manually to the include paths (adding D:\01_Programs\boost_1_55_0\ as text to my VC C++ include directories), everything works as expected.
To avoid a simple typo, I added a post-build event:
echo $(VS_BOOST_INCLUDE_HEADER)
That works as expected:
1>PostBuildEvent:
1> D:\01_Programs\boost_1_55_0\
All my other environmental variables still work as expected, even those that were renamed this morning as well.
Any ideas?
What am I doing wrong?
Maybe I'm late to the party, but a possible scenario is when you
run VS as administrator
adjusted a User environment variable
Then it would make some sense for VS to see the System environment only and still use the old value.
If you decide to use property sheets the msdn has clear docs
"If you have a common, frequently used set of properties that you want
to apply to multiple projects, you can use Property Manager to capture
them in a reusable property sheet file"
Under the view menu, chose property manager and add a new sheet.
You can then make your project inherit its settings from this property sheet, thereby just setting this in one place.

coldfusion application.cfc not found

I've been having a sporadic problem for a few weeks where on restarting the CF Server (Enterprise 9) one of my applications runs without ColdFusion referencing all the variables in the Application.cfc file. It's in the same folder as the CFML pages, it IS properly capitalised as Application.cfc, but it seems to just be ignored. Obviously this causes problems with datasource name and all the other variables I set in Application.cfc. For reference, I'm using an Application.cfc file based on Ben Nadel's excellent intro at http://www.bennadel.com/blog/726-ColdFusion-Application-cfc-Tutorial-And-Application-cfc-Reference.htm . Usually my requested template runs as an include and I can see it in the stack using debugging output, now I can't see it there at all. It's as if the file just doesn't exist.
Has anyone else experienced this, or can you think of possible solutions? Note that at times a restart has got the whole thing running perfectly smoothly.
Re folder structure it's really simple: the Application.cfc file is in the web root along with executable CFML templates - included templates, images, CSS etc are in separate folders referenced via relative paths.
There is another application with its own similar Application.cfc file that is in a sub-directory of the web root. This is running perfectly.
Try clearing your template cache. I've see cases where CF just gets flakey and the cached files are causing issues. Another option: Does ColdFusion have permissions to read/execute the Application.cfc? If this WAS an issue but is no longer an issue I've seen cases where the template cache was causing these files not to be found. Again, delete these files (from disk, not the cfadmin) and try again.

Localhost pointing to different codeFolder locations

WINDOWS XP PROFESSIONAL/coldfusion/Dreamweaver/Fusebox-3
I have the same CF-8 code in two places
* folder A:- c:\Coldfusion8\wwwroot\BootsmanCode\code
* folder B:- c:\wwwroot\BootsmanCode\code
Local:- http://127.0.0.1:8500/BootsmanCode/
http://localhost:8500/BootsmanCode/
ISSUE:- I am making my code changes in "folder B", testing it on http://localhost:8500.
When I go home and use VPN, I cannot see these code changes when I call http://localhost:8500 from folder B
Then when I use http://localhost:8500/, with code from folder A, I am able to see the code changes.
So the URL seems to be magically pointing to different folders at at diffent time.
Any correction to this please let me know?
Would need more detail for a more definitive answer, I'd be happy to take a closer look. But some things I would look at/ask/suggest include:
If you're using IIS, do you have any bindings/host headers that route the request from one folder to another? Following up on VAS's comment (are we talking about a 127.0.0.1 vs. localhost showing different results issue?)
From home, when you VPN... are you accessing http://localhost... from your PC? Or are you remote-desktopping to your PC at work and doing it from there? Localhost is relative to the machine that you're on.
Make sure CF has template caching at 0.
Make sure your browser isn't caching the site.