# 方案总结
基于提供的 Git diff,我将生成以下 conventional commit message: ## 变更分析: 1. **核心功能**: - 新增睡眠监控服务(`services/sleepMonitor.ts`) - 新增睡眠通知服务(`services/sleepNotificationService.ts`) - iOS 原生端增加睡眠观察者方法 2. **应用启动优化**: - 重构 `app/_layout.tsx` 中的初始化流程,按优先级分阶段加载服务 3. **药品功能改进**: - 优化语音识别交互(实时预览、可取消) - Widget 增加 URL scheme 支持 4. **路由配置**: - 新增药品管理路由常量 ## 提交信息类型: - **主类型**:`feat` (新增睡眠监控功能) - **作用域**:`health` (健康相关功能) --- 请确认方案后,我将生成最终的 commit message。 --- **最终 Commit Message:** feat(health): 添加睡眠监控和通知服务,优化应用启动流程 - 新增睡眠监控服务,支持实时监听 HealthKit 睡眠数据更新 - 实现睡眠质量分析算法,计算睡眠评分和各阶段占比 - 新增睡眠通知服务,分析完成后自动推送质量评估和建议 - iOS 原生端实现睡眠数据观察者,支持后台数据传递 - 重构应用启动初始化流程,按优先级分阶段加载服务(关键/次要/后台/空闲) - 优化药品录入页面语音识别交互,支持实时预览和取消操作 - 药品 Widget 增加 deeplink 支持,点击跳转到应用 - 新增药品管理路由常量配置
This commit is contained in:
@@ -89,4 +89,11 @@ RCT_EXTERN_METHOD(startWorkoutObserver:(RCTPromiseResolveBlock)resolver
|
||||
RCT_EXTERN_METHOD(stopWorkoutObserver:(RCTPromiseResolveBlock)resolver
|
||||
rejecter:(RCTPromiseRejectBlock)rejecter)
|
||||
|
||||
// Sleep Observer Methods
|
||||
RCT_EXTERN_METHOD(startSleepObserver:(RCTPromiseResolveBlock)resolver
|
||||
rejecter:(RCTPromiseRejectBlock)rejecter)
|
||||
|
||||
RCT_EXTERN_METHOD(stopSleepObserver:(RCTPromiseResolveBlock)resolver
|
||||
rejecter:(RCTPromiseRejectBlock)rejecter)
|
||||
|
||||
@end
|
||||
@@ -1700,9 +1700,10 @@ class HealthKitManager: RCTEventEmitter {
|
||||
return description.lowercased()
|
||||
}
|
||||
|
||||
// MARK: - Workout Observer Methods
|
||||
// MARK: - Observer Methods
|
||||
|
||||
private var workoutObserverQuery: HKObserverQuery?
|
||||
private var sleepObserverQuery: HKObserverQuery?
|
||||
|
||||
@objc
|
||||
func startWorkoutObserver(
|
||||
@@ -1781,10 +1782,89 @@ private func sendWorkoutUpdateEvent() {
|
||||
])
|
||||
}
|
||||
|
||||
// MARK: - Sleep Observer Methods
|
||||
|
||||
@objc
|
||||
func startSleepObserver(
|
||||
_ resolver: @escaping RCTPromiseResolveBlock,
|
||||
rejecter: @escaping RCTPromiseRejectBlock
|
||||
) {
|
||||
guard HKHealthStore.isHealthDataAvailable() else {
|
||||
rejecter("HEALTHKIT_NOT_AVAILABLE", "HealthKit is not available on this device", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已经有观察者在运行,先停止它
|
||||
if let existingQuery = sleepObserverQuery {
|
||||
healthStore.stop(existingQuery)
|
||||
sleepObserverQuery = nil
|
||||
}
|
||||
|
||||
// 创建睡眠数据观察者
|
||||
let sleepType = ReadTypes.sleep
|
||||
|
||||
sleepObserverQuery = HKObserverQuery(sampleType: sleepType, predicate: nil) { [weak self] (query, completionHandler, error) in
|
||||
if let error = error {
|
||||
print("Sleep observer error: \(error.localizedDescription)")
|
||||
completionHandler()
|
||||
return
|
||||
}
|
||||
|
||||
print("Sleep data updated, sending event to React Native")
|
||||
// 发送简单的更新事件到 React Native,让 RN 层处理数据分析
|
||||
self?.sendSleepUpdateEvent()
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
// 启用后台传递
|
||||
healthStore.enableBackgroundDelivery(for: sleepType, frequency: .immediate) { (success, error) in
|
||||
if let error = error {
|
||||
print("Failed to enable background delivery for sleep: \(error.localizedDescription)")
|
||||
} else {
|
||||
print("Background delivery for sleep enabled successfully")
|
||||
}
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
healthStore.execute(sleepObserverQuery!)
|
||||
|
||||
resolver(["success": true])
|
||||
}
|
||||
|
||||
@objc
|
||||
func stopSleepObserver(
|
||||
_ resolver: @escaping RCTPromiseResolveBlock,
|
||||
rejecter: @escaping RCTPromiseRejectBlock
|
||||
) {
|
||||
if let query = sleepObserverQuery {
|
||||
healthStore.stop(query)
|
||||
sleepObserverQuery = nil
|
||||
|
||||
// 禁用后台传递
|
||||
healthStore.disableBackgroundDelivery(for: ReadTypes.sleep) { (success, error) in
|
||||
if let error = error {
|
||||
print("Failed to disable background delivery for sleep: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
resolver(["success": true])
|
||||
} else {
|
||||
resolver(["success": true]) // 即使没有查询在运行也返回成功
|
||||
}
|
||||
}
|
||||
|
||||
/// 发送睡眠更新事件到 React Native(简单通知,不包含分析数据)
|
||||
private func sendSleepUpdateEvent() {
|
||||
sendEvent(withName: "sleepUpdate", body: [
|
||||
"timestamp": Date().timeIntervalSince1970,
|
||||
"type": "sleep_data_updated"
|
||||
])
|
||||
}
|
||||
|
||||
// MARK: - RCTEventEmitter Overrides
|
||||
|
||||
override func supportedEvents() -> [String]! {
|
||||
return ["workoutUpdate"]
|
||||
return ["workoutUpdate", "sleepUpdate"]
|
||||
}
|
||||
|
||||
override static func requiresMainQueueSetup() -> Bool {
|
||||
|
||||
@@ -105,6 +105,7 @@ struct medicineEntryView: View {
|
||||
.foregroundColor(Color.secondary)
|
||||
}
|
||||
.padding()
|
||||
.widgetURL(URL(string: "digitalpilates://medications"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,10 +175,11 @@ struct medicine: Widget {
|
||||
var body: some WidgetConfiguration {
|
||||
AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in
|
||||
medicineEntryView(entry: entry)
|
||||
.containerBackground(.fill.tertiary, for: .widget)
|
||||
.containerBackground(.white, for: .widget)
|
||||
}
|
||||
.configurationDisplayName("用药计划")
|
||||
.description("显示今日用药计划和服药状态")
|
||||
.supportedFamilies([.systemSmall, .systemMedium])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user