iCloud uploading/sync images, videos and plist files - ios

I want to upload Images, Videos and some PList files on iCloud on Button Click event. I did following code but there are some issues.
(Q.1) It takes too much time to upload data on iCloud Dashboard http://icloud.developer.apple.com/dashboard/.
(Q.2) Sometime Dashboard shows data and sometimes not.
(Q.3) One important question: right now its data shows in iCloud Dashboard, after app go live will it be visible to user's iCloud drive? because I need to this: data will visible to user's iCloud drive in a folder.
(Q.4) As I want to upload images, video and plist files, so my following coding approach is correct or not? else I need to use Key-Value storage or iCloud-Document upload or iCloud Drive upload? (right now i am using iCloud Drive upload method)
Below is my code:
private let pathsForDocDir = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let DOCUMENT_DIRECTORY: AnyObject = pathsForDocDir[0]
let filePath = DOCUMENT_DIRECTORY.stringByAppendingPathComponent("image1.png")
let File : CKAsset? = CKAsset(fileURL: NSURL(fileURLWithPath: filePath))
let newRecord:CKRecord = CKRecord(recordType: "album")
newRecord.setValue(File, forKey: "ImageOrVideo")
let privateDB = CKContainer.defaultContainer().privateCloudDatabase
privateDB.saveRecord(newRecord) { (record : CKRecord?, error : NSError?) in
if error != nil {
print(error?.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
print("finished")
}
}
}
I am using this code in For loop because I have multiple files to upload.
(Q.5) And also I need to click on "Add Record ID Query Index" on iCloud Dashboard. you can see the screenshot of iCloud Dashboard.

Related

Access iCloud documents in iOS

I'm trying to access documents that I've put into my iCloud Documents folder on my Mac in an iOS app but I can't work out how to.
let manager = FileManager.default
let dir = manager.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
let files = try? FileManager.default.contentsOfDirectory(at: dir!, includingPropertiesForKeys: nil, options: [])
print(files) //(Optional([])
I have enabled iCloud Documents in my apps capabilities, and I know there are files in my Documents folder on my desktop..
I'm clearly missing something here..
Thanks in advance
Create iCloud Container for the iCloud
a. login to developer.apple.com
b. go to Identifiers and add iCloud Containers.
c. You can't delete iCloud Containers once created.
Create App ID that includes iCloud capabilities
a. Create App ID
b. Add iCloud support with explicit Bundle ID.
c. Create Provisioning Profile and download it to Xcode.
Configure the Capabilities in Xcode
a. Click and add iCloud support from "+ Capability"
b. For iCloud document storage, select iCloud Documents and select the Container you created.
c. Add NSUbiquitousContainers key in Info.plist
d. "MyApp" inside is what will display as foldername.
<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>
Test Code Snippet
a. Try below quick and dirty test.
let driveURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
if let unwrappedFU = driveURL {
print("iCloud available")
let fileURL = driveURL!.appendingPathComponent("test.txt")
try? "Hello word".data(using: .utf8)?.write(to: fileURL)
} else {
print("iCloud not available")
}
Writing to your App Document Folder is different from iCloud document storage. You can make your App Document folder visible. By adding to Info.plist 2 additional property.
a. Add Support opening documents in place : YES
b. Supports opening documents in place : YES
c. Test using Tim's code snippet. https://www.youtube.com/watch?v=p1UNnsodJxc
let file = "\(UUID().uuidString).txt"
let contents = "Some text..."
let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = dir.appendingPathComponent(file)
do {
try contents.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {
print("Error: \(error)")
}
NOTE: You will notice App Folder in the Files App in "On My iPhone" folder. That is App's Document folder you exposed to user. You will also notice your app folder in iCloud Drive folder. Those 2 folders are different. You should use your App Folder and use iCloud Drive folder as your export destination that way you don't have to deal with access control much.
CAVEAT: Oddly none of this worked including resigning into iCloud on the iPhone. Even though it was working on the simulator. It only started working when iPhone was rebooted in my case.
func clickFunction(){
let DOCUMENTS_DIRECTORY = "Documents"
if let iCloudDocumentsURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent(DOCUMENTS_DIRECTORY){
if let pathComponent = iCloudDocumentsURL.path as? String {
if (FileManager.default.fileExists(atPath: pathComponent, isDirectory: nil)) {
//Write it out the code of getting files
let fileManager = FileManager.default
let enumerator = fileManager.enumerator(atPath: DocumentsDirectory.iCloudDocumentsURL!.path!)
while let file = enumerator?.nextObject() as? String {
//this this the file or document path.
}
}
}
}
}

Contact image data not saving

I have a phonelist application that loads employees from a database and lets users search through them. They have an option to add the contact to their phone. Currently I can add all of the data to the phone as a CNMutableContact(), but if I open up my iOS contact application the image data only works the first time I open the application. If I open it later the images are gone, but all of the other information is correct. Is there something I need to do for saving the image? Does the image need to be stored locally aside from saving it through the save request? The CNMutableContact uses a Data object for the image data. Using Swift 4, iOS target 9.0+
let contact = CNMutableContact()
contact.givenName = givenName
contact.familyName = familyName
contact.imageData = UIImagePNGRepresentation(image)
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.add(contact, toContainerWithIdentifier: nil)
do {
try store.execute(saveRequest)
} catch let error {
print(error)
}

AWS S3 capabilities for iOS

I decided to utilize Amazon S3 to upload files, however I find AWS Docs a bit confusing about S3 capabilities for iOS platform.
I would like to know how my app would act in the following scenarios:
Scenario 1: During the upload user has accidentally lost internet connection
Scenario 2: App crashes during the upload
I heard that iOS SDK takes care of such issues itself by resuming remaining upload when possible, I failed to find relevant information in docs, though.
Will AWSS3 framework cover both this scenarios? Does it need any additional lines od code to not be vulnerable for potential crashes and network errors?
I've found some relevant informations for Android platform
I'd love to know what can I expect from the following code
let image = UIImage(named: "12.jpeg")
let fileManager = FileManager.default
let imageData = UIImageJPEGRepresentation(image!, 0.99)
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(imageData!).jpeg")
fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)
let fileUrl = NSURL(fileURLWithPath: path)
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "bucketname"
uploadRequest?.key = "folder/12.jpeg"
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = fileUrl as URL!
uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
print("bytes sent \(bytesSent), total bytes sent \(totalBytesSent), of total \(totalBytesExpectedToSend)")
})
}
let transferManager = AWSS3TransferManager.default()
transferManager?.upload(uploadRequest).continue(with: AWSExecutor.mainThread(), withSuccessBlock: { (taskk: AWSTask) -> Any? in
if taskk.error != nil {
// Error.
} else {
// Do something with your result.
}
return nil
})
Is it already crash/network proof?
EDIT:
This is the part of docs that sounds ambiguous to me:
S3 provides a multipart upload feature that lets you upload a single
object as a set of parts. Each part is a contiguous portion of the
object's data, and the object parts are uploaded independently and in
any order. If transmission of any part fails, you can retransmit that
part without affecting other parts. After all parts of the object are
uploaded, S3 assembles these parts and creates the object.
Does that mean it has its own inherent mechanism to manage that? Let's say I kill app during uploading a file, when I relaunch it and start over the upload process , will it start with the last chunk where it left off before I killed the app?

