- 重构权限管理,新增SimpleEventEmitter实现状态监听 - 实现完整的健身圆环数据获取(活动热量、锻炼时间、站立小时) - 优化组件状态管理,支持实时数据刷新和权限状态响应 - 新增useHealthPermissions Hook,简化权限状态管理 - 完善iOS原生代码,支持按小时统计健身数据 - 优化应用启动时权限初始化流程,避免启动弹窗 BREAKING CHANGE: FitnessRingsCard组件API变更,移除手动传参改为自动获取数据
236 lines
7.3 KiB
TypeScript
236 lines
7.3 KiB
TypeScript
import { useState, useEffect, useCallback, useRef } from 'react';
|
||
import {
|
||
healthPermissionManager,
|
||
HealthPermissionStatus,
|
||
ensureHealthPermissions,
|
||
checkHealthPermissionStatus,
|
||
fetchTodayHealthData,
|
||
fetchHealthDataForDate,
|
||
TodayHealthData
|
||
} from '@/utils/health';
|
||
|
||
export interface UseHealthPermissionsReturn {
|
||
// 权限状态
|
||
permissionStatus: HealthPermissionStatus;
|
||
isLoading: boolean;
|
||
|
||
// 权限操作
|
||
requestPermissions: () => Promise<boolean>;
|
||
checkPermissions: (forceCheck?: boolean) => Promise<HealthPermissionStatus>;
|
||
|
||
// 数据刷新
|
||
refreshHealthData: () => Promise<void>;
|
||
refreshHealthDataForDate: (date: Date) => Promise<void>;
|
||
|
||
// 健康数据
|
||
healthData: TodayHealthData | null;
|
||
|
||
// 状态检查
|
||
hasPermission: boolean;
|
||
needsPermission: boolean;
|
||
}
|
||
|
||
/**
|
||
* HealthKit权限状态管理Hook
|
||
*
|
||
* 功能:
|
||
* 1. 监听权限状态变化
|
||
* 2. 自动刷新数据当权限状态改变时
|
||
* 3. 提供权限请求和数据刷新方法
|
||
* 4. 缓存健康数据状态
|
||
*/
|
||
export function useHealthPermissions(): UseHealthPermissionsReturn {
|
||
const [permissionStatus, setPermissionStatus] = useState<HealthPermissionStatus>(
|
||
healthPermissionManager.getPermissionStatus()
|
||
);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const [healthData, setHealthData] = useState<TodayHealthData | null>(null);
|
||
|
||
// 使用ref避免闭包问题
|
||
const isLoadingRef = useRef(false);
|
||
const lastRefreshTime = useRef(0);
|
||
const refreshThrottle = 2000; // 2秒内避免重复刷新
|
||
|
||
// 刷新健康数据
|
||
const refreshHealthData = useCallback(async () => {
|
||
const now = Date.now();
|
||
|
||
// 防抖:避免短时间内重复刷新
|
||
if (isLoadingRef.current || (now - lastRefreshTime.current) < refreshThrottle) {
|
||
console.log('健康数据刷新被节流,跳过本次刷新');
|
||
return;
|
||
}
|
||
|
||
if (permissionStatus !== HealthPermissionStatus.Authorized) {
|
||
console.log('没有HealthKit权限,跳过数据刷新');
|
||
return;
|
||
}
|
||
|
||
isLoadingRef.current = true;
|
||
setIsLoading(true);
|
||
lastRefreshTime.current = now;
|
||
|
||
try {
|
||
console.log('开始刷新今日健康数据...');
|
||
const data = await fetchTodayHealthData();
|
||
setHealthData(data);
|
||
console.log('健康数据刷新成功:', data);
|
||
} catch (error) {
|
||
console.error('刷新健康数据失败:', error);
|
||
} finally {
|
||
isLoadingRef.current = false;
|
||
setIsLoading(false);
|
||
}
|
||
}, [permissionStatus]);
|
||
|
||
// 刷新指定日期的健康数据
|
||
const refreshHealthDataForDate = useCallback(async (date: Date) => {
|
||
if (permissionStatus !== HealthPermissionStatus.Authorized) {
|
||
console.log('没有HealthKit权限,跳过数据刷新');
|
||
return;
|
||
}
|
||
|
||
setIsLoading(true);
|
||
try {
|
||
console.log('开始刷新指定日期健康数据...', date);
|
||
const data = await fetchHealthDataForDate(date);
|
||
// 只有是今天的数据才更新state
|
||
const today = new Date();
|
||
if (date.toDateString() === today.toDateString()) {
|
||
setHealthData(data);
|
||
}
|
||
console.log('指定日期健康数据刷新成功:', data);
|
||
} catch (error) {
|
||
console.error('刷新指定日期健康数据失败:', error);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [permissionStatus]);
|
||
|
||
// 请求权限
|
||
const requestPermissions = useCallback(async (): Promise<boolean> => {
|
||
setIsLoading(true);
|
||
try {
|
||
console.log('开始请求HealthKit权限...');
|
||
const granted = await ensureHealthPermissions();
|
||
|
||
if (granted) {
|
||
console.log('权限请求成功,准备刷新数据');
|
||
// 权限获取成功后,稍微延迟刷新数据
|
||
setTimeout(() => {
|
||
refreshHealthData();
|
||
}, 500);
|
||
}
|
||
|
||
return granted;
|
||
} catch (error) {
|
||
console.error('请求HealthKit权限失败:', error);
|
||
return false;
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [refreshHealthData]);
|
||
|
||
// 检查权限状态
|
||
const checkPermissions = useCallback(async (forceCheck: boolean = false): Promise<HealthPermissionStatus> => {
|
||
try {
|
||
const status = await checkHealthPermissionStatus(forceCheck);
|
||
return status;
|
||
} catch (error) {
|
||
console.error('检查权限状态失败:', error);
|
||
return HealthPermissionStatus.Unknown;
|
||
}
|
||
}, []);
|
||
|
||
// 监听权限状态变化
|
||
useEffect(() => {
|
||
console.log('设置HealthKit权限状态监听器...');
|
||
|
||
// 权限状态变化监听
|
||
const handlePermissionStatusChanged = (newStatus: HealthPermissionStatus, oldStatus: HealthPermissionStatus) => {
|
||
console.log(`权限状态变化: ${oldStatus} -> ${newStatus}`);
|
||
setPermissionStatus(newStatus);
|
||
|
||
// 如果从无权限变为有权限,自动刷新数据
|
||
if (oldStatus !== HealthPermissionStatus.Authorized && newStatus === HealthPermissionStatus.Authorized) {
|
||
console.log('权限状态变为已授权,准备刷新健康数据...');
|
||
setTimeout(() => {
|
||
refreshHealthData();
|
||
}, 500);
|
||
}
|
||
};
|
||
|
||
// 权限获取成功监听
|
||
const handlePermissionGranted = () => {
|
||
console.log('权限获取成功事件触发,准备刷新数据...');
|
||
setTimeout(() => {
|
||
refreshHealthData();
|
||
}, 500);
|
||
};
|
||
|
||
healthPermissionManager.on('permissionStatusChanged', handlePermissionStatusChanged);
|
||
healthPermissionManager.on('permissionGranted', handlePermissionGranted);
|
||
|
||
// 组件挂载时检查一次权限状态
|
||
checkPermissions(true);
|
||
|
||
// 如果已经有权限,立即刷新数据
|
||
if (permissionStatus === HealthPermissionStatus.Authorized) {
|
||
refreshHealthData();
|
||
}
|
||
|
||
return () => {
|
||
console.log('清理HealthKit权限状态监听器...');
|
||
healthPermissionManager.off('permissionStatusChanged', handlePermissionStatusChanged);
|
||
healthPermissionManager.off('permissionGranted', handlePermissionGranted);
|
||
};
|
||
}, [checkPermissions, refreshHealthData, permissionStatus]);
|
||
|
||
// 计算派生状态
|
||
const hasPermission = permissionStatus === HealthPermissionStatus.Authorized;
|
||
const needsPermission = permissionStatus === HealthPermissionStatus.NotDetermined ||
|
||
permissionStatus === HealthPermissionStatus.Unknown;
|
||
|
||
return {
|
||
permissionStatus,
|
||
isLoading,
|
||
requestPermissions,
|
||
checkPermissions,
|
||
refreshHealthData,
|
||
refreshHealthDataForDate,
|
||
healthData,
|
||
hasPermission,
|
||
needsPermission
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 简化版Hook,只关注权限状态
|
||
*/
|
||
export function useHealthPermissionStatus() {
|
||
const [permissionStatus, setPermissionStatus] = useState<HealthPermissionStatus>(
|
||
healthPermissionManager.getPermissionStatus()
|
||
);
|
||
|
||
useEffect(() => {
|
||
const handlePermissionStatusChanged = (newStatus: HealthPermissionStatus) => {
|
||
setPermissionStatus(newStatus);
|
||
};
|
||
|
||
healthPermissionManager.on('permissionStatusChanged', handlePermissionStatusChanged);
|
||
|
||
// 检查一次当前状态
|
||
checkHealthPermissionStatus(true);
|
||
|
||
return () => {
|
||
healthPermissionManager.off('permissionStatusChanged', handlePermissionStatusChanged);
|
||
};
|
||
}, []);
|
||
|
||
return {
|
||
permissionStatus,
|
||
hasPermission: permissionStatus === HealthPermissionStatus.Authorized,
|
||
needsPermission: permissionStatus === HealthPermissionStatus.NotDetermined ||
|
||
permissionStatus === HealthPermissionStatus.Unknown
|
||
};
|
||
} |