如何将SwiftUI生成的PDF上传至Firebase Storage并获取下载链接
如何将生成的PDF上传至Firebase Storage并获取下载链接
我已经实现了SwiftUI视图转PDF的功能,现在需要把生成的PDF上传到Firebase Storage,并且获取它的下载链接。
已实现的PDF生成代码
func exportToPDF() { let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let outputFileURL = documentDirectory.appendingPathComponent("SwiftUI.pdf") //Normal width let width: CGFloat = 8.5 * 72.0 //Estimate the height of your view let height: CGFloat = 1000 let charts = SmartSheet() let pdfVC = UIHostingController(rootView: charts) pdfVC.view.frame = CGRect(x: 0, y: 0, width: width, height: height) //Render the view behind all other views let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.addChild(pdfVC) rootVC?.view.insertSubview(pdfVC.view, at: 0) //Render the PDF let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: 8.5 * 72.0, height: height)) DispatchQueue.main.async { do { try pdfRenderer.writePDF(to: outputFileURL, withActions: { (context) in context.beginPage() pdfVC.view.layer.render(in: context.cgContext) }) print("wrote file to: \(outputFileURL.path)") } catch { print("Could not create PDF file: \(error.localizedDescription)") } } pdfVC.removeFromParent() pdfVC.view.removeFromSuperview() }
已实现的UIImage上传及获取链接代码
func upload(image: UIImage) { // Create a storage reference let storageRef = Storage.storage().reference().child("squawks/\(v.FirstName)-sqauwk.jpg") // Convert the image into JPEG and compress the quality to reduce its size let data = image.jpegData(compressionQuality: 0.2) // Change the content type to jpg. If you don't, it'll be saved as application/octet-stream type let metadata = StorageMetadata() metadata.contentType = "image/jpeg" // Upload the image if let data = data { storageRef.putData(data, metadata: metadata) { (metadata, error) in if let error = error { print("Error while uploading file: ", error) } if let metadata = metadata { print("Metadata: ", metadata) } } } } func getPhotoURL(completion: @escaping (String) -> Void) { // Create a reference to the file you want to download let starsRef = Storage.storage().reference().child("squawks/\(v.FirstName)-sqauwk.jpg") // Fetch the download URL starsRef.downloadURL { url, error in if let error = error { // Handle any errors print("error getting link: \(error)") } else { // Get the download URL for 'images/stars.jpg' completion(url!.absoluteString) } } } //On click of button: var strURL = "" upload(image: inputImage!) //inputImage is a UIImage DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { getPhotoURL() { url in strURL = url print("STORAGE URL: \(strURL)") } }
解决方案
参考图片上传逻辑,对PDF上传做适配,步骤如下:
1. 修改PDF生成函数,添加回调返回文件URL
让exportToPDF支持回调,生成PDF后直接触发后续上传流程:
func exportToPDF(completion: @escaping (URL?, Error?) -> Void) { let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let outputFileURL = documentDirectory.appendingPathComponent("SwiftUI.pdf") let width: CGFloat = 8.5 * 72.0 let height: CGFloat = 1000 let charts = SmartSheet() let pdfVC = UIHostingController(rootView: charts) pdfVC.view.frame = CGRect(x: 0, y: 0, width: width, height: height) let rootVC = UIApplication.shared.windows.first?.rootViewController rootVC?.addChild(pdfVC) rootVC?.view.insertSubview(pdfVC.view, at: 0) let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: width, height: height)) DispatchQueue.main.async { do { try pdfRenderer.writePDF(to: outputFileURL, withActions: { (context) in context.beginPage() pdfVC.view.layer.render(in: context.cgContext) }) print("wrote file to: \(outputFileURL.path)") completion(outputFileURL, nil) } catch { print("Could not create PDF file: \(error.localizedDescription)") completion(nil, error) } pdfVC.removeFromParent() pdfVC.view.removeFromSuperview() } }
2. 实现PDF上传函数
读取PDF文件数据,设置正确的MIME类型(application/pdf):
func uploadPDF(at url: URL, completion: @escaping (Error?) -> Void) { // 创建Storage引用,命名可按需调整 let pdfName = "\(v.FirstName)-sheet.pdf" let storageRef = Storage.storage().reference().child("pdfs/\(pdfName)") // 读取PDF文件数据 do { let pdfData = try Data(contentsOf: url) // 设置Metadata,指定内容类型为PDF let metadata = StorageMetadata() metadata.contentType = "application/pdf" // 上传数据 storageRef.putData(pdfData, metadata: metadata) { (_, error) in if let error = error { print("PDF上传失败: \(error.localizedDescription)") completion(error) } else { print("PDF上传成功") completion(nil) } } } catch { print("读取PDF文件失败: \(error.localizedDescription)") completion(error) } }
3. 实现获取PDF下载链接的函数
修改Storage路径即可复用类似逻辑:
func getPDFDownloadURL(completion: @escaping (String?, Error?) -> Void) { let pdfName = "\(v.FirstName)-sheet.pdf" let pdfRef = Storage.storage().reference().child("pdfs/\(pdfName)") pdfRef.downloadURL { url, error in if let error = error { print("获取PDF链接失败: \(error.localizedDescription)") completion(nil, error) } else { completion(url?.absoluteString, nil) } } }
4. 完整调用流程(按钮点击事件)
用回调替代asyncAfter等待,逻辑更可靠:
// 按钮点击时触发 exportToPDF { pdfURL, error in guard let pdfURL = pdfURL, error == nil else { return } uploadPDF(at: pdfURL) { uploadError in guard uploadError == nil else { return } // 上传成功后获取下载链接 getPDFDownloadURL { url, urlError in if let downloadURL = url { print("PDF下载链接: \(downloadURL)") // 可在此将链接保存到数据库或直接使用 } } } }
注意事项
- 不要依赖
asyncAfter等待上传完成,回调方式更适配网络波动场景。 - 确保Firebase Storage规则允许PDF的上传与读取,测试阶段可使用宽松规则(上线后需调整为安全规则):
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write: if request.auth != null; } } }
内容的提问来源于stack exchange,提问作者user17864647
相关产品推荐
相关产品推荐