iCloud files not visible after app reinstall swift

I'm storing files in iCloud as a means of backup. Uploading and downloading files seems to work fine, but if I delete the app on a device and re-install the app on that same device, I no longer see the files that were uploaded to iCloud (even from that device just before deleting the app). The ubiquityIdentityToken is the same from all installs. I'm not trying to sync among devices, just store and retrieve. I can see the files in \settings\icloud\manage storage\ but not by running this code:
func createListOfSQLBaseFilesIniCloudDocumentsDirectory() -> [String]{
let iCloudDocumentsURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents")
var iCloudBackupSQLFiles = [String]()
do{
let directoryContents = try FileManager.default.contentsOfDirectory(at: iCloudDocumentsURL!, includingPropertiesForKeys: nil, options: [])
for myFile in directoryContents {
if myFile.pathExtension == "sqlite" {
let fileWithExtension = myFile.lastPathComponent
//backupSQLFiles is an array of full file names - including the extension
iCloudBackupSQLFiles.append(fileWithExtension)
}//if myFile
}//for in
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}//do catch
return iCloudBackupSQLFiles
}//createListOfSQLBaseFilesIniCloudDocumentsDirectory
Any guidance would be appreciated. Swift 3, iOS 10, Xcode 8
Hard to believe no one else has had this issue. Again, this is for simple file storage and retrieval, not syncing dynamically among devices.
The gist of the issue is that iCloud does not automatically sync cloud files down to a new device. Your code must do that. So if you remove an app from a device (but not from iCloud) and reinstall that same app, the app will not see prior iCloud files. You can add new ones and see them with the code above, but you are really just seeing the local ubiquitous container copy. To see previous items you need to perform a metadataQuery on iCloud, parse the filenames of the files of interest from the metadataQuery results and then run
startDownloadingUbiquitousItem(at:) on each file. For example, make an array of files in iCloud from the metadataQuery results and put this do-catch in a for-in loop.
let fileManager = FileManager.default
let iCloudDocumentsURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents", isDirectory: true)
let iCloudDocumentToCheckURL = iCloudDocumentsURL?.appendingPathComponent(whateverFileName, isDirectory: false)
do {
try fileManager.startDownloadingUbiquitousItem(at: iCloudDocumentToCheckURL!)
print("tested file: \(whateverFileName)")
} catch let error as NSError {
print("Unresolved error \(error), \(error.userInfo)")
}//do catch

Will images be removed from within the local filesystem on update in iOS?

I am saving images captured from the camera within the local sandbox (filesystem) and store the filepath within my app to show the images (using Swift). I see that if I hit play in XCode, the images will be removed (which is ok)
Now I wonder what would happen if I submit this to the app store, the user saves images and I will update the app later on. Will the images will be removed as well?
To store the image, I use this function..
func saveImageLocally(imageData:NSData!) -> String{
let time = NSDate().timeIntervalSince1970
let fileManager = NSFileManager.defaultManager()
let dir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0].stringByAppendingPathComponent(subDirForImage) as String
if !fileManager.fileExistsAtPath(dir) {
var error: NSError?
if !fileManager.createDirectoryAtPath(dir, withIntermediateDirectories: true, attributes: nil, error: &error) {
println("Unable to create directory: \(error)")
return ""
}
}
let path = dir.stringByAppendingPathComponent("IMAGENAME\(Int(time)).png")
var error: NSError?
if !imageData.writeToFile(path, options: NSDataWritingOptions.DataWritingAtomic, error: &error) {
println("error writing file: \(error)")
return ""
}
return path
}
Anything you store in your documents folder will persist through app updates providing you keep the same app ID and increment the version number.
Though it is worth noting that the full path to the app sandbox will be different (there will be a new sandbox for the update and the old data copied into it), so make sure you are only accessing resources by storing relative paths etc and are not storing full paths to images and expecting them to resolve after an update.

Resources