Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift write/save/move a document file to iCloud drive

I've been trying for over two days to write a file to iCloud drive. I have tried writing a simple text file directly, locally then moving it, using UIDocumentMenuViewController, etc. I'm not getting any errors with my code and stepping through debugger, it looks successful, but when I check to see if the file exists or at least the iCloud directory, there is nothing there. I tried on both the simulator and my iPhone, triggering iCloud synching, and everything else I can think of.

My main goal is to simply write a text file to the iCloud drive, which later will be "numbers" file

I have set up my plist file and my entitlements:

<key>NSUbiquitousContainers</key>
<dict>
    <key>iCloud.com.paul.c.$(PRODUCT_NAME:rfc1034identifier)</key>
    <dict>
        <key>NSUbiquitousContainerIsDocumentScopePublic</key>
        <true/>
        <key>NSUbiquitousContainerName</key>
        <string>myCloudTest</string>
        <key>NSUbiquitousContainerSupportedFolderLevels</key>
        <string>Any</string>
    </dict>
</dict>

I have also bumped up by bundle version as stated at: Save iOS 8 Documents to iCloud Drive

I have tried dozens of tutorials with no luck. My latest code is based off of this sample: https://medium.com/ios-os-x-development/icloud-drive-documents-1a46b5706fe1

Here is my code:

@IBAction func ExportFile(sender: AnyObject) {

    var error:NSError?

    let iCloudDocumentsURL = NSFileManager.defaultManager().URLForUbiquityContainerIdentifier(nil)?.URLByAppendingPathComponent("myCloudTest")

    //is iCloud working?
    if  iCloudDocumentsURL != nil {

        //Create the Directory if it doesn't exist
        if (!NSFileManager.defaultManager().fileExistsAtPath(iCloudDocumentsURL!.path!, isDirectory: nil)) {
                //This gets skipped after initial run saying directory exists, but still don't see it on iCloud
                NSFileManager.defaultManager().createDirectoryAtURL(iCloudDocumentsURL!, withIntermediateDirectories: true, attributes: nil, error: nil)
        }
    } else {
        println("iCloud is NOT working!")
        //  return
    }

    if ((error) != nil) {
        println("Error creating iCloud DIR")
    }


    //Set up directorys
    let localDocumentsURL = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: .UserDomainMask).last as! NSURL

    //Add txt file to my local folder
    let myTextString = NSString(string: "HELLO WORLD")
    let myLocalFile = localDocumentsURL.URLByAppendingPathComponent("myTextFile.txt")
    let written = myTextString.writeToURL(myLocalFile, atomically: true, encoding: NSUTF8StringEncoding, error: &error)

    if ((error) != nil){
        println("Error saving to local DIR")
    }


   //If file exists on iCloud remove it
    var isDir:ObjCBool = false
    if (NSFileManager.defaultManager().fileExistsAtPath(iCloudDocumentsURL!.path!, isDirectory: &isDir)) {
        NSFileManager.defaultManager().removeItemAtURL(iCloudDocumentsURL!, error: &error)
    }

    //copy from my local to iCloud
    if (error == nil && !NSFileManager.defaultManager().copyItemAtURL(localDocumentsURL, toURL: iCloudDocumentsURL!, error: &error)) {
        println(error?.localizedDescription);
    }

Thank You for taking time for this.

Cheers, Paul

I ran some code on my iphone after the code above:

var error:NSError?
    let iCloudDocumentsURL = NSFileManager.defaultManager().URLForUbiquityContainerIdentifier(nil) //?.URLByAppendingPathComponent("myCloudTest")

    var fileManager: NSFileManager = NSFileManager()


    var fileList: NSArray = fileManager.contentsOfDirectoryAtURL(iCloudDocumentsURL!, includingPropertiesForKeys: nil, options: nil, error: &error)!
    var filesStr: NSMutableString = NSMutableString(string: "Files in iCloud folder \n")
    for s in fileList {

        println(s)
    }

and it prints out the path to my text file: file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~paul~c~myApp/MyTextFile.txt

My file is there, I just can't see it on iCloud drive.

like image 980
Paul C Avatar asked Aug 30 '15 19:08

Paul C


4 Answers

I had this problem. I followed the advice here and I found that my Info.plist key was not correct. Once I changed it to iCloud.MY_BUNDLE_IDENTIFIER (i.e. copy the string from the CFBundleIdentifier key higher in Info.plist) it all started working.

Removing the .com from your key may fix your issue.

like image 54
Rick Andrews Avatar answered Nov 07 '22 08:11

Rick Andrews


FWIW:

I also found out that the name of the project within the bundle ID is important.

My project bundle ID was something like the following: aaa-bbb-ccc-ddd

I could not get the iCloud working.

Then I renamed it to: aaa-bbb.ccc-ddd

It started working.

like image 38
Mehmet Avatar answered Nov 07 '22 09:11

Mehmet


I believe I've found a way to get everything back in sync without constantly having to "bump" my bundle number. I've tried this multiple times while making changes within the "capabilities" area of key-value storage/iCloud Documents/CloudKit and it seems to work each time.

  1. Sign out of iCloud on your Mac
  2. Sign out of iCloud on your Simulator
  3. Sign back into iCloud on your Mac
  4. Sign back into iCloud on your Simulator
  5. Do a clean build from XCode (Shift-Cmd-K)

This appears to reset the synchronization of the folder structures when you're App is writing to your iCloud Documents directory - without having to touch your bundle number. It takes a little longer to do it, but I'm a little OCD and kinda prefer my initial App launch to start with a 1!

like image 1
pscarnegie Avatar answered Nov 07 '22 07:11

pscarnegie


You need to do 2 things

  1. Do what @rick Andrews said: "Once I changed it to iCloud.MY_BUNDLE_IDENTIFIER (i.e. copy the string from the CFBundleIdentifier key higher in Info.plist)"
  2. Store your filed inside the containers subfolder Documents
struct iCloudStore {
    public var containerUrl: URL! {
        return fileManager.url(forUbiquityContainerIdentifier: nil)!
    }
    
    public var documents: URL! {
        return containerUrl.appendingPathComponent("Documents", isDirectory: true)
    }
    
    private let fileManager: FileManager = FileManager.default

    func store(url: URL) {
      // move ulr into the documents folder as a file
 let fileID = "\(UUID().uuidString).<#extension#>"
        let icloudFile = documents.appendingPathComponent(fileID, isDirectory: false)
        try fileManager.copyItem(at: url, to: icloudFile)
    }
}
like image 1
doozMen Avatar answered Nov 07 '22 09:11

doozMen