Search code examples
iosswifticloudavplayercloudkit

Play video downloaded through CloudKit as CKAsset - iOS


I'm making an app that records video, uploads it to iCloud using CloudKit with a CKAsset, then downloads the file and plays it in an AVPlayer. This is all written in Swift 2.0

I have gotten the data downloaded, and I think I've been able to reference it but I'm not sure. Data/garbage does print when I convert the URL into an NSData object and print it to the console. The video files gets downloaded as a binary file however. I was able to go to the CloudKit dashboard and download the file and append '.mov' to it, and it opened in Quicktime no problem.

So I think my main issue is that I can't work out how to get the video file to actually play, since the file has no extension. I have tried appending '.mov' to the end with URLByAppendingPathExtension() to no avail. Let me know of any ideas!

Upload Video

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
    let tempURL = info[UIImagePickerControllerMediaURL] as! NSURL

    dismissViewControllerAnimated(true) { () -> Void in
        self.uploadVideoToiCloud(tempURL)
        print("\n     Before Upload: \(tempURL)\n")
    }
}

func uploadVideoToiCloud(url: NSURL) {
    let videoRecord = CKRecord(recordType: "video", recordID: id)

    videoRecord["title"] = "This is the title"

    let videoAsset = CKAsset(fileURL: url)
    videoRecord["video"] = videoAsset

    CKContainer.defaultContainer().privateCloudDatabase.saveRecord(videoRecord) { (record, error) -> Void in
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            if error == nil {
                print("upload successful")

            } else {
                print(error!)
            }
        })
    }
}

Download Video

func downloadVideo(id: CKRecordID) {

    privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in

        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            if error != nil {

                    print(" Error Fetching Record  " + error!.localizedDescription)
            } else {
                if results != nil {
                    print("pulled record")

                    let record = results!
                    let videoFile = record.objectForKey("video") as! CKAsset

                    self.videoURL = videoFile.fileURL

                    print("     After Download: \(self.videoURL!)")

                    self.videoAsset = AVAsset(URL: self.videoURL!)
                    self.playVideo()

                } else {
                    print("results Empty")
                }
            }
        }
    }
}

Solution

  • Solution ended up being that I forgot to specify the filename before I wrote the data to it. I was using URLByAppendingPathExtension and it messed up the URL, ended up using URLByAppendingPathComponent and adding a filename there. Here's the solution that worked for me! Thanks for the comments guys.

    func downloadVideo(id: CKRecordID) {
    
        privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in
    
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                if error != nil {
    
                        print(" Error Fetching Record  " + error!.localizedDescription)
                } else {
                    if results != nil {
                        print("pulled record")
    
                        let record = results as CKRecord!
                        let videoFile = record.objectForKey("video") as! CKAsset
    
                        self.videoURL = videoFile.fileURL as NSURL!
                        let videoData = NSData(contentsOfURL: self.videoURL!)
    
                        let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
                        let destinationPath = NSURL(fileURLWithPath: documentsPath).URLByAppendingPathComponent("filename.mov", isDirectory: false) //This is where I messed up.
    
                        NSFileManager.defaultManager().createFileAtPath(destinationPath.path!, contents:videoData, attributes:nil)
    
                        self.videoURL = destinationPath
    
                        self.videoAsset = AVURLAsset(URL: self.videoURL!)
                        self.playVideo()
    
                    } else {
                        print("results Empty")
                    }
                }
            }
        }
    }