34

在 iOS 中,即使应用程序不再处于前台,我将如何指示操作系统保持我的应用程序运行?

还有更多的应用程序这样做。

4

4 回答 4

58

基本上,iOS 中不存在服务类型应用程序或功能之类的东西。即使是“后台”应用程序(UIBackgroundMode)也不能完全免费运行,并且不受其他操作系统上的服务或守护程序等限制。

这是有关后台执行以及通知和计时器等的情况。

1) 应用程序无法在后台执行,除非:

a) 它要求操作系统有额外的时间来这样做。这是使用 beginBackgroundTaskWithExpirationHandler 完成的。Apple 没有(有意)指定这个额外的时间有多长,但实际上它大约是 10 分钟。

b) 应用程序具有后台模式,模式为 VoIP、音频、位置、报亭。即使它具有这些类型之一,应用程序也无法不受限制地执行。本讨论的其余部分假设应用程序没有后台模式。如果您尝试使用其中一种后台模式来使您的应用能够在后台运行,但您的应用没有合法使用特定功能,那么您的应用将在应用商店提交时被拒绝(即拥有 UIBackgroundMode它必须是:VoIP 应用程序,需要不断更新位置,在后台连续播放音频的能力是一项基本功能,或者是报亭应用程序)。

2)当一个应用程序被暂停时,它不能做任何事情来直接唤醒自己。它以前不能安排一个 NSTimer,它不能使用像 performSelector:afterDelay 这样的东西。等等

应用程序可以再次激活的唯一方法是用户执行某些操作使其激活。用户可以通过以下方式执行此操作:

a) 直接从其图标启动应用程序

b) 启动应用程序以响应应用程序先前在其处于活动状态时安排的本地通知。

c) 启动应用程序以响应服务器发送的远程通知。

d) 其他一些:例如,如果应用程序注册为处理通过 URL 启动,则 URL 启动;或者如果它被注册为能够处理某种类型的内容。

如果本地/远程通知触发时应用程序处于前台,则应用程序直接接收它。

如果在本地/远程通知触发时应用程序当前不在前台,则应用程序不会收到它。通知触发时没有执行任何代码!

只有当用户选择通知时,应用才会激活并且可以执行。

请注意,用户可以为整个设备或仅针对特定应用程序禁用通知,在这种情况下,用户将永远看不到它们。如果在通知即将触发时关闭设备,则它会丢失。

IOS 7 更新

1)有一些新的后台模式,比如后台获取(但是你仍然不能被操作系统以一种确定的方式唤醒)

2)现在有一个后台推送通知

3) beginBackgroundTaskWithExpirationHandler 时间从 10 分钟减少到 3 分钟左右。

于 2012-06-15T03:05:56.463 回答
3

现在iOS7发生了变化,现在是测试版

来自Apple 的开发者门户

通过采用 iOS 7 中新的多任务 API,使您的应用程序的内容保持最新。新服务允许您的应用程序在后台更新信息和下载内容,而不会不必要地耗尽电池电量。更新可以在机会性的时间发生,并根据使用情况智能安排,因此您的应用可以在用户需要时在后台更新内容。

于 2013-09-05T09:00:56.340 回答
3

更新到Swift 5

也许不是 OP 的正确答案。但这将帮助您background task在应用程序进入后台时启动。并在一段时间后被iOS杀死(希望在处理完成之后)。

创建扩展

extension Notification.Name {
  @discardableResult
  func observe(using: @escaping (Notification) -> Void) -> NSObjectProtocol {
    return NotificationCenter.default.addObserver(forName: self,
                                                  object: nil,
                                                  queue: OperationQueue.main,
                                                  using: using)
  }
}

声明一个变量

fileprivate let backgroundTaskStarter = {
  // TODO: If this doesn't work, switch to willResignActiveNotification.
  UIApplication.didEnterBackgroundNotification.observe() { _ in
    UIApplication.shared.beginBackgroundTask {
      print("endBackgroundTask called by iOS")
    }
  }
}()

Filename.swift'sinit()方法中,执行以下操作:

_ = backgroundTaskStarter
于 2019-05-07T10:53:09.223 回答
1

是的,我们可以做到这一点,

创建一个私有字段来跟踪我们的状态:

UIBackgroundTaskIdentifier _bgTask;

现在调用这个方法,像服务一样运行你的应用程序

if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]) 
{
   _bgTask = UIBackgroundTaskInvalid;
   [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(doBackground:)
name:UIApplicationDidEnterBackgroundNotification object:nil];
}

现在创建一个选择器-

- (void) doBackground:(NSNotification *)aNotification
{
   UIApplication *app = [UIApplication sharedApplication];

   if ([app respondsToSelector:@selector(beginBackgroundTaskWithExpirationHandler:)])
   {
      _bgTask = [app beginBackgroundTaskWithExpirationHandler:^
      {
         dispatch_async(dispatch_get_main_queue(), ^
         {
            if (_bgTask != UIBackgroundTaskInvalid)
            {
               [app endBackgroundTask:_bgTask];
               _bgTask = UIBackgroundTaskInvalid;
            }
         });
      }];
   }
}

完成任务后,请调用以下代码-

UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:@selector(endBackgroundTask:)]) 
{
   if (_bgTask != UIBackgroundTaskInvalid)
   {
      [app endBackgroundTask:_bgTask];
      _bgTask = UIBackgroundTaskInvalid;
   }
}
于 2013-09-05T09:44:27.460 回答