import dayjs from 'dayjs'; import type { HealthActivitySummary, HealthKitPermissions } from 'react-native-health'; import AppleHealthKit from 'react-native-health'; const PERMISSIONS: HealthKitPermissions = { permissions: { read: [ AppleHealthKit.Constants.Permissions.StepCount, AppleHealthKit.Constants.Permissions.ActiveEnergyBurned, AppleHealthKit.Constants.Permissions.SleepAnalysis, AppleHealthKit.Constants.Permissions.HeartRateVariability, AppleHealthKit.Constants.Permissions.ActivitySummary, ], write: [ // 支持体重写入 AppleHealthKit.Constants.Permissions.Weight, ], }, }; export type TodayHealthData = { steps: number; activeEnergyBurned: number; // kilocalories sleepDuration: number; // 睡眠时长(分钟) hrv: number | null; // 心率变异性 (ms) // 健身圆环数据 activeCalories: number; activeCaloriesGoal: number; exerciseMinutes: number; exerciseMinutesGoal: number; standHours: number; standHoursGoal: number; }; export async function ensureHealthPermissions(): Promise { return new Promise((resolve) => { console.log('开始初始化HealthKit...'); AppleHealthKit.initHealthKit(PERMISSIONS, (error) => { if (error) { console.error('HealthKit初始化失败:', error); // 常见错误处理 if (typeof error === 'string') { if (error.includes('not available')) { console.warn('HealthKit不可用 - 可能在模拟器上运行或非iOS设备'); } } resolve(false); return; } console.log('HealthKit初始化成功'); resolve(true); }); }); } export async function fetchHealthDataForDate(date: Date): Promise { console.log('开始获取指定日期健康数据...', date); const start = dayjs(date).startOf('day').toDate(); const end = dayjs(date).endOf('day').toDate(); const options = { startDate: start.toISOString(), endDate: end.toISOString() } as any; const activitySummaryOptions = { startDate: start.toISOString(), endDate: end.toISOString() }; console.log('查询选项:', options); // 并行获取所有健康数据,包括ActivitySummary const [steps, calories, sleepDuration, hrv, activitySummary] = await Promise.all([ // 获取步数 new Promise((resolve) => { AppleHealthKit.getStepCount({ date: dayjs(date).toISOString() }, (err, res) => { if (err) { console.error('获取步数失败:', err); return resolve(0); } if (!res) { console.warn('步数数据为空'); return resolve(0); } console.log('步数数据:', res); resolve(res.value || 0); }); }), // 获取消耗卡路里 new Promise((resolve) => { AppleHealthKit.getActiveEnergyBurned(options, (err, res) => { if (err) { console.error('获取消耗卡路里失败:', err); return resolve(0); } if (!res || !Array.isArray(res) || res.length === 0) { console.warn('卡路里数据为空或格式错误'); return resolve(0); } console.log('卡路里数据:', res); // 求和该日内的所有记录(单位:千卡) const total = res.reduce((acc: number, item: any) => acc + (item?.value || 0), 0); resolve(total); }); }), // 获取睡眠时长 new Promise((resolve) => { AppleHealthKit.getSleepSamples(options, (err, res) => { if (err) { console.error('获取睡眠数据失败:', err); return resolve(0); } if (!res || !Array.isArray(res) || res.length === 0) { console.warn('睡眠数据为空或格式错误'); return resolve(0); } console.log('睡眠数据:', res); // 计算总睡眠时间(单位:分钟) let totalSleepDuration = 0; res.forEach((sample: any) => { if (sample && sample.startDate && sample.endDate) { const startTime = new Date(sample.startDate).getTime(); const endTime = new Date(sample.endDate).getTime(); const durationMinutes = (endTime - startTime) / (1000 * 60); totalSleepDuration += durationMinutes; } }); resolve(totalSleepDuration); }); }), // 获取HRV数据 new Promise((resolve) => { AppleHealthKit.getHeartRateVariabilitySamples(options, (err, res) => { if (err) { console.error('获取HRV数据失败:', err); return resolve(null); } if (!res || !Array.isArray(res) || res.length === 0) { console.warn('HRV数据为空或格式错误'); return resolve(null); } console.log('HRV数据:', res); // 获取最新的HRV值 const latestHrv = res[res.length - 1]; if (latestHrv && latestHrv.value) { resolve(Math.round(latestHrv.value * 1000)); } else { resolve(null); } }); }), // 获取ActivitySummary数据(健身圆环数据) new Promise((resolve) => { AppleHealthKit.getActivitySummary( activitySummaryOptions, (err: Object, results: HealthActivitySummary[]) => { if (err) { console.error('获取ActivitySummary失败:', err); return resolve(null); } if (!results || results.length === 0) { console.warn('ActivitySummary数据为空'); return resolve(null); } console.log('ActivitySummary数据:', results[0]); resolve(results[0]); }, ); }) ]); console.log('指定日期健康数据获取完成:', { steps, calories, sleepDuration, hrv, activitySummary }); return { steps, activeEnergyBurned: calories, sleepDuration, hrv, // 健身圆环数据 activeCalories: activitySummary?.activeEnergyBurned || 0, activeCaloriesGoal: activitySummary?.activeEnergyBurnedGoal || 350, exerciseMinutes: activitySummary?.appleExerciseTime || 0, exerciseMinutesGoal: activitySummary?.appleExerciseTimeGoal || 30, standHours: activitySummary?.appleStandHours || 0, standHoursGoal: activitySummary?.appleStandHoursGoal || 12 }; } export async function fetchTodayHealthData(): Promise { return fetchHealthDataForDate(new Date()); } // 新增:专门获取HRV数据的函数 export async function fetchHRVForDate(date: Date): Promise { console.log('开始获取指定日期HRV数据...', date); const start = new Date(date); start.setHours(0, 0, 0, 0); const end = new Date(date); end.setHours(23, 59, 59, 999); const options = { startDate: start.toISOString(), endDate: end.toISOString() } as any; return new Promise((resolve) => { AppleHealthKit.getHeartRateVariabilitySamples(options, (err, res) => { if (err) { console.error('获取HRV数据失败:', err); return resolve(null); } if (!res || !Array.isArray(res) || res.length === 0) { console.warn('HRV数据为空或格式错误'); return resolve(null); } console.log('HRV数据:', res); // 获取最新的HRV值 const latestHrv = res[res.length - 1]; if (latestHrv && latestHrv.value) { resolve(latestHrv.value); } else { resolve(null); } }); }); } // 新增:获取今日HRV数据 export async function fetchTodayHRV(): Promise { return fetchHRVForDate(new Date()); } // 更新healthkit中的体重 export async function updateWeight(weight: number) { return new Promise((resolve) => { AppleHealthKit.saveWeight({ value: weight, }, (err, res) => { if (err) { console.error('更新体重失败:', err); return resolve(false); } console.log('体重更新成功:', res); resolve(true); }); }); }