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

iOS Swift应用中WKWebView无法触发Google Drive文件下载的问题

WKWebView加载Google Drive文件无法触发下载的解决方案

问题分析

Google Drive的网页下载按钮并非直接指向文件资源链接,而是通过JavaScript触发跳转,且会进行权限验证,导致WKWebView默认的下载代理回调无法捕获下载请求。你的现有代码已经实现了WKDownloadDelegate,但缺少关键的代理配置和链接转换处理。

修复方案(WKWebView方式)

1. 完善WKWebView代理设置

iOS 14及以上版本,WKWebView新增了downloadDelegate属性,需要直接设置该代理才能正确捕获下载请求,补充代码如下:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let configuration = WKWebViewConfiguration()
    webView = WKWebView(frame: self.view.bounds, configuration: configuration)
    webView.navigationDelegate = self
    // 设置downloadDelegate(iOS14+)
    if #available(iOS 14.0, *) {
        webView.downloadDelegate = self
    }
    webView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(webView)
    
    // ... 原有约束代码
    
    // 转换为直接下载链接后加载
    if let driveURL = URL(string: "GOOGLEDRIVE_FILE_URL"),
       let directDownloadURL = convertToDirectDownloadURL(from: driveURL) {
        let request = URLRequest(url: directDownloadURL)
        webView.load(request)
    }
}

2. 转换Google Drive链接为直接下载格式

默认的Google Drive文件查看链接(如https://drive.google.com/file/d/FILE_ID/view?usp=sharing)不会触发自动下载,需要转换为导出下载的专用链接:

func convertToDirectDownloadURL(from driveURL: URL) -> URL? {
    // 提取链接中的文件ID
    guard let dIndex = driveURL.pathComponents.firstIndex(of: "d"),
          dIndex + 1 < driveURL.pathComponents.count else {
        return nil
    }
    let fileID = driveURL.pathComponents[dIndex + 1]
    // 构造直接下载链接
    return URL(string: "https://drive.google.com/uc?export=download&id=\(fileID)")
}

备选方案:使用URLSession实现下载

如果WKWebView方案仍无法生效,直接使用URLSession发起下载请求更可靠,不受网页JS逻辑限制:

1. 发起下载任务

// 在需要触发下载的地方调用
if let driveURL = URL(string: "GOOGLEDRIVE_FILE_URL"),
   let directDownloadURL = convertToDirectDownloadURL(from: driveURL) {
    downloadFileWithURLSession(from: directDownloadURL)
}

func downloadFileWithURLSession(from url: URL) {
    let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
    let downloadTask = session.downloadTask(with: url)
    downloadTask.resume()
}

2. 实现URLSession下载代理

// 扩展ViewController实现URLSessionDownloadDelegate
extension ViewController: URLSessionDownloadDelegate, URLSessionTaskDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // 保存文件到Documents目录
        guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        let suggestedFilename = downloadTask.response?.suggestedFilename ?? "unknown_file"
        let destinationURL = documentsDir.appendingPathComponent(suggestedFilename)
        
        do {
            // 覆盖已存在的文件
            if FileManager.default.fileExists(atPath: destinationURL.path) {
                try FileManager.default.removeItem(at: destinationURL)
            }
            try FileManager.default.moveItem(at: location, to: destinationURL)
            print("文件已保存至: \(destinationURL)")
        } catch {
            print("保存文件失败: \(error.localizedDescription)")
        }
    }
    
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let error = error {
            print("下载失败: \(error.localizedDescription)")
        }
    }
    
    // 处理大文件的确认重定向
    func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
        guard response.statusCode == 302, let redirectURL = request.url else {
            completionHandler(request)
            return
        }
        
        // 检测是否是Google Drive的确认页面
        if redirectURL.path.contains("/confirm"),
           let confirmParam = redirectURL.queryItems?.first(where: { $0.name == "confirm" })?.value {
            // 构造POST请求确认下载
            var postRequest = URLRequest(url: redirectURL)
            postRequest.httpMethod = "POST"
            postRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            postRequest.httpBody = "confirm=\(confirmParam)".data(using: .utf8)
            completionHandler(postRequest)
            return
        }
        
        completionHandler(request)
    }
}

关于直接URL下载的疑问

可以通过直接URL下载,但必须将Google Drive的共享链接转换为uc?export=download格式的专用下载链接。对于超过一定大小的文件,Google Drive会返回重定向到确认页面,此时需要在代码中处理该重定向(如上述URLSession代理中的逻辑),才能获取真实的文件资源链接完成下载。

内容的提问来源于stack exchange,提问作者Alise

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:17:07