1. 在SwiftUI中发起后台任务请求
- 配置权限:
- 在
Info.plist
文件中添加UIBackgroundModes
键,并包含fetch
值,以声明应用支持后台获取。
- 设置后台任务调度:
- 在AppDelegate中配置后台任务。例如,在
SceneDelegate.swift
或AppDelegate.swift
中:
import UIKit
import UserNotifications
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// 配置后台任务
let backgroundTaskScheduler = BGTaskScheduler.shared
backgroundTaskScheduler.register(forTaskWithIdentifier: "com.example.fetchDataTask", using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
}
}
func handleAppRefresh(task: BGAppRefreshTask) {
// 执行数据获取逻辑
let semaphore = DispatchSemaphore(value: 0)
let url = URL(string: "https://example.com/api/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// 处理数据
if let data = data {
// 保存数据等操作
}
semaphore.signal()
}
task.resume()
semaphore.wait()
task.expirationHandler = {
task.cancel()
}
task.setTaskDescription("Fetching data in background")
task.earliestBeginDate = Date(timeIntervalSinceNow: 30)
task.setTaskDescription("Fetching data in background")
task.earliestBeginDate = Date(timeIntervalSinceNow: 30)
task.expirationHandler = {
task.cancel()
}
task.resume()
}
}
- 触发后台任务:
- 在合适的时机触发后台任务,例如在应用启动时或根据业务逻辑:
let backgroundTaskScheduler = BGTaskScheduler.shared
let request = BGAppRefreshTaskRequest(identifier: "com.example.fetchDataTask")
request.earliestBeginDate = Date(timeIntervalSinceNow: 0)
do {
try backgroundTaskScheduler.submit(request)
} catch {
print("Could not submit background task: \(error)")
}
2. 后台任务完成后将新数据传递给Widget进行更新
- 数据存储:
- 后台任务获取到数据后,将数据存储在合适的地方,如
UserDefaults
、Core Data
或文件系统。例如,使用UserDefaults
:
if let data = data {
UserDefaults.standard.set(data, forKey: "newData")
}
- Widget更新:
- 在Widget的
TimelineProvider
中监听数据变化并更新Widget内容。例如:
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), data: nil)
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date(), data: UserDefaults.standard.data(forKey: "newData"))
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
var entries: [SimpleEntry] = []
let currentDate = Date()
for _ in 0..<5 {
let entryDate = Calendar.current.date(byAdding:.minute, value: 1, to: currentDate)!
let entry = SimpleEntry(date: entryDate, data: UserDefaults.standard.data(forKey: "newData"))
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy:.atEnd)
completion(timeline)
}
}
- Widget刷新:
- 可以通过
WidgetCenter.shared.reloadAllTimelines()
方法在数据更新后通知WidgetKit重新加载时间线,以显示新数据。例如,在后台任务完成数据存储后:
import WidgetKit
WidgetCenter.shared.reloadAllTimelines()