如果应用程序在后台,iOS Swift Timer 不会触发

Posted

技术标签:

【中文标题】如果应用程序在后台,iOS Swift Timer 不会触发【英文标题】:iOS Swift Timer in not firing if the App is in the background 【发布时间】:2018-03-28 05:39:03 【问题描述】:

我正在开发一个 Cocoapod 库,我必须在定时器触发时调用一个函数。 我在 ios 应用程序中使用该 Cocoapod,当应用程序进入后台状态时计时器不会触发

private var timer : DispatchSourceTimer? = nil

let queue = DispatchQueue(label: "sample.timer")
timer = DispatchSource.makeTimerSource(queue : queue)
timer?.setEventHandler 

    [weak self] in
    self?.sendData()

timer?.scheduleRepeating(deadline: .now(), interval: .seconds(5))

【问题讨论】:

你的问题是什么? 如何在后台模式下触发计时器@QuocNguyen 我知道您想让应用程序保持活动状态,每五秒运行一次计时器,但是 (a) 这是一个坏主意,因为它会耗尽用户的电池; (b) 它违反了应用商店指南。如果您告诉我们此计时器的功能用途是什么,我们或许可以就如何最好地实现您想要做的事情向您提供建议。 Apple 为各种各样的现实问题提供了各种机制。但是,如果不知道您的图书馆为什么要在后台发送数据,我们就无法为您提供进一步的建议。 @Gokul 你有没有想过如何在应用程序处于后台时触发计时器时运行代码?我想弄清楚同样的事情。 【参考方案1】:

您使用 GCD 计时器(可以在后台线程上运行的 Timer 的替代品)这一事实让我想知道您是否将“背景”一词的两种完全不同的用法混为一谈:

“后台”的一个含义与应用程序运行时的后台队列或线程有关。这与“主”线程/队列形成对比。

而且,是的,GCD 计时器不同于 Timer 实例,因为它们可以在后台队列上运行(假设应用程序本身实际上正在运行)。

“背景”的另一个含义与应用程序的状态有关。您可以在前台运行、在后台运行或被挂起/终止。

当应用程序运行时(在前台或后台),计时器(GCD 计时器或标准 Timer)可以运行。但是如果一个应用被暂停或终止,所有的执行都会停止,包括计时器。

问题是您尝试在应用程序本身已暂停时运行计时器。那是行不通的。

您的应用不会在后台运行,除非您:

请求一点时间来完成一些有限长度的任务(在最近的 iOS 版本中只运行 30 秒);或

您的应用启用了一些后台模式,用于某些经过批准的用途(例如导航、音乐、VOIP 等)。

但应用程序不能继续在后台运行(计时器或其他任何东西),除非是那些特殊的、狭窄的情况(例如 VOIP、音乐、导航应用程序等)。有关后台执行的更多信息,请参阅:

Managing Your App's Life Cycle About the Background Execution Sequence

而且,即使在 iOS 13 及更高版本中,允许更通用的background tasks,它们也适用于有限长度的任务,这些任务将由操作系统自行决定(由电源、wifi、频率决定)用户启动应用程序等)。欲了解更多信息,请参阅 WWDC 2019 Advances in App Background Execution。

【讨论】:

您缺少一个应用状态。 我的意图不是让他了解完整的App Life Cycle,而是让他忘记应用程序(更少的计时器)会在用户离开应用程序时自动继续运行的概念。而且,坦率地说,如果他真的对定期发布更新的各种替代方案有疑问,他真的应该澄清他的问题。【参考方案2】:

这有点老套,但您可以尝试限制您在后台的时间并解决此问题。

import AVFoundation

do 
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: .mixWithOthers)
    try AVAudioSession.sharedInstance().setActive(true)

catch  print(error) 

【讨论】:

需要注意的是,这违反了App Store的指导方针,如果Apple注意到你这样做了,他们很可能会拒绝你的申请。 这不会让你被商店拒绝 guidelines 非常明确:“多任务应用程序只能将后台服务用于其预期目的:VoIP、音频播放、位置、任务完成、本地通知等。如果您的应用程序使用位置背景模式,包括提醒,这样做可能会大大缩短电池寿命。”如果您愿意,您可以尝试偷偷溜过他们,但如果他们发现偷偷使用后台执行,他们拒绝应用程序。我当然不建议为第三方开发人员使用 CocoaPod。 在 AVAudioSession 上使用共享实例解决了这个问题,并且永远不会让你被商店拒绝 “将永远让你被拒绝”......这根本不是真的。这样做的应用程序肯定会通过审核流程,但苹果公司在这一点上毫不含糊,当然可以拒绝这样做的应用程序。现在,如果它真的是一个音乐/视频应用程序,那就另当别论了。但如果这只是一种让应用程序保持活力的技术,他们可以因此拒绝它。此外,这只是一个坏主意。它会杀死用户的电池。 Apple 的指南禁止这种做法是有原因的。

以上是关于如果应用程序在后台,iOS Swift Timer 不会触发的主要内容,如果未能解决你的问题,请参考以下文章

后台任务未在 Swift 中重新启动

将用户位置发送到服务器(Web文件)甚至应用程序已关闭或终止或终止iOS Swift

【Swift】iOS中的定时器

React-Native IOS:Background-Timer 不在后台运行

检测应用程序是不是从后台 Swift iOS 打开

swift中定时器(Timer) 的使用