【问题标题】:Perform background tasks when app is terminated应用程序终止时执行后台任务
【发布时间】:2016-11-06 13:03:08
【问题描述】:

我正在为我的学校创建一个应用程序,如果网站上有新标记,它应该每 n 分钟检查一次。 为此,当用户第一次登录时,实际标记的编号保存在“UserDefaults”中。当app终止时,n分钟后,重新计算mark的数量,并与之前的比较,如果数量有变化,发送通知。

我想知道是否有办法执行此任务。我试图在 -applicationWillTerminate- 中创建一个计时器,但它只触发一次。 这是我尝试过的:

func applicationWillTerminate(_ application: UIApplication) {
    DispatchQueue.main.async {
        self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(AppDelegate.findMark), userInfo: nil, repeats: true)
        self.timer.fire()
    }
}

选择器 findMark 是任务。

提前致谢!

【问题讨论】:

  • 应用程序终止时无法执行此操作。请检查我的答案。如有任何疑问,请随时提出:)
  • 您打算在后台无限期运行应用程序还是仅在应用程序终止时运行该应用程序?
  • 我的理解是你想在后台运行它无限时间,每当计数器更新标记的数量时,你想发送通知,就是你打算做的?
  • 是的,@Sharpkits..无限时间

标签: ios swift


【解决方案1】:

你有两个选择

  1. 后台应用刷新
  2. 静默推送通知

最简单的是后台应用刷新。因为以后需要一台服务器来发送通知。您可以查看以下API 的用法。基本上,您在应用的功能/背景模式上设置 Background Fetch 功能。然后,iOS 会不时唤醒你的应用并调用application(_:performFetchWithCompletionHandler:)delegate。您将有大约 30-45 秒的时间来调用您的函数并调用完成处理程序。如果你没有按时完成它,iOS 会杀死你的应用程序。如果你不遵守规则,iOS 会给你更少的醒来机会。后台模式更详细的使用方法,可以关注tutorial

【讨论】:

  • 我读到 application(_:performFetchWithCompletionHandler:) 不会每 n 分钟执行一次任务.. 对吗?
  • 是的。 iOS 会安排这个调用,你无法知道它什么时候会被调用。但是,使用的应用程序越多,iOS 将调用此处理程序的次数越多。没有推送通知,就没有可靠的方法在 n 分钟内唤醒应用。
  • 我会说 VoIP 推送通知使这成为可能。
  • 嗯,那Alarmy App是怎么做到的呢? Alarmy 不需要 WiFi,也不需要 GSM,也不需要推送 - 他们是如何做到的?
  • @funct7 这也是错误的,(至少在 iOS 13 中)静默 ("content_available": true) 推送通知实际上会启动应用程序,即使它完全被用户杀死而不是在应用程序中切换器。但是,在这种情况下,您不能执行长时间的扩展后台任务。来源:一秒钟前刚刚测试过。
【解决方案2】:

应用终止后,无法执行问题中所述的任务。如文档中所述:

应用程序终止

应用程序必须随时准备终止,不应等待保存用户数据或执行其他关键任务。系统启动的终止是应用程序生命周期的正常部分。系统通常会终止应用程序,以便它可以回收内存并为用户启动的其他应用程序腾出空间,但系统也可能会终止行为不端或未及时响应事件的应用程序。

暂停的应用在终止时不会收到任何通知;系统杀死进程并回收相应的内存。如果应用程序当前正在后台运行且未挂起,则系统会在终止之前调用其应用程序委托的 applicationWillTerminate:。设备重启时系统不会调用该方法。

除了系统终止您的应用外,用户还可以使用多任务 UI 显式终止您的应用。用户发起的终止与终止暂停的应用程序具有相同的效果。应用程序的进程被杀死,并且没有通知发送到应用程序。

链接:https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html

编辑:

应用程序终止后,您将无法执行任何任务。您可以做的是从服务器端完成计算并将Push Notification 发送到设备。

【讨论】:

  • 谢谢,我该怎么办?因为有很多离线游戏会在何时发送通知,例如建筑物被终止..即使使用多任务管理器手动关闭应用程序也会出现这种情况..
  • 这是 PushNotification 或 LocalNotification。如果这是需要的,那么我将在答案中添加。等等..
  • 是的,这就是我所指的......但是当应用程序关闭时,发送 localNotification 的任务只被调用一次
  • 我再次阅读了您的问题。当应用终止时,您无法计算应用内网站的分数。
  • 应用终止时无法发送 UILocalNotification。但是,您可以从服务器发送推送通知
【解决方案3】:

确实,答案是肯定的。但你不应该。 我们可以使用位置来归档您的目标。 根据这里的官方文档:https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW10:

注意:如果您的应用程序被用户或系统终止,则 新位置时系统不会自动重启您的应用 更新到达。用户必须在 恢复位置更新的交付。拥有您的应用程序的唯一方法 自动重新启动是使用区域监控或 重大变化的定位服务。

所以我们可以使用启动显着变化定位服务来归档它:

如果您让重大变化的定位服务继续运行并且您的 iOS 应用程序随后被暂停或终止,服务 当新的位置数据到达时自动唤醒您的应用。在 唤醒时间,应用程序进入后台,你会得到一个 手动重启定位的少量时间(大约 10 秒) 服务和处理位置数据。 (必须手动重启 在任何待定位置之前在后台提供定位服务 可以交付更新,如了解何时开始中所述 位置服务。)因为您的应用程序在后台,所以它必须这样做 最少的工作并避免任何任务(例如查询网络) 可能会阻止它在分配的时间到期之前返回。如果 它没有,您的应用程序将被终止。如果 iOS 应用程序需要更多 处理位置数据的时间,它可以请求更多背景 执行时间使用 beginBackgroundTaskWithName:expirationHandler: 方法 UIApplication 类。

在 willFinishLaunchingWithOptions 和 applicationDidBecomeActive 中调用 location update 之后就可以执行自己的代码了

[_locationManager startUpdatingLocation];

但是这会非常耗电,您可能会被应用商店拒绝。

【讨论】:

  • 我从来没有想过这个问题。我去看看,看看app store会不会拒绝。
  • @SelloneCiompi 您是否尝试通过 Apple 审查?它通过了吗?我正在尝试实施相同的方法,并问自己是否有机会通过审查过程。
  • 嗨@Teetz,是的,我做到了,Apple Review 毫无问题地通过了 :) 我或多或少在 3 年前做过,从那天起我就再也没有更新过,但我认为 Apple 的政策还是一样...我希望!让我知道:D
  • @SelloneCiompi 非常感谢您的回复。这将需要一些时间,因为在我们的案例中这应该是一个专业的商业应用程序。当我们通过(或不通过)审查时,我会通知您:)
  • 我不认为以 3 公里的精度更新位置会完全耗尽电池电量 - 如果该信息可用,这种粗粒度的粒度将被动地使用手机信号塔进行定位,并且会不启动任何额外的传感器。电池成本应该可以忽略不计。
最近更新 更多