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

Swift中Firebase Storage下载发票无反应问题求助

问题原因分析

你的代码核心问题有两个:

  1. 下载完成后未触发文件预览:调用downloadInvoice后,你没有将返回的文件URL赋值给@State private var fileToPreview,导致QLPreviewControllerRepresentation无法感知到文件已下载,自然不会显示任何内容。
  2. 缺少错误处理:下载过程中如果抛出异常,没有任何提示,你无法得知是否出现错误。

另外,你将QLPreviewController放在background中的做法并不合适,这种方式不会自动弹出预览界面,需要通过弹窗方式触发。

修复方案

1. 修改按钮点击逻辑,处理返回值与错误

将按钮的Task代码修改为:

Button {
    Task{
        do {
            if let downloadedURL = try await downloadInvoice(forSolde: solde) {
                // 将下载好的文件URL赋值给预览变量
                fileToPreview = downloadedURL
            } else {
                toastMessage = "无法获取文件URL"
                isShowingToast = true
            }
        } catch {
            toastMessage = "下载失败:\(error.localizedDescription)"
            isShowingToast = true
        }
    }
} label: {
    Text("Voir la facture").multilineTextAlignment(.center)
}

2. 调整QLPreviewController的展示方式

将原来的background改为sheet,当fileToPreview不为nil时弹出预览界面:

var body: some View {
    content.onAppear{
        Task{
            await adminUserToPaid.fetchSoldeData()
            soldes = adminUserToPaid.soldeList
        }
    }
    .toast(isShowing: $isShowingToast, text: Text(toastMessage))
    // 替换background为sheet
    .sheet(item: $fileToPreview) { url in
        QLPreviewControllerRepresentation(fileURL: .constant(url))
    }
}

同时需要让URL遵循Identifiable协议,在文件末尾添加扩展:

extension URL: Identifiable {
    public var id: String {
        absoluteString
    }
}

3. 优化下载函数(可选)

可以在下载前检查文件是否已存在,避免重复下载:

func downloadInvoice(forSolde solde: Solde) async throws -> URL? {
    let filename = solde.facture
    let soldeCollection = Firestore.firestore().collection("solde")
    
    guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        throw NSError(domain: "AppError", code: 1001, userInfo: ["message": "Erreur lors de la récupération du chemin du dossier Documents"])
    }
    let fileURL = documentsURL.appendingPathComponent(filename)
    
    // 检查文件是否已存在,存在则直接返回
    if FileManager.default.fileExists(atPath: fileURL.path) {
        return fileURL
    }
    
    let document = try await soldeCollection.document(solde.id).getDocument()
    guard let documentData = document.data(),
          let proprietaireUID = documentData["proprietaire"] as? String else {
        throw NSError(domain: "AppError", code: 1002, userInfo: ["message": "Impossible de trouver le champ proprietaire dans le document"])
    }
    
    return try await withCheckedThrowingContinuation { continuation in
        let storageRef = Storage.storage().reference().child("invoices/\(proprietaireUID)/\(solde.id)/\(filename)")
        storageRef.write(toFile: fileURL) { url, error in
            if let error = error {
                continuation.resume(throwing: error)
            } else if let url = url {
                continuation.resume(returning: url)
            } else {
                continuation.resume(throwing: NSError(domain: "AppError", code: 1003, userInfo: ["message": "Erreur inconnue lors du téléchargement"]))
            }
        }
    }
}
验证说明

修改后,点击“Voir la facture”按钮:

  • 若下载成功,会自动弹出QLPreviewController展示发票文件
  • 若下载失败,会通过toast提示错误信息
  • 重复点击时,若文件已存在会直接预览,无需重复下载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:43:12