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

Swift实现应用进入后台/终止时向服务器发送请求的方案

解决方案:在App后台/终止时发送请求并接收推送

首先得说,你之前尝试用NotificationCenter观察者来监听UIApplicationWillTerminate其实没必要——AppDelegate本身就提供了对应的生命周期回调方法,直接重写这些方法就行,这也是你观察者没生效的核心原因之一。接下来我会一步步帮你调整代码,实现需求:

核心问题分析

当App进入后台或即将终止时,系统会很快挂起App,普通的网络请求大概率会被中断。所以我们需要申请后台任务时间来保证请求能完成;另外applicationWillTerminate的触发场景很有限(只有用户手动划掉App且系统资源充足时才会调用),所以重点要放在applicationDidEnterBackground上。

步骤1:修改后台请求逻辑(添加后台任务)

更新applicationDidEnterBackground和applicationWillTerminate方法,给网络请求争取足够的后台执行时间:

func applicationDidEnterBackground(_ application: UIApplication) {
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
    
    // 启动后台任务,告诉系统"我还有活儿没干完"
    backgroundTaskID = application.beginBackgroundTask(withName: "SendBackgroundRequest") {
        // 任务超时,必须结束后台任务,否则系统会终止App
        application.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    }
    
    // 在全局队列执行请求,避免阻塞主线程
    DispatchQueue.global().async { [weak self] in
        guard let self = self else { return }
        
        // 发送请求,注意要给getLiveMatches加回调,方便任务结束后通知系统
        if let vc = self.window?.rootViewController as? LiveScores {
            vc.getLiveMatches(url: URL(string: "http://opucukgonder.com/tipster/index.php/Service/lastLive")) {
                // 请求完成,结束后台任务
                application.endBackgroundTask(backgroundTaskID)
                backgroundTaskID = .invalid
            }
        } else {
            // 无法获取VC时直接结束任务
            application.endBackgroundTask(backgroundTaskID)
            backgroundTaskID = .invalid
        }
        
        self.mS.StartTimer()
    }
}

func applicationWillTerminate(_ application: UIApplication) {
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
    
    backgroundTaskID = application.beginBackgroundTask(withName: "SendTerminateRequest") {
        application.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    }
    
    DispatchQueue.global().async { [weak self] in
        guard let self = self else { return }
        
        if let vc = self.window?.rootViewController as? LiveScores {
            vc.getLiveMatches(url: URL(string: "http://opucukgonder.com/tipster/index.php/Service/lastLive")) {
                application.endBackgroundTask(backgroundTaskID)
                backgroundTaskID = .invalid
            }
        } else {
            application.endBackgroundTask(backgroundTaskID)
            backgroundTaskID = .invalid
        }
        
        self.mS.StartTimer()
    }
}

步骤2:更新getLiveMatches方法(添加完成回调)

你的getLiveMatches需要支持异步回调,这样才能在请求完成后结束后台任务。修改LiveScoresViewController里的方法:

func getLiveMatches(url: URL?, completion: @escaping () -> Void) {
    guard let requestUrl = url else {
        print("无效的URL")
        completion()
        return
    }
    
    URLSession.shared.dataTask(with: requestUrl) { data, response, error in
        defer {
            // 不管成功失败,都要调用completion结束后台任务
            completion()
        }
        
        if let error = error {
            print("请求失败: \(error.localizedDescription)")
            return
        }
        
        guard let data = data else {
            print("未获取到响应数据")
            return
        }
        
        // 解析JSON数据(根据你的业务逻辑调整)
        do {
            let jsonResult = try JSONSerialization.jsonObject(with: data, options: [])
            // 如果需要更新UI,必须切回主线程
            DispatchQueue.main.async {
                // 这里写更新UI的逻辑,比如刷新赛事数据
            }
        } catch {
            print("JSON解析失败: \(error.localizedDescription)")
        }
    }.resume()
}

步骤3:配置后台模式

在Xcode中打开项目的Capabilities选项卡,找到Background Modes并勾选Remote notifications——这样App才能在后台接收服务器返回的推送通知,并且保证推送能正常展示。

步骤4:服务器端推送逻辑

当你的服务器收到App发送的请求后,需要通过OneSignal给对应的设备发送推送。确保服务器能获取到设备的OneSignal Player ID(你可以在App启动时通过OneSignal的API获取并上传到服务器),这样就能精准推送通知到目标设备。

注意事项

  1. applicationWillTerminate的触发场景非常有限,大部分时候App被系统终止时不会调用这个方法,所以不要把核心逻辑依赖在这里,重点放在applicationDidEnterBackground。
  2. 后台任务的时间是有限的(iOS 13+约30秒),所以你的请求要尽量轻量,避免耗时操作。
  3. 移除你之前添加的UIApplicationWillTerminate观察者,直接用AppDelegate的回调方法即可。

内容的提问来源于stack exchange,提问作者Burhan Toprakman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:18:44