后台任务 #

一、后台任务概述 #

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