You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:04:54