Files
digital-pilates/utils/health.ts

196 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { 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,
],
write: [],
},
};
export type TodayHealthData = {
steps: number;
activeEnergyBurned: number; // kilocalories
sleepDuration: number; // 睡眠时长(分钟)
hrv: number | null; // 心率变异性 (ms)
};
export async function ensureHealthPermissions(): Promise<boolean> {
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<TodayHealthData> {
console.log('开始获取指定日期健康数据...', 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;
console.log('查询选项:', options);
// 并行获取所有健康数据
const [steps, calories, sleepDuration, hrv] = await Promise.all([
// 获取步数
new Promise<number>((resolve) => {
AppleHealthKit.getStepCount(options, (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<number>((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<number>((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<number | null>((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);
}
});
})
]);
console.log('指定日期健康数据获取完成:', { steps, calories, sleepDuration, hrv });
return { steps, activeEnergyBurned: calories, sleepDuration, hrv };
}
export async function fetchTodayHealthData(): Promise<TodayHealthData> {
return fetchHealthDataForDate(new Date());
}
// 新增专门获取HRV数据的函数
export async function fetchHRVForDate(date: Date): Promise<number | null> {
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<number | null>((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<number | null> {
return fetchHRVForDate(new Date());
}