iOS Sharing Extension异常:URL与HTML上传服务器功能失效求助
排查iOS Sharing Extension上传失效问题
我正在开发一款iOS Sharing Extension,用于获取URL与HTML内容并上传至服务器。该代码曾成功运行2次,但之后突然失效,目前无法复现成功场景。已确认可从主应用获取FirebaseAccessToken,但作为Swift新手,完全找不到问题原因,恳请帮忙排查。
相关代码如下:
override func didSelectPost() { let url = self.extensionContext!.inputItems[0] as! NSExtensionItem let itemProvider = url.attachments![0] as NSItemProvider if itemProvider.hasItemConformingToTypeIdentifier("public.url") { itemProvider.loadItem(forTypeIdentifier: "public.url", options: nil) { (url, error) in if let error = error { // Handle error return } guard let shareURL = url as? URL else { return } // Get the HTML guard let htmlString = try? String(contentsOf: shareURL) else { return } let shareData = ShareData(url: shareURL.absoluteString, html: htmlString) guard let jsonData = try? JSONEncoder().encode(shareData) else { return } // Do sending it to a server let token = UserDefaults(suiteName: "group.com.readout.app")?.string(forKey: "FirebaseAccessToken") let url = URL(string: "http://blabla.com/api/article")! var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("Bearer \(token ?? "")", forHTTPHeaderField: "Authorization") request.httpBody = jsonData let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { // Handle error return } guard let response = response as? HTTPURLResponse else { return } if response.statusCode == 200 { // Successfully sent data } else { // Handle non-200 response } } task.resume() } } self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil) }
问题排查与修复建议
1. 核心问题:Extension生命周期被提前终止
你在loadItem的异步闭包执行前就调用了completeRequest,Extension会直接结束生命周期,导致后续的HTML获取、网络请求等异步任务被强制中断。之前偶尔成功是因为闭包执行速度刚好快于completeRequest,但这是不可靠的。
修复:把completeRequest移到网络请求完成的闭包内,确保所有异步任务结束后再终止Extension:
let task = URLSession.shared.dataTask(with: request) { data, response, error in // ... 原有逻辑 ... // 所有任务完成后再终止Extension DispatchQueue.main.async { self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil) } } task.resume()
2. 错误处理缺失,无法定位故障点
代码中大量使用try?和空的错误处理块,出现任何错误都会静默失败,完全不知道哪一步出问题。比如:
String(contentsOf: shareURL)可能因网络错误、网站反爬限制失败JSONEncoder.encode可能因ShareData不符合Codable要求失败loadItem可能因权限问题获取URL失败
修复:添加错误日志打印,替换try?为do-catch:
// 获取HTML时 do { let htmlString = try String(contentsOf: shareURL) // 后续逻辑 } catch { print("获取HTML失败:\(error.localizedDescription)") DispatchQueue.main.async { self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil) } return } // 编码JSON时 do { let jsonData = try JSONEncoder().encode(shareData) // 后续逻辑 } catch { print("JSON编码失败:\(error.localizedDescription)") DispatchQueue.main.async { self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil) } return }
3. 强制解包存在崩溃风险
extensionContext!.inputItems[0]、url.attachments![0]都是强制解包,如果输入项为空或无附件,会直接崩溃,且Extension崩溃不会在主应用中显示日志。
修复:用可选绑定替换强制解包:
guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem, let itemProvider = extensionItem.attachments?.first as? NSItemProvider else { print("无法获取输入项或附件") extensionContext?.completeRequest(returningItems: [], completionHandler: nil) return }
4. 网络请求的额外注意事项
- 确保Extension的
Info.plist中添加了对应服务器的网络权限(比如HTTP请求需要关闭App Transport Security或添加例外) - 自定义URLSession配置,避免共享session的生命周期问题:
let config = URLSessionConfiguration.default let session = URLSession(configuration: config) let task = session.dataTask(with: request) { ... }
内容的提问来源于stack exchange,提问作者Vynny zePooh
相关产品推荐
相关产品推荐

