iOS:让应用程序像服务一样运行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11044095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS: Keep an app running like a service
提问by Ian Vink
回答by Gruntcakes
Basically, there is no such thing as a service type app or functionality in iOS. Even the "background" apps (UIBackgroundMode) cannot run entirely free and without restrictions like a service or daemon etc. on other OSs can.
基本上,iOS 中没有服务类型应用程序或功能这样的东西。即使是“后台”应用程序 (UIBackgroundMode) 也不能完全免费运行并且不受其他操作系统上的服务或守护程序等限制。
Here's the situation regarding background execution and notifications and timers etc.
这是有关后台执行、通知和计时器等的情况。
1) An app cannot execute in the background unless:
1) 应用程序不能在后台执行,除非:
a) it requests extra time from the OS to do so. This is done using beginBackgroundTaskWithExpirationHandler. It is not specified (intentionally) by Apple how long this extra time is, however in practice it is around 10 minutes.
a) 它要求操作系统提供额外的时间来这样做。这是使用 beginBackgroundTaskWithExpirationHandler 完成的。Apple 没有(有意地)指定这个额外时间有多长,但实际上大约是 10 分钟。
b) an app has a background mode, the modes are VoIP, audio, location, newsstand. Even if it has one of these types an app cannot execute without restrictions. The rest of this discussion assumes the app does not have a background mode. If you try to use one of these background modes to enable your app to be capable of running in the background but your app does not make legitimate use of the specific functionality then your app will be rejected upon app store submission (i.e. to have a UIBackgroundMode it MUST be either: a VoIP app, NEED to have continual location updates, the ability to play audio in the background continuously is a fundamental feature, or be a newsstand app).
b) 应用有后台模式,模式有 VoIP、音频、位置、报亭。即使它具有这些类型之一,应用程序也无法不受限制地执行。本讨论的其余部分假设应用程序没有后台模式。如果您尝试使用这些后台模式之一来使您的应用程序能够在后台运行,但您的应用程序没有合法使用特定功能,那么您的应用程序将在应用程序商店提交时被拒绝(即具有 UIBackgroundMode它必须是:一个 VoIP 应用程序,需要有持续的位置更新,在后台连续播放音频的能力是一个基本功能,或者是一个报摊应用程序)。
2) When an app is suspended it cannot do ANYTHING to rouse itself directly. It cannot previously have scheduled an NSTimer, it cannot make use of something like performSelector:afterDelay. etc.
2)当一个应用程序被暂停时,它不能做任何事情来直接唤醒自己。它之前不能安排 NSTimer,也不能使用诸如 performSelector:afterDelay 之类的东西。等等。
The ONLY way the app can become active again is if the USER does something to make it active. The user can do this from via of the following:
应用程序可以再次激活的唯一方法是用户做了一些事情来激活它。用户可以通过以下方式执行此操作:
a) Launch the app directly from its icon
a) 直接从其图标启动应用程序
b) Launch the app in response to a local notification that was previously scheduled by the app while it was active.
b) 启动应用程序以响应应用程序先前在活动时安排的本地通知。
c) Launch the app in response to a remote notification sent by a server.
c) 响应服务器发送的远程通知启动应用程序。
d) A few others: such as URL launching if the app is registered to deal with launching via a URL; or if it's registered to be capable of dealing with a certain type of content.
d) 其他一些:例如 URL 启动,如果应用程序注册处理通过 URL 启动;或者它是否注册为能够处理某种类型的内容。
If an app is in the foreground when a local/remote notification fires then the app receives it directly.
如果本地/远程通知触发时应用程序在前台,则应用程序直接接收它。
If the app is not currently in the foreground when a local/remote notification fires then the app DOES NOT receive it. There is no code that is executed when the notification fires!
如果本地/远程通知触发时应用程序当前不在前台,则应用程序不会收到它。通知触发时没有执行任何代码!
Only IF the user selects the notification will the app become active and it can execute.
只有当用户选择通知时,应用才会激活并可以执行。
Note that the user can disable notifications, either for the entire device or just for a specific application, in which case the user will never see them. If the device is turned off when a notification is due to fire then it is lost.
请注意,用户可以针对整个设备或仅针对特定应用程序禁用通知,在这种情况下,用户将永远不会看到它们。如果设备在通知发生火灾时关闭,那么它就会丢失。
UPDATE FOR IOS 7
IOS 7 更新
1) there are some new background modes such as background fetch (you still can't be roused by the OS in a deterministic fashion however)
1)有一些新的后台模式,例如后台获取(但是,您仍然无法以确定性的方式被操作系统唤醒)
2) there's now a background push notification
2)现在有一个后台推送通知
3) beginBackgroundTaskWithExpirationHandler time has reduced from 10 minutes to about 3.
3) beginBackgroundTaskWithExpirationHandler 时间从 10 分钟减少到大约 3 分钟。
回答by Ajo
Updated to Swift 5:
更新到Swift 5:
Maybe not the right answer to the OP. But this will help you start a background task
whenever the app goes into the background. And gets itself killed by iOS after sometime (Hopefully after the processing is finished).
也许不是 OP 的正确答案。但这将帮助您background task
在应用程序进入后台时启动。并在一段时间后被iOS 杀死(希望在处理完成后)。
Create an extension
创建扩展
extension Notification.Name {
@discardableResult
func observe(using: @escaping (Notification) -> Void) -> NSObjectProtocol {
return NotificationCenter.default.addObserver(forName: self,
object: nil,
queue: OperationQueue.main,
using: using)
}
}
Declare a variable
声明一个变量
fileprivate let backgroundTaskStarter = {
// TODO: If this doesn't work, switch to willResignActiveNotification.
UIApplication.didEnterBackgroundNotification.observe() { _ in
UIApplication.shared.beginBackgroundTask {
print("endBackgroundTask called by iOS")
}
}
}()
And in Filename.swift
's init()
method, do:
和 inFilename.swift
的init()
方法,做:
_ = backgroundTaskStarter
回答by Tarek Hallak
Things changed now in iOS7, it is beta now.
现在情况改变了在iOS7,现在是测试版。
From Apple's developer portal:
从苹果的开发者门户:
Keep the content of your app up-to-date by adopting the new multitasking APIs in iOS 7. The new services allow your app to update information and download content in the background without draining the battery unnecessarily. The updates can happen at opportunistic times and are intelligently scheduled according to usage, so your app can update content in the background just when your users need it.
通过在 iOS 7 中采用新的多任务 API,使您的应用程序的内容保持最新。新服务允许您的应用程序在后台更新信息和下载内容,而不会不必要地耗尽电池电量。更新可能会适时发生,并根据使用情况进行智能安排,因此您的应用可以在用户需要时在后台更新内容。
回答by Zoeb S
Yes we can do this,
是的,我们可以做到这一点,
Create a private field to track our status:
创建一个私有字段来跟踪我们的状态:
UIBackgroundTaskIdentifier _bgTask;
Now call this method, to run your app like a service
现在调用这个方法,像服务一样运行你的应用程序
if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)])
{
? ?_bgTask = UIBackgroundTaskInvalid;
? ?[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(doBackground:)
name:UIApplicationDidEnterBackgroundNotification object:nil];
}
Now create a selector-
现在创建一个选择器-
- (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;
? ? ? ? ? ? }
? ? ? ? ?});
? ? ? }];
? ?}
}
When you finished your task, call below code-
完成任务后,调用以下代码-
UIApplication *app = [UIApplication sharedApplication];
if ([app respondsToSelector:@selector(endBackgroundTask:)])
{
? ?if (_bgTask != UIBackgroundTaskInvalid)
? ?{
? ? ? [app endBackgroundTask:_bgTask];
? ? ? _bgTask = UIBackgroundTaskInvalid;
? ?}
}