iOS点击推送启动App时URLSession服务调用随机报-1005如何解决
问题根因
iOS真机的进程调度策略比模拟器严格很多,点击推送通知触发回调时,系统分配的执行窗口极短,如果不主动申请额外运行时间,App会被快速挂起,正在进行的网络请求会被强制中断,就会抛出NSURLErrorDomain Code=-1005 "The network connection was lost"错误。
你当前的代码缺少后台任务申请逻辑,同时没有针对该类错误的重试机制,是问题的核心诱因。
修复方案
步骤1:新增后台任务权限申请
在AppDelegate中声明后台任务标识变量:
private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
修改推送回调逻辑,发起请求前申请后台执行权限,请求完成后主动释放权限,同时必须调用resume()启动网络任务(若漏写该方法,任务不会被执行):
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { guard response.actionIdentifier == UNNotificationDefaultActionIdentifier else { completionHandler() return } // 向系统申请最长30秒的后台执行时间 backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in // 申请的时间耗尽时,主动结束任务避免App被系统强制杀死 guard let taskID = self?.backgroundTaskID, taskID != .invalid else { return } UIApplication.shared.endBackgroundTask(taskID) self?.backgroundTaskID = .invalid } var urlRequest = URLRequest(url: <#你的请求URL#>) urlRequest.httpMethod = "GET" urlRequest.httpShouldHandleCookies = false urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") urlRequest.addValue(<#你的鉴权头#>, forHTTPHeaderField: "Authorization") self.dataSession.dataTask(with: urlRequest) { [weak self] data, response, error in defer { // 所有逻辑处理完成后,释放后台任务,调用系统要求的回调 guard let taskID = self?.backgroundTaskID, taskID != .invalid else { completionHandler() return } UIApplication.shared.endBackgroundTask(taskID) self?.backgroundTaskID = .invalid completionHandler() } // 针对-1005错误自动重试1次 if let nsError = error as? NSError, nsError.code == -1005 { self?.dataSession.dataTask(with: urlRequest) { retryData, retryResponse, retryError in // 处理重试后的结果,执行页面跳转逻辑 }.resume() return } // 处理正常请求结果,执行页面跳转逻辑 }.resume() }
步骤2:可选优化(针对TCP连接复用导致的偶现错误)
如果修改后仍偶现报错,可调整URLSession配置禁用TCP连接复用,避免复用服务端已关闭的空闲连接:
private lazy var dataSession:URLSession = { var config = URLSessionConfiguration.default config.requestCachePolicy = .reloadIgnoringLocalCacheData config.urlCache = nil config.httpMaximumConnectionsPerHost = 8 config.httpShouldSetCookies = false // 禁用连接复用 config.httpShouldUsePipelining = false return URLSession(configuration: config, delegate: self, delegateQueue: nil) }()
内容的提问来源于stack exchange,提问作者Miles
相关产品推荐
相关产品推荐

