SwiftUI如何将相机拍摄的照片直接上传至服务器(非相册选取)
实现方案
你现有代码里已经在拍摄完成时拿到了图片原始二进制数据,完全不需要走相册选取的流程,只要打通相机模块和上传模块的数据流,加个直接上传的入口即可,改造成本很低。
核心改造点
- 你的
CameraModel类在拍摄回调里已经把图片数据存在了@Published var picData = Data(count:0)属性中,这部分数据可以直接用来上传,不需要先写入系统相册再重新读取。 - 把上传逻辑抽成公共可复用方法,相册选图、相机拍图两种场景都能调用,避免写重复代码。
- 在相机拍摄完成后的操作栏加「上传」按钮,不需要强制用户先保存到相册再跳转选图。
具体代码修改
第一步:抽离公共上传方法
把原来写在PictureView里的上传逻辑抽成独立方法,减少冗余转码步骤:
import Foundation import UIKit // 可放到公共工具类中,全局可调用 func uploadImage(imageData: Data, completion: @escaping (Bool, String?) -> Void) { // 直接用传入的原始图片数据转base64,避免反复转Image/UIImage造成画质损失 let imageStr = imageData.base64EncodedString() guard let url = URL(string: "gs://lalala-af09c.appspot.com/swiftui-save-image.php") else { completion(false, "上传地址无效") return } let paramStr = "image=\(imageStr)" guard let paramData = paramStr.data(using: .utf8) else { completion(false, "参数编码失败") return } var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = paramData request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { completion(false, error.localizedDescription) return } guard let data = data else { completion(false, "服务端返回数据为空") return } let responseText = String(data: data, encoding: .utf8) ?? "" completion(true, responseText) }.resume() }
第二步:给相机页面添加上传入口
在拍摄完成后的操作栏加直接上传按钮,复用已经拿到的picData,不需要跳转相册页面:
// 只贴CameraView中需要修改的底部按钮栏代码,其余原有拍摄、重拍、保存相册逻辑保持不变 HStack{ if camera.isTaken{ Button(action: { if !camera.isSaved{ camera.savePic() } }, label: { Text(camera.isSaved ? "Saved" : "Save") .foregroundColor(.black) .fontWeight(.semibold) .padding(.vertical,10) .padding(.horizontal,20) .background(Color.white) .clipShape(Capsule()) }).padding(.leading) // 新增直接上传按钮 Button(action: { guard !camera.picData.isEmpty else { return } uploadImage(imageData: camera.picData) { success, msg in DispatchQueue.main.async { // 主线程更新UI,可加成功/失败提示 print(success ? "上传成功:\(msg ?? "")" : "上传失败:\(msg ?? "")") } } }, label: { Text("Upload") .foregroundColor(.white) .fontWeight(.semibold) .padding(.vertical,10) .padding(.horizontal,20) .background(Color.blue) .clipShape(Capsule()) }) Spacer() }else{ Button(action: camera.takePic, label: { ZStack{ Circle() .fill(Color.white) .frame(width: 65, height: 65, alignment: .center) Circle() .stroke(Color.white,lineWidth: 2) .frame(width: 75, height: 75, alignment: .center) } }) } }.frame(height: 75)
第三步:可选优化
- 如果需要拍完自动上传,不需要用户点按钮,直接把上传逻辑加到
CameraModel的photoOutput(_:didFinishProcessingPhoto:error:)代理方法里,拿到picData后直接调用上传方法即可。 - 原有相册选图上传的逻辑也可以直接复用
uploadImage方法,删掉原来冗余的Image转UIImage的代码,在ImagePicker选图时直接存原始UIImage的JPEG数据即可,减少性能损耗。 - 保存到相册的逻辑可以保留,给用户选择权,不需要强制写入相册才能上传。
内容的提问来源于stack exchange,提问作者LeraValera
相关产品推荐
相关产品推荐

