I have an app say called MyApp it is primarily wkwebview. It is already integrated to Files app so I can import/export files from my wkwebview to be able to download files to local machine or upload files to the server.
Finally I am trying to build a UIbutton in my app that will allow my users to Jump into Files app in the folder where I am storing all their content. Instead of building a full FileProviderUI into my app, I just want the button to take the user into the Files App navigating to the folder.
When I give the path for UIDocumentInteractionController to be a directory and do a shared open to present it, nothing happens. No error, nothing at at all. I just want the user to be able to Jump into the folder called MyApp inside the Files app.
I thought it will be very simple. Adding a FileProvider extension or FilePRoviderUI extension seems superflous to just jump the user into this folder and let him interact with Files app to do whatever he likes - open/delete/modify document.
I have to assume that the users are not savvy enough to know even if I tell them that files are saved in Files App for them to be able to interact with directly when they are offline!
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// Just jump to the folder forcing Files app to open this
let viewer = UIDocumentInteractionController(documentsUrl)
viewer.delegate = self
viewer.presentPreview(animated: true)
Nothing gets presented to the user and nothing happens. The button tap just quietly fails.
I think I figured this out. There is a specific URL format that will automatically open the Files app it is shareddocuments:// - Here is a simple function that seems to achieve this quiet simply.
func openSharedFilesApp() {
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let sharedurl = documentsUrl.absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://")
let furl:URL = URL(string: sharedurl)!
UIApplication.shared.open(furl, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
}
Thanks, Vijay. Here it is in Objective-C.
- (void) openSharedFilesApp
{
NSArray<NSString *>* directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // yes = expand tilde
NSURL* url = [NSURL fileURLWithPath:directories.firstObject];
NSString* sharedDocumentPath = [url.absoluteString stringByReplacingOccurrencesOfString:#"file://" withString:#"shareddocuments://"];
NSURL* sharedDocumentURL = [NSURL URLWithString:sharedDocumentPath];
[UIApplication.sharedApplication openURL:sharedDocumentURL options:#{UIApplicationOpenURLOptionUniversalLinksOnly: #(NO)} completionHandler:^(BOOL success) {
}];
}
Adding to #Vijay's answer in iOS 15, Swift 5:
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let sharedurl = documentsUrl.absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://")
let furl:URL = URL(string: sharedurl)!
if UIApplication.shared.canOpenURL(furl) {
UIApplication.shared.open(furl, options: [:])
}
Related
In my iOS Swift App, I have created files in my App's documents directory through this code:
let localFileName = String("\(fileName).rtf")
let text = String("text text text")
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(localFileName)
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {
}
}
Now I want to Add a link in my app to this directory where file is created so that user can see files. Currently I am doing this by this code:
let importMenu = UIDocumentPickerViewController(documentTypes: [String(kUTTypeRTF)], in: .open)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
present(importMenu, animated: true, completion: nil)
but this code is for picking documents, not for opening directory, So How I can open my App's Documents directory, not for picking documents, just only for showing documents?
It is not possible to explore/open a directory in iOS app. Apple doesn't provide any api for the same. You need to create it by your own.
What you can do
You need to fetch all the files from the specific directory and list them all in either tableview or collection view.
And when user click on the any file, you can show that in web view or based on the file type you can do any specific operations.
So ultimately you need to explore more about FileManager.
This class contains what you want.
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
In my app I am get video from gallery using below method:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
}
But Apple is rejected app and required to include functionality to select video items from Files app.
Here is Apple give me the reason:
We noticed that your app enables users to view and select files, but
it does not include functionality to allow users to view or select
items from the Files app and the user's iCloud documents, as required
by the App Store Review Guidelines.
It seems that they want you to use UIDocumentPickerViewController to enable users to select video files from cloud services as well as from the photo library in accordance with clause 2.5.15
Apple wants their customers to have a good experience with their device and the apps they run on it, so it makes sense for your app to support all relevant iOS features.
You can create a show a document picker to select video files using:
let picker = UIDocumentPickerViewController(documentTypes: ["public.movie"], in: .import)
picker.delegate = self
self.show(picker, sender: self)
You will need to implement some delegate code to handle the picked document. For example, to copy the selected file into your app's documents directory:
extension ViewController: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
if let pickedUrl = urls.first {
let filename = pickedUrl.lastPathComponent
self.filename.text = filename
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
var documentsDirectory = paths[0]
// Apend filename (name+extension) to URL
documentsDirectory.appendPathComponent(filename)
do {
// If file with same name exists remove it (replace file with new one)
if FileManager.default.fileExists(atPath: documentsDirectory.path) {
try FileManager.default.removeItem(atPath: documentsDirectory.path)
}
// Move file from app_id-Inbox to tmp/filename
try FileManager.default.moveItem(atPath: pickedUrl.path, toPath: documentsDirectory.path)
UserDefaults.standard.set(filename, forKey:"filename")
UserDefaults.standard.set(documentsDirectory, forKey:"fileurl")
self.fileURL = documentsDirectory
} catch {
print(error.localizedDescription)
}
}
}
}
I could see the clause in the review guideline
2.5.15 Apps that enable users to view and select files should include items from the Files app and the user’s iCloud documents.
Looks like you should add UIDocumentPickerViewController support as #Paulw11 pointed out
Below are the two functions which I use in the picker view controller to save the file in the App documents directory. And save the url in the local DB & display the image using UIImage(contentsOfFile: ImagePathString)
Everything works well as until this point however as soon as i re-run the simulator images does not show up. I believe its because the app directory keeps changing every time its run on the simulator. My question if its the same when deployed on the device?
func getDocumentsDirectory() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0]
return documentsDirectory
}
//Below function is used in imagePickerController
if let data = UIImagePNGRepresentation(modifiedImage!) {
let filename = getDocumentsDirectory().stringByAppendingPathComponent("\(NSDate()).png")
data.writeToFile(filename, atomically: true)
pathImage = filename
print(pathImage)
}
Yes url to App documents folder may change when the app is deployed on the device.
Refer below link
Technical Note TN2406
.
I've been trying to create a Today extension that needs access to a .plist file in the documents directory. I have setup the App group for both the app and the extension.
While I have seen examples for NSUserDefaults, I couldn't find anything for accessing files.
I tried accessing the file like this (which works in the app itself)
let paths = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0] as String
let filePath = "\(documentsDirectory)/config.plist"
if NSFileManager.defaultManager().fileExistsAtPath(filePath) // false
{
…
}
But I get the following error messages in the console:
Warning: CFFIXED_USER_HOME is not set! It should be set to the simulated home directory.
Failed to inherit CoreMedia permissions from 59919: (null)
The documentation says something about using NSFileCoordinator and NSFilePresenter. I couldn't find out how to use them though. I'm sure I'll need to tell them the app group identifier somewhere but I don't where.
I got it to work. Since I don't need to write the file from the extension, I don't think I need to use NSFileCoordinator. Turns out NSFileManager has a method containerURLForSecurityApplicationGroupIdentifier() for retrieving the container URL.
let manager = NSFileManager()
let containerURL = manager.containerURLForSecurityApplicationGroupIdentifier("group.MyGroupIdentifier")
let filePath = "\(containerURL.path)/config.plist"
let settings = NSDictionary(contentsOfFile: filePath)