Background — 应用程序生命周期中的一种状态,在此状态下它继续运行但不在屏幕上显示。我们解释 iOS 和 Android 后台工作的基础知识:限制、超时、通过 beginBackgroundTask、WorkManager 和 Service 进行的后台任务,以及正确处理 Background 的最佳实践。
要点
Background — 应用程序的一种状态,在此状态下它继续存在于操作系统中,执行代码并消耗资源,但不在设备屏幕上显示。用户位于主屏幕、另一个应用程序中,或者设备屏幕已锁定。在 iOS 中,Background 在 Inactive 之后 — 转换链:Active → Inactive → Background。在 Android 中,onStop 表示 Activity 转换到 Background。
两个平台都对后台工作施加了严格的限制。iOS 提供了一个有限的时间窗口(通常为 30 秒)在进入 Background 后执行代码,之后应用程序将转换为 Suspended。Android 更加灵活:带有可见通知的 Foreground Service 可以无限期工作,但普通的 Background Service 限制为几分钟。开发者的关键任务 — 正确保存状态并通过系统后台任务 API 计划工作的继续。
系统可以在内存不足时随时终止后台应用程序。终止时,所有未保存的数据都会丢失。因此,在 applicationDidEnterBackground(iOS)或 onStop(Android)中保存状态至关重要。终止后,下次启动时应用程序从 Not Running 状态冷启动,并恢复已保存的状态。
区分 Background 和 Suspended 很重要。Background — 应用程序正在主动执行代码。Suspended — 应用程序在内存中但不执行代码 — 被冻结。在 iOS 中,应用程序在后台任务完成后从 Background 转换到 Suspended。在 Android 中没有 Suspended — 进程要么存在(包括后台),要么已终止(Not Running)。但是 Android 可以通过 LMK(Low Memory Killer)暂停线程的执行。
| 特征 | iOS Background | Android Background |
|---|---|---|
| 代码执行 | 是,最多 30 秒 | 是,取决于 API |
| UI 可见 | 否 | 否 |
| 默认超时 | ~30 秒 (beginBackgroundTask) | 几分钟 (Service) |
| 无限工作 | 仅限特殊类别(音频、VoIP、导航) | 带有通知的 Foreground Service |
| 执行保证 | 否 — 系统可以随时终止 | WorkManager 保证执行 |
| 需要权限 | 是 — Info.plist 中的 capabilities | 是 — FOREGROUND_SERVICE 权限 |
| 下一个状态 | Suspended → Not Running | Not Running(或重启) |
在 iOS 中,Background 通过委托方法 applicationDidEnterBackground 处理。在此方法中,开发者应保存用户状态、释放资源并完成后台任务。为了在进入 Background 后执行代码,使用 beginBackgroundTask(expirationHandler:) — 一个向系统请求额外时间(通常为 30 秒)的 API。如果任务在此时间内未完成,则会调用 expirationHandler,应用程序被强制转换为 Suspended。
从 iOS 13 开始,Apple 引入了 BGTaskScheduler — 一个用于计划后台任务的现代 API。与 beginBackgroundTask 不同,它仅在进入后台后提供完成时间,BGTaskScheduler 允许计划将来任务的执行 — 例如,每小时更新一次内容或在夜间上传分析数据。BGTaskScheduler 是新项目的推荐方法,因为它更节能。
import UIKit
import BackgroundTasks
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
// 应用程序进入后台 — 开始后台任务
func applicationDidEnterBackground(_ application: UIApplication) {
saveAppState()
startBackgroundTask()
}
private func startBackgroundTask() {
backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
// 时间到了 — 强制结束
self?.endBackgroundTask()
}
// 模拟后台工作(将数据保存到服务器)
DispatchQueue.global().async { [weak self] in
uploadAnalyticsData()
self?.endBackgroundTask()
}
}
private func endBackgroundTask() {
guard backgroundTaskID != .invalid else { return }
UIApplication.shared.endBackgroundTask(backgroundTaskID)
backgroundTaskID = .invalid
}
// 注册 BGTaskScheduler
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: "com.example.refresh",
using: nil
) { task in
handleAppRefresh(task: task as! BGAppRefreshTask)
}
return true
}
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 3600)
try? BGTaskScheduler.shared.submit(request)
}
func handleAppRefresh(task: BGAppRefreshTask) {
scheduleAppRefresh()
task.expirationHandler = { task.setTaskCompleted(success: false) }
fetchLatestData { result in
task.setTaskCompleted(success: result)
}
}
}代码展示了 iOS 中 Background 的完整处理。applicationDidEnterBackground 通过 beginBackgroundTask 启动一个后台任务,带有超时和 expirationHandler。同时注册 BGTaskScheduler 用于定期内容更新。beginBackgroundTask 用于立即完成工作,BGTaskScheduler 用于长期计划。两个 API 都需要正确管理任务标识符。
在 Android 中,Background 通过多个 API 管理。传统的 Service 允许在后台执行代码,但从 Android 8+(API 26)开始,Background Service 受到限制:系统在应用程序进入后台几分钟后将其终止。带有永久通知的 Foreground Service 可以无限期工作。WorkManager — 推荐的后台任务解决方案,即使在设备重启后也能保证执行。
Android 与 iOS 不同,支持长时间运行的后台进程。Foreground Service 用于用户应该看到的任务 — 播放音乐、导航、记录锻炼。JobScheduler 和 WorkManager — 用于可以延迟的任务:数据同步、上传日志、更新缓存。关键区别:Android 允许带有条件的任务计划 — Wi-Fi、充电、设备不活动,这节省了电池和数据流量。
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.work.*
// 1. Foreground Service 用于长时间后台工作
class SyncService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val notification = createNotification()
startForeground(NOTIFICATION_ID, notification)
performBackgroundWork()
return START_STICKY
}
private fun performBackgroundWork() {
Thread {
// 与服务器同步数据
syncDataToServer()
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}.start()
}
override fun onBind(intent: Intent?): IBinder? = null
}
// 2. WorkManager 用于延迟的后台任务
class DataSyncWorker(
private val context: Context,
private val params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// 将分析数据上传到服务器
uploadAnalytics()
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
// 计划 WorkManager 任务
fun scheduleBackgroundSync(context: Context) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val request = OneTimeWorkRequestBuilder<DataSyncWorker>()
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context).enqueue(request)
}代码展示了 Android 后台工作的两种方法。SyncService — 带有通知的 Foreground Service,用于立即和长时间的后台工作。DataSyncWorker — WorkManager 用于带有条件(Wi-Fi、充电)的延迟任务。WorkManager 保证即使在设备重启后也能执行,并支持指数退避以进行重试。Foreground Service 需要在状态栏中有永久通知。
两个移动平台都在不断收紧后台工作规则。在 iOS 中,每一代新操作系统都减少后台工作时间并增加新的限制。在 Android 中,Google 引入了越来越严格的省电模式(Doze、App Standby)。开发者必须了解当前的限制,以便应用程序不会被系统提前终止。
在 iOS 中,从 iOS 13 开始,系统会关闭滥用后台时间的应用程序的后台任务。每个应用程序根据用户行为获得特定的限制。BGTaskScheduler 在最佳时间计划执行 — 例如,当设备连接到 Wi-Fi 并正在充电时。正确使用 BGTaskScheduler 的应用程序会获得更多的后台时间。
在 Android 中,从 Android 9(API 28)开始,后台工作受到 Doze 模式的限制,该模式在设备不活动时激活。处于 Doze 状态的应用程序无法执行后台任务,网络关闭,JobScheduler 和 WorkManager 将任务推迟到退出 Doze。Foreground Service 是绕过 Doze 的唯一方法,但滥用会导致用户阻止应用程序并删除权限。
| 限制 | iOS | Android |
|---|---|---|
| 后台任务超时 | ~30 秒 (beginBackgroundTask) | 几分钟 (JobScheduler) |
| 无限制后台 | 音频、VoIP、导航、蓝牙 | Foreground Service + 通知 |
| 省电 | Low Power Mode — 关闭后台任务 | Doze、App Standby、Battery Optimization |
| 计划 | BGTaskScheduler (iOS 13+) | WorkManager (Android Jetpack) |
| 重启后 | 仅推送通知 | WorkManager 保留任务 |
| 最大执行时间 | ~30 分钟(音频) | 无限制(Foreground Service) |
第一条规则 — 最小化后台资源消耗。大多数后台任务可以推迟到设备充电并连接到 Wi-Fi 时。使用 BGTaskScheduler(iOS)和 WorkManager(Android)计划带有条件的任务。不要在后台运行繁重的计算 — 这会耗尽电池并导致 CPU 节流。
第二条规则 — 始终为 beginBackgroundTask 指定 expirationHandler。如果应用程序未在规定时间内完成任务,系统将强制将其转换为 Suspended 或终止。ExpirationHandler 是保存数据和正确结束工作的最后机会。在 Android 中,在 WorkManager 中使用 setForegroundAsync 将普通任务转换为前台任务,如果需要更多时间。
第三条规则 — 在启动前检查后台工作的限制。在 iOS 中,使用 UIApplication.shared.backgroundTimeRemaining 检查剩余时间。在 Android 中,检查 ActivityManager.isBackgroundRestricted() — 如果为 true,应用程序将无法启动后台任务,需要建议用户在设置中移除限制。这对于具有关键后台功能的应用程序尤其重要 — 闹钟、日历、同步。
第四条规则 — 在真实设备上测试后台任务。模拟器和仿真器不会重现实际的后台工作限制。在 iOS 中,在 Xcode 中使用 Debug → Simulate Background Fetch。在 Android 中 — adb shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED 用于测试重启后的 WorkManager。在低电量设备上的真实测试 可发现大多数后台工作问题。
import UIKit
final class BackgroundTaskManager {
static let shared = BackgroundTaskManager()
private var tasks: [String: UIBackgroundTaskIdentifier] = [:]
func startTask(name: String, expiration: @escaping () -> Void) {
let remaining = UIApplication.shared.backgroundTimeRemaining
print("后台剩余时间:\(remaining) 秒")
let task = UIApplication.shared.beginBackgroundTask { [weak self] in
print("任务时间已到:\(name)")
expiration()
self?.endTask(name: name)
}
tasks[name] = task
}
func endTask(name: String) {
guard let task = tasks.removeValue(forKey: name),
task != .invalid
else { return }
UIApplication.shared.endBackgroundTask(task)
}
}代码展示了一个后台任务管理器,用于跟踪剩余时间和管理标识符。backgroundTimeRemaining 返回强制终止前的秒数 — 如果值为无限,则应用程序无限制地工作(音频、导航)。该管理器允许使用不同名称启动多个后台任务并正确结束每个任务。这种方法可以防止后台任务泄漏,并保证系统不会因未关闭的任务而终止应用程序。
常见问题
可以,对于有限数量的类别:音频(AVAudioSession 类别 .playback)、VoIP(PushKit)、导航(CLLocationManager 带有 allowsBackgroundLocationUpdates)、蓝牙(中央后台模式)、后台更新(BGTaskScheduler)。对于所有其他类别 — 最多 30 秒。在 iOS 16+ 中,Apple 甚至对允许的类别也收紧了要求。
beginBackgroundTask — 同步 API,用于在进入后台后将应用程序的生命周期延长约 30 秒。在 applicationDidEnterBackground 中调用。BGTaskScheduler — 异步 API,用于通过系统触发器(时间、位置、内容更新)计划将来的任务。BGTaskScheduler 是 Apple 为 iOS 13+ 推荐的现代方法。
从 Android 8(API 26)开始,Background Service 在应用程序进入后台几分钟后被终止。解决方案:对于长时间操作使用带有通知的 Foreground Service,对于延迟任务使用 WorkManager。在设置中检查您应用的 Battery Optimization — 如果已优化,系统可能会延迟或取消后台任务。
按 Cmd+Shift+H 返回主屏幕。在 Xcode 中使用 Debug → Simulate Background Fetch。要检查 beginBackgroundTask,打开控制台(Shift+Cmd+C)并调用 e UIApplication.shared.backgroundTimeRemaining。在 Xcode 15+ 中,模拟器的 Diagnostics 选项卡中提供了 Background Execution 场景。
Process Death — 在资源不足或后台不活动时,Android 系统终止进程。与 iOS 不同,Android 没有 Suspended — 进程要么存活(可以在后台),要么死亡(Not Running)。Process Death 是操作系统的正常行为,应用程序应通过 SavedStateHandle、onSaveInstanceState 或 DataStore 正确恢复状态。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。