iOS共享存储(谷歌云盘/OneDrive等)PDF上传至服务器(Ktor)失败
解决KMM iOS端无法读取Google Drive/OneDrive文件的问题
问题概述
使用Kotlin Multiplatform 2.0.20开发跨平台应用,iOS端通过UIDocumentPickerViewController选择PDF文件上传时,iCloud、本地文件及Dropbox文件可正常处理,但Google Drive和OneDrive的文件无法读取,调试发现NSData.dataWithContentsOfURL(didPickDocumentAtURL)返回null且无异常抛出。
问题原因
Google Drive和OneDrive返回的文件URL属于云存储的安全范围资源书签,并非本地文件路径,直接通过NSData.dataWithContentsOfURL无法直接读取内容,需要借助iOS系统提供的UIDocument类来处理云文件的下载与访问逻辑。
解决方案
使用UIDocument异步读取文件内容,替代直接读取URL的方式,以下是修改后的Kotlin代码:
1. 自定义UIDocument子类
首先创建一个继承自UIDocument的子类,用于处理PDF文件的读取:
class PDFDocument(fileURL: NSURL) : UIDocument(fileURL) { var fileData: NSData? = null override fun contentsForType(typeName: String, outError: AutoreleasingPointer<NSError?>?): Any? { return fileData } override fun loadContentsOfType(typeName: String, outError: AutoreleasingPointer<NSError?>?): Boolean { val fileData = NSData.dataWithContentsOfURL(fileURL) this.fileData = fileData return fileData != null } }
2. 修改DocumentPicker代理逻辑
更新UIDocumentPickerDelegateProtocol的实现,使用自定义PDFDocument读取文件:
val documentDelegate = remember { object : NSObject(), UIDocumentPickerDelegateProtocol { override fun documentPicker( controller: UIDocumentPickerViewController, didPickDocumentAtURL: NSURL ) { val accessing = didPickDocumentAtURL.startAccessingSecurityScopedResource() val pdfDocument = PDFDocument(didPickDocumentAtURL) pdfDocument.openWithCompletionHandler { success, error -> if (success) { val fileData = pdfDocument.fileData // 这里处理fileData,比如上传到服务器 pdfDocument.closeWithCompletionHandler { _ -> if (accessing) { didPickDocumentAtURL.stopAccessingSecurityScopedResource() } controller.dismissViewControllerAnimated(true, null) } } else { error?.let { // 处理错误,比如打印错误信息 println("读取文件失败: ${it.localizedDescription}") } if (accessing) { didPickDocumentAtURL.stopAccessingSecurityScopedResource() } controller.dismissViewControllerAnimated(true, null) } } } } }
关键说明
UIDocument会自动处理云存储文件的下载流程,无需手动处理文件是否本地存在的问题- 必须在完成文件读取后调用
closeWithCompletionHandler释放资源 - 始终确保在使用完安全范围资源后调用
stopAccessingSecurityScopedResource
内容的提问来源于stack exchange,提问作者Kaouther Mefteh
相关产品推荐
相关产品推荐

