iOS: Open saved image inside the native Files app
After doing some research, I don't think this is unwanted behavior but more like behavior that Snapseed
has subscribed to, as this behavior does not happen automatically.
However, there is some bug (I think) that does not let you unsubscribe from this behavior easily.
The place we need to look at is using LSSupportsOpeningDocumentsInPlace
and CFBundleDocumentTypes
, more on that here and here:
Here I created a small example to save an image from the app main bundle to the documents directory when the user taps a button using your code:
Absolutely no difference to your code
@objc
private func saveImage()
{
if let imageData
= UIImage(named: "dog")?.jpegData(compressionQuality: 1.0)
{
save(imageData: imageData,
toFolder: "image",
withFileName: "dog.jpeg")
}
}
func save(imageData: Data,
toFolder folderName: String,
withFileName fileName: String)
{
DispatchQueue.global().async
{
let manager = FileManager.default
let documentFolder = manager.urls(for: .documentDirectory,
in: .userDomainMask).last
let folder = documentFolder?.appendingPathComponent(folderName)
let file = folder?.appendingPathComponent(fileName)
do {
try manager.createDirectory(at: folder!,
withIntermediateDirectories: true,
attributes: [:])
if let file = file
{
try imageData.write(to: file)
print("file \(fileName) saved")
}
}
catch
{
print(error.localizedDescription)
}
}
}
If you add the following to your info.plist
UIFileSharingEnabled
LSSupportsOpeningDocumentsInPlace
This supports exposing your documents directory in the files app and after this everything works as normal:
However, if you want your app to be part of a group that opens certain file formats, you modify your info.plist to add the CFBundleDocumentTypes
to suggest that your app is able to open specific files, like images in our case.
To do that, we add the following to info.plist
CFBundleDocumentTypes
LSItemContentTypes
public.image
CFBundleTypeName
image
LSHandlerRank
Default
This would allow your app to be listed when some wants to share or open an image and by adding this, then we get the behavior shown in your gif which opens the app instead of the preview in the files app
Unfortunately, it seems once this behavior is assigned to your app, even if you remove the above above key from info.plist, this behavior persists.
The only way I could restore the original behavior was by using a fresh bundle identifier and only using these two keys in the info.plist
in order to expose your documents directory to the Files app
UIFileSharingEnabled
LSSupportsOpeningDocumentsInPlace
I believe this is some sort of bug as there should be a simple way to unsubscribe from this behavior.
Hope this helps even though it does not fully solve your problem
Loading an image saved to the Documents Directory only works once, then never loads again
Never store a full path. An app's sandbox changes over time. Just store the file name. When you want to get the full path to the file, calculate it at runtime based on the stored filename and the current value for the Documents folder.
Loading/Downloading image from URL on Swift
Xcode 8 or later • Swift 3 or later
Synchronously:
if let filePath = Bundle.main.path(forResource: "imageName", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath) {
imageView.contentMode = .scaleAspectFit
imageView.image = image
}
Asynchronously:
Create a method with a completion handler to get the image data from your url
func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}
Create a method to download the image (start the task)
func downloadImage(from url: URL) {
print("Download Started")
getData(from: url) { data, response, error in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
print("Download Finished")
// always update the UI from the main thread
DispatchQueue.main.async() { [weak self] in
self?.imageView.image = UIImage(data: data)
}
}
}
Usage:
override func viewDidLoad() {
super.viewDidLoad()
print("Begin of code")
let url = URL(string: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")!
downloadImage(from: url)
print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
}
Extension:
extension UIImageView {
func downloaded(from url: URL, contentMode mode: ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: ContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
Usage:
imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")
Related Topics
iOS - Calling App Delegate Method from Viewcontroller
How to Get Unique Id in iOS Device
No Avplayer Delegate? How to Track When Song Finished Playing? Objective C iPhone Development
Long Press Gesture on Uicollectionviewcell
Swift - Problems with Corner Radius and Drop Shadow
Cannot Change Search Bar Background Color
How to Find File Uti for File, Withouth Pathextension, in a Path in Swift
Get Progress from Datataskwithurl in Swift
Apns (Apple Push Notification Service) Reliability
How to Create an Umbrella Framework in iOS Sdk
Parsing Nested Array of Dictionaries Using Object Mapper
How to Set the Title of a Uibutton as Left-Aligned
Round Top Corners of a Uibutton in Swift
How to Reset the Privacy Settings in iOS
How to Test If a String Is Empty in Objective-C
Unable to Get the Access Token Through [Fbsdkaccesstoken Currentaccesstoken] in iPhone Sdk
Kcfstreamerrordomainssl, -9802 When Connecting to a Server by Ip Address Through Https in iOS 9