- 新增iOS原生BackgroundTaskBridge桥接模块,支持后台任务注册、调度和完成 - 重构BackgroundTaskManager为V2版本,集成原生iOS后台任务能力 - 在AppDelegate中注册后台任务处理器,确保应用启动时正确初始化 - 重构锻炼通知消息生成逻辑,使用配置化模板提升可维护性 - 扩展健康数据类型映射,支持更多运动项目的中文显示 - 替换原有backgroundTaskManager引用为backgroundTaskManagerV2
124 lines
4.1 KiB
Swift
124 lines
4.1 KiB
Swift
import Expo
|
||
import React
|
||
import ReactAppDependencyProvider
|
||
import BackgroundTasks
|
||
|
||
@UIApplicationMain
|
||
public class AppDelegate: ExpoAppDelegate {
|
||
var window: UIWindow?
|
||
|
||
var reactNativeDelegate: ExpoReactNativeFactoryDelegate?
|
||
var reactNativeFactory: RCTReactNativeFactory?
|
||
|
||
public override func application(
|
||
_ application: UIApplication,
|
||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
||
) -> Bool {
|
||
// 在应用启动完成前注册后台任务
|
||
if #available(iOS 13.0, *) {
|
||
registerBackgroundTasks()
|
||
}
|
||
|
||
let delegate = ReactNativeDelegate()
|
||
let factory = ExpoReactNativeFactory(delegate: delegate)
|
||
delegate.dependencyProvider = RCTAppDependencyProvider()
|
||
|
||
reactNativeDelegate = delegate
|
||
reactNativeFactory = factory
|
||
bindReactNativeFactory(factory)
|
||
|
||
#if os(iOS) || os(tvOS)
|
||
window = UIWindow(frame: UIScreen.main.bounds)
|
||
factory.startReactNative(
|
||
withModuleName: "main",
|
||
in: window,
|
||
launchOptions: launchOptions)
|
||
#endif
|
||
|
||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||
}
|
||
|
||
// MARK: - Background Task Registration
|
||
|
||
@available(iOS 13.0, *)
|
||
private func registerBackgroundTasks() {
|
||
let identifier = "com.anonymous.digitalpilates.task"
|
||
|
||
// 注册后台任务处理器
|
||
// 必须在应用启动完成前注册,否则会崩溃
|
||
BGTaskScheduler.shared.register(
|
||
forTaskWithIdentifier: identifier,
|
||
using: nil
|
||
) { [weak self] task in
|
||
// 尝试通知 BackgroundTaskBridge 处理任务
|
||
// 如果 bridge 不可用,标记任务完成
|
||
self?.handleBackgroundTask(task, identifier: identifier)
|
||
}
|
||
|
||
NSLog("[AppDelegate] 后台任务已在应用启动时注册: \(identifier)")
|
||
}
|
||
|
||
@available(iOS 13.0, *)
|
||
private func handleBackgroundTask(_ task: BGTask, identifier: String) {
|
||
// 尝试获取 BackgroundTaskBridge 实例来处理任务
|
||
// 如果 React Native bridge 还未初始化,则直接完成任务
|
||
guard let bridge = reactNativeFactory?.bridge,
|
||
bridge.isValid else {
|
||
NSLog("[AppDelegate] React Native bridge 未就绪,直接完成后台任务")
|
||
task.setTaskCompleted(success: false)
|
||
return
|
||
}
|
||
|
||
// 通过 bridge 查找 BackgroundTaskBridge 模块
|
||
DispatchQueue.main.async {
|
||
if let module = bridge.module(for: BackgroundTaskBridge.self) as? BackgroundTaskBridge {
|
||
// 通知 BackgroundTaskBridge 处理任务
|
||
NotificationCenter.default.post(
|
||
name: NSNotification.Name("BackgroundTaskBridge.handleTask"),
|
||
object: nil,
|
||
userInfo: ["task": task, "identifier": identifier]
|
||
)
|
||
} else {
|
||
NSLog("[AppDelegate] BackgroundTaskBridge 模块未找到,完成后台任务")
|
||
task.setTaskCompleted(success: false)
|
||
}
|
||
}
|
||
}
|
||
|
||
// Linking API
|
||
public override func application(
|
||
_ app: UIApplication,
|
||
open url: URL,
|
||
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
|
||
) -> Bool {
|
||
return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)
|
||
}
|
||
|
||
// Universal Links
|
||
public override func application(
|
||
_ application: UIApplication,
|
||
continue userActivity: NSUserActivity,
|
||
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
|
||
) -> Bool {
|
||
let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||
return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result
|
||
}
|
||
}
|
||
|
||
class ReactNativeDelegate: ExpoReactNativeFactoryDelegate {
|
||
// Extension point for config-plugins
|
||
|
||
override func sourceURL(for bridge: RCTBridge) -> URL? {
|
||
// needed to return the correct URL for expo-dev-client.
|
||
bridge.bundleURL ?? bundleURL()
|
||
}
|
||
|
||
override func bundleURL() -> URL? {
|
||
#if DEBUG
|
||
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry")
|
||
#else
|
||
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
|
||
#endif
|
||
}
|
||
}
|