I am developing a feature for my app where user can upload a PDF from shared storage in device (Drive, onDrive, Dropbox,..)
I am using Kotlin Multiplatform 2.0.20
This is the code i am using to upload the PDF for iOS, it works fine for files selected from iCloud, Downloaded locally in the device and Dropbox but NOT for Google Drive
and OneDrive
val documentPickerController = UIDocumentPickerViewController(
forOpeningContentTypes = listOf(UTTypePDF)
)
documentPickerController.allowsMultipleSelection = false
val documentDelegate = remember {
object : NSObject(), UIDocumentPickerDelegateProtocol {
override fun documentPicker(
controller: UIDocumentPickerViewController,
didPickDocumentAtURL: NSURL
) {
val accessing =
didPickDocumentAtURL.startAccessingSecurityScopedResource()
val data = try {
NSData.dataWithContentsOfURL(didPickDocumentAtURL)
} catch (e: Error) {
e.printStackTrace()
null
}
if (accessing == true) {
didPickDocumentAtURL.stopAccessingSecurityScopedResource()
}
controller.dismissViewControllerAnimated(true, null)
}
}
}
When debugging i find that the problem in this line : NSData.dataWithContentsOfURL(didPickDocumentAtURL)
it returns null
no exception is thrown and even putting it in try/catch
block did’t help to understand the error behind the null value.
I don’t have an expert knowledge of ObjectiveC or Swift so i am reaching out for your help 🙂
I found this is exactly a similar issue: https://www.hackingwithswift.com/forums/swiftui/error-domain-nsposixerrordomain-code-2-no-such-file-or-directory-when-using-fileimporter-then-read-the-content/20397
except they use SwiftUI, but i am not so i wonder how can i fix it in my case.
I appreciate if someone faced similar issue and can share his/her thoughts 🙂
Thank you!
2
Answers
I managed to find the reason behind this issue and a solution.
The problem: in iOS cloud storage (Google Drive, OneDrive, Dropbox,..) provide placeholders not the real URI to the file and unless the file is downloaded locally you cannot get the Data of the file. Even it seems to you that you can access files from Google Drive, or any other cloud storage from the shared storage in iOS u can not get the data only if they are downloaded in the device.
The solution: There are 2 solution for this problem:
Use each Cloud service/API separately to manage access remote files. that way you need to implement each API separately.
Display a preview of the file using
documentInteractionController
and it will take care of loading the file, and then you got access to data.I personally found the second solution more efficient, because in my case i just need the data of the selected file and displaying the file to the user is not problem for me so i am not limited to implement the logic only in the background.
here is my solution:
and this the
DocumentInteractionControllerDelegate
class:NOTE: i am not expert in kotlin
on swift side we are doing it this way.