Access iCloud documents in iOS - 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.
}
}
}
}
}

Related

How can I create an app icon folder in the files app and copy items to it?

I want to transfer some files (sound, texts, etc.) from an iOS app to the files app. In addition, I want to put all these items into a folder which has the same name as my app - as it is the case with GarageBand or KeyNote, for example.
In Xcode, I did enable the iCloud Documents capability - I did also define a Container "iCloud.xxx.yyy" - see code below.
guard let fileURL = Bundle.main.url(forResource: "test", withExtension: "aiff") else { return }
guard let containerURL = FileManager.default.url(forUbiquityContainerIdentifier: "iCloud.xxx.yyy") else { return }
if !FileManager.default.fileExists(atPath: containerURL.path) {
try FileManager.default.createDirectory(at: containerURL, withIntermediateDirectories: true, attributes: nil)
}
let backupFileURL = containerURL.appendingPathComponent("test.aiff")
if FileManager.default.fileExists(atPath: backupFileURL.path) {
try FileManager.default.removeItem(at: backupFileURL)
try FileManager.default.copyItem(at: fileURL, to: backupFileURL)
} else {
try FileManager.default.copyItem(at: fileURL, to: backupFileURL)
}
When I run my code, it seems to work - anyhow, I can't see nor folder representing my app name, nor "test.aiff" file in the files app. What is wrong with my approach?
You don't need to copy/move any file. What you need is to allow your app documents to be accessible from the other apps. Just go to your Info plist and allow "Supports Document Browser". All documents in your Documents directory will be automatically available there.

How to download a Pdf file in swift and find in file manager

I have downloaded a pdf using code below. I am able to find the file in App Data Container, but from app data container my device needs Mac, x code or iTunes etc.
Can I give a distinction path to Documents OR another place to find the pdf in iPhone files? I have an option to open the file with iBook but it is not there.
My code to download the file is here:
func downloadFile(){
let url = "https://www.tutorialspoint.com/swift/swift_tutorial.pdf"
let fileName = "MyFile"
savePdf(urlString: url, fileName: fileName)
}
func savePdf(urlString:String, fileName:String) {
DispatchQueue.main.async {
let url = URL(string: urlString)
let pdfData = try? Data.init(contentsOf: url!)
let resourceDocPath = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
let pdfNameFromUrl = "YourAppName-\(fileName).pdf"
let actualPath = resourceDocPath.appendingPathComponent(pdfNameFromUrl)
do {
try pdfData?.write(to: actualPath, options: .atomic)
print("pdf successfully saved!")
//file is downloaded in app data container, I can find file from x code > devices > MyApp > download Container >This container has the file
} catch {
print("Pdf could not be saved")
}
}
}
Configure your app so that its files appear in the Files app by adding below lines to your Info.plist file.
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
OR
Just like below using Xcode
Note: Remember that you must be running iOS 11 or above.

Adding iCloud Drive File Manager to App - iOS 13

I want to support adding files to iCloud within my iOS Application. I want these files to be added to a folder on iCloud Drive (e.g. like the Numbers or Pages folders). I tried everything I found online about this subject but I did not manage to add a folder to iCloud Drive.
First, I added NSUbiquitousContainers to the info.plist
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.com.<xyz>.AppName</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>App Name</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
After this, I added the iCloud capability to my app:
Then, I added the following code to my ViewController:
if let iCloudDocumentsURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents") {
if (!FileManager.default.fileExists(atPath: iCloudDocumentsURL.path, isDirectory: nil)) {
do {
try FileManager.default.createDirectory(at: iCloudDocumentsURL, withIntermediateDirectories: true, attributes: nil)
} catch {
print(error.localizedDescription)
}
}
}
Note: after setting breakpoints I discovered that the code after if (!FileManager.default.fileExists(atPath: iCloudDocumentsURL.path, isDirectory: nil)) { never gets called. I temporarily removed this line, but this did not do anything.
Finaly, I added a file using the following code:
//Save text file to local directory
let file = "file.txt" //Text file to save to iCloud
let text = "sample text" //Text to write into the file
func saveToDirectory(){
guard let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileURL = directory.appendingPathComponent(file)
print(directory)
//Writing
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
} catch {
/* error handling here */
print("Error in writing")
}
//Reading
do {
let getText = try String(contentsOf: fileURL, encoding: .utf8)
print(getText)
} catch {
/* error handling here */
print("Error in reading")
}
}
I do not see the app's folder, or the above file appear on my iCloud Drive. But when I download the apps container and look at it's contents I see the file listed under /AppData/Documents.
Did someone else got this? And/or does someone know how to solve this?
Thanks!
I also changed the Build/Version numbers of my app, but without any result
You should copy your file to iCloud container, you are writing it to app sandbox only.
First, create Documents folder on your iCloud container - if you store file in other folder, your app on another device will see the folder but it won't appear in Files app.
Then copy your file.txt into Documents folder on your iCloud container.

iOS File System SandBox

As I understand from Apple documentation, that there is sandbox for each app , so there local storage to the app can save data and files inside it and the other apps can not access its data and files, but I tried to create file by app and retrieved file URL from it and create another app and pass the file URL to it, but the new app open this file successfully, why that happen? the other app must can not be able to open the file according to Apple documentation
In first App:
I download file using Alamofire
let destination: DownloadRequest.DownloadFileDestination =
{
(temporaryURL, response)in
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0]
let documentsURL = URL(fileURLWithPath: documentsPath, isDirectory: true)
let tmpURL = documentsURL.appendingPathComponent("wordFile.docx")
return (tmpURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(urlString, to:
destination).responseData { response in
(response.destinationURL?.path)!
//The "response.destinationURL?.path" is: "/Users/user/Library/Developer/CoreSimulator/Devices/A0427AC0-6D5E-4734-A550-73A8224BD54D/data/Containers/Data/Application/4126243E-E166-4311-A950-D8FF49A07991/Documents/wordFile.docx"
})
In second App:
I got the file path from previous App (response.destinationURL?.path)!
and pass it to webView , but the webView show file the successfully

Reading/Writing data that is accessible from iOS app extension

I'm working on an iOS Content Blocker, but I would like to have the user choose what lists they want to block (ads, tracks, adult sites etc.). I found that the app extension and the containing app's bundles are separate and have no access to each other's files, so a shared container is needed. I created an app group, but it seems like what I write there does not actually get written. What I am attempting to do is read a .json file from the bundle, and then write it to a sharedJson.json file that the content blocker extension can access.
func writeJsonToSharedJson(arrayOfStrings:[String]) -> Bool {
let composedString = arrayOfStrings.joined(separator: "\n")
let sharedJsonPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.alexspear.BlockerTestGroup")?.appendingPathComponent("sharedJson.json")
//let sharedJsonPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("sharedJson.json")
do {
try composedString.write(to: sharedJsonPath!, atomically: true, encoding: .utf8)
}
catch {
print("Could not write to sharedJson.json\n")
return false
}
return verifyJsonWrite()
}
The result is that through the verifyJsonWrite() function, there is nothing there. Am I incorrect in assuming you can create a file in the app group container? I have also tried using FileManager's createFile function with the same result.

Resources