后台任务 #
一、后台任务概述 #
1.1 后台任务类型 #
| 类型 | 说明 | 平台 |
|---|---|---|
| 后台执行 | 应用进入后台时执行 | iOS/Android |
| 定时任务 | 定期执行任务 | iOS/Android |
| 后台同步 | 后台数据同步 | iOS/Android |
| 后台下载 | 后台文件下载 | iOS/Android |
1.2 平台限制 #
| 平台 | 限制 |
|---|---|
| iOS | 约30秒后台执行时间 |
| Android | 根据系统版本不同 |
二、应用生命周期处理 #
2.1 监听应用状态 #
typescript
import { App, AppState } from '@capacitor/app';
// 监听应用状态变化
App.addListener('appStateChange', ({ isActive }) => {
if (isActive) {
console.log('应用进入前台');
onAppResume();
} else {
console.log('应用进入后台');
onAppPause();
}
});
function onAppPause() {
// 保存状态
saveAppState();
// 启动后台任务
startBackgroundTasks();
}
function onAppResume() {
// 恢复状态
restoreAppState();
// 检查后台任务结果
checkBackgroundTaskResults();
}
2.2 后台任务管理器 #
typescript
// src/services/background-task.service.ts
import { App } from '@capacitor/app';
import { Preferences } from '@capacitor/preferences';
type BackgroundTask = () => Promise<void>;
class BackgroundTaskManager {
private tasks: Map<string, BackgroundTask> = new Map();
private results: Map<string, any> = new Map();
constructor() {
this.init();
}
private init() {
App.addListener('appStateChange', async ({ isActive }) => {
if (!isActive) {
await this.executeTasks();
}
});
}
register(name: string, task: BackgroundTask): void {
this.tasks.set(name, task);
}
unregister(name: string): void {
this.tasks.delete(name);
}
private async executeTasks(): Promise<void> {
const results: Record<string, any> = {};
for (const [name, task] of this.tasks) {
try {
await task();
results[name] = { success: true };
} catch (error) {
results[name] = {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
// 保存结果
await Preferences.set({
key: 'background_task_results',
value: JSON.stringify({
timestamp: Date.now(),
results
})
});
}
async getResults(): Promise<Record<string, any> | null> {
const { value } = await Preferences.get({
key: 'background_task_results'
});
if (!value) return null;
const data = JSON.parse(value);
// 清除旧结果
await Preferences.remove({
key: 'background_task_results'
});
return data;
}
}
export const backgroundTaskManager = new BackgroundTaskManager();
2.3 使用示例 #
typescript
// 注册后台任务
backgroundTaskManager.register('sync-data', async () => {
// 同步数据到服务器
await syncDataToServer();
});
backgroundTaskManager.register('save-cache', async () => {
// 保存缓存
await saveCache();
});
// 检查结果
const results = await backgroundTaskManager.getResults();
if (results) {
console.log('Background task results:', results);
}
三、iOS后台任务 #
3.1 配置后台模式 #
xml
<!-- ios/App/App/Info.plist -->
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>remote-notification</string>
</array>
3.2 后台获取 (Background Fetch) #
swift
// ios/App/App/AppDelegate.swift
import UIKit
import Capacitor
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 设置后台获取间隔
application.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
return true
}
func application(_ application: UIApplication,
performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// 执行后台获取
performBackgroundFetch { result in
completionHandler(result)
}
}
private func performBackgroundFetch(completion: @escaping (UIBackgroundFetchResult) -> Void) {
// 获取新数据
URLSession.shared.dataTask(with: URL(string: "https://api.example.com/data")!) { data, response, error in
if let error = error {
print("Background fetch error: \(error)")
completion(.failed)
return
}
if let data = data {
// 处理数据
self.processNewData(data)
completion(.newData)
} else {
completion(.noData)
}
}.resume()
}
private func processNewData(_ data: Data) {
// 处理获取的数据
}
}
3.3 后台处理任务 (BGProcessingTask) #
swift
import BackgroundTasks
class BackgroundTaskScheduler {
static let shared = BackgroundTaskScheduler()
private let processingTaskIdentifier = "com.company.myapp.processing"
func registerTasks() {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: processingTaskIdentifier,
using: nil
) { task in
self.handleProcessingTask(task: task as! BGProcessingTask)
}
}
func scheduleProcessingTask() {
let request = BGProcessingTaskRequest(identifier: processingTaskIdentifier)
request.requiresNetworkConnectivity = true
request.earliestBeginDate = Date(timeIntervalSinceNow: 3600) // 1小时后
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule task: \(error)")
}
}
private func handleProcessingTask(task: BGProcessingTask) {
// 设置过期处理
task.expirationHandler = {
task.setTaskCompleted(success: false)
}
// 执行任务
performProcessing { success in
task.setTaskCompleted(success: success)
}
}
private func performProcessing(completion: @escaping (Bool) -> Void) {
// 执行后台处理
completion(true)
}
}
四、Android后台任务 #
4.1 使用WorkManager #
groovy
// android/app/build.gradle
dependencies {
implementation "androidx.work:work-runtime:2.8.0"
}
4.2 创建Worker #
java
// android/app/src/main/java/com/company/app/workers/SyncWorker.java
package com.company.app.workers;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class SyncWorker extends Worker {
public SyncWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
try {
// 执行同步任务
String result = syncData();
// 返回成功
return Result.success();
} catch (Exception e) {
// 返回失败,可以设置重试
return Result.retry();
}
}
private String syncData() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.example.com/sync")
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
}
4.3 调度任务 #
java
// android/app/src/main/java/com/company/app/MainActivity.java
package com.company.app;
import android.os.Bundle;
import androidx.work.Constraints;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import com.company.app.workers.SyncWorker;
import com.getcapacitor.BridgeActivity;
import java.util.concurrent.TimeUnit;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 调度后台任务
scheduleBackgroundSync();
}
private void scheduleBackgroundSync() {
// 设置约束条件
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build();
// 创建周期性任务
PeriodicWorkRequest syncWork = new PeriodicWorkRequest.Builder(
SyncWorker.class,
1, // 每1小时
TimeUnit.HOURS
)
.setConstraints(constraints)
.build();
// 提交任务
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sync_work",
ExistingPeriodicWorkPolicy.KEEP,
syncWork
);
}
}
4.4 Kotlin实现 #
kotlin
// SyncWorker.kt
package com.company.app.workers
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import okhttp3.OkHttpClient
import okhttp3.Request
class SyncWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
return try {
syncData()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
private fun syncData() {
val client = OkHttpClient()
val request = Request.Builder()
.url("https://api.example.com/sync")
.build()
client.newCall(request).execute().use { response ->
// 处理响应
}
}
}
五、后台下载 #
5.1 iOS后台下载 #
swift
import UIKit
class BackgroundDownloadManager: NSObject, URLSessionDownloadDelegate {
private var session: URLSession!
override init() {
super.init()
let config = URLSessionConfiguration.background(withIdentifier: "com.company.myapp.download")
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
}
func startDownload(url: URL) {
let task = session.downloadTask(with: url)
task.resume()
}
func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL) {
// 下载完成
do {
let documents = try FileManager.default.url(
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false
)
let destination = documents.appendingPathComponent(downloadTask.originalRequest?.url?.lastPathComponent ?? "file")
try FileManager.default.moveItem(at: location, to: destination)
} catch {
print("Error moving file: \(error)")
}
}
func urlSession(_ session: URLSession,
task: URLSessionTask,
didCompleteWithError error: Error?) {
if let error = error {
print("Download error: \(error)")
}
}
}
5.2 Android后台下载 #
java
// 使用WorkManager下载
public class DownloadWorker extends Worker {
public DownloadWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
String url = getInputData().getString("url");
String fileName = getInputData().getString("fileName");
try {
downloadFile(url, fileName);
return Result.success();
} catch (Exception e) {
return Result.failure();
}
}
private void downloadFile(String url, String fileName) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Download failed: " + response);
}
InputStream input = response.body().byteStream();
File output = new File(getApplicationContext().getFilesDir(), fileName);
try (FileOutputStream fos = new FileOutputStream(output)) {
byte[] buffer = new byte[8192];
int len;
while ((len = input.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
}
}
}
}
六、最佳实践 #
6.1 任务优先级 #
typescript
// 根据重要性排序任务
const tasks = [
{ name: 'sync-critical', priority: 1, task: syncCriticalData },
{ name: 'sync-normal', priority: 2, task: syncNormalData },
{ name: 'cleanup', priority: 3, task: cleanupCache }
];
tasks.sort((a, b) => a.priority - b.priority);
for (const { task } of tasks) {
await task();
}
6.2 错误处理 #
typescript
async function executeWithErrorHandling(task: () => Promise<void>, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
await task();
return;
} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error);
if (i === retries - 1) {
throw error;
}
// 等待后重试
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
6.3 资源管理 #
typescript
// 限制后台任务执行时间
async function executeWithTimeout(task: () => Promise<void>, timeout: number) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Task timeout')), timeout);
});
try {
await Promise.race([task(), timeoutPromise]);
} catch (error) {
console.error('Background task error:', error);
}
}
七、总结 #
7.1 后台任务要点 #
| 要点 | 说明 |
|---|---|
| 时间限制 | 注意平台后台执行时间限制 |
| 错误处理 | 完善的错误处理和重试机制 |
| 资源管理 | 合理使用系统资源 |
| 状态保存 | 保存任务状态和结果 |
7.2 下一步 #
了解后台任务后,让我们学习 安全最佳实践!
最后更新:2026-03-28