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

Swift 5 技术疑问:如何让计时器在后台模式下持续运行?

iOS后台持续运行计时器的解决方案

首先明确:iOS系统出于资源优化,会在应用进入后台后挂起主线程RunLoop,你用的Timer.scheduledTimer依赖主线程RunLoop,所以必然会停止。要实现后台持续运行,得根据需求选择以下方案:

方案1:短时间后台任务(最长约3分钟)

如果只是需要在后台短时间内维持计时器运行,可以利用系统提供的后台任务机制,申请额外的后台执行时间:

修改你的backgroundRefreshStatusDidChange方法:

@objc func backgroundRefreshStatusDidChange(notification: NSNotification) {
    print("New status: \(UIApplication.shared.backgroundRefreshStatus)")
    
    // 启动后台任务
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
    backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "BackgroundTimerTask") { [weak self] in
        // 后台任务即将到期,结束任务
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
        self?.timer?.cancel()
    }
    
    // 使用GCD定时器替代普通Timer,更可靠
    let queue = DispatchQueue.global(qos: .background)
    timer = DispatchSource.makeTimerSource(queue: queue)
    timer?.schedule(deadline: .now(), repeating: 0.5)
    timer?.setEventHandler { [weak self] in
        // 回到主线程执行UI相关操作
        DispatchQueue.main.async {
            self?.timerAction()
        }
    }
    timer?.resume()
}

@objc func timerAction() {
    print("Timer fired in background/foreground")
}

注意:后台任务的时间限制由系统控制,通常最多3分钟左右,到期前系统会触发结束回调,必须及时调用endBackgroundTask,否则应用会被系统终止。

方案2:长时间后台运行(需申请特定后台模式)

如果需要持续运行超过3分钟,必须在Xcode中配置对应的后台模式,且只能用于符合苹果政策的场景:

  1. 音频类场景:开启Audio, AirPlay, and Picture in Picture后台模式,播放静音音频(需正确配置音频会话)来保持应用活跃,这种方式下GCD定时器可以持续运行。
  2. 定位类场景:开启Location updates后台模式,使用持续定位(需用户授权),但要注意频繁定位会消耗电量,且审核时需明确说明必要性。
  3. VoIP/推送唤醒:如果是VoIP应用,开启Voice over IP模式,通过推送唤醒应用执行任务,但这不是持续计时,而是按需唤醒。

以音频后台模式为例,配置步骤:

  • 在Xcode项目的Signing & Capabilities中添加Background Modes,勾选Audio, AirPlay, and Picture in Picture。
  • 在应用启动时配置音频会话:
import AVFoundation

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playback, mode: .default)
        try audioSession.setActive(true)
    } catch {
        print("Audio session setup failed: \(error)")
    }
    return true
}

之后再使用GCD定时器,就能在后台持续运行。

重要提醒

苹果对后台执行的审核非常严格,禁止无合理理由的后台持续运行。如果你的需求是周期性执行任务而非持续计时,建议使用Background App Refresh(后台刷新),系统会在合适的时机唤醒应用执行任务,这种方式更符合iOS的设计规范,也更容易通过审核。

内容的提问来源于stack exchange,提问作者Muhammad Manzar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:30:55