Refactor components and enhance background task management

- Updated font sizes and weights in BasalMetabolismCard, MoodCard, HealthDataCard, and NutritionRadarCard for improved readability.
- Removed loading state from MoodCard to simplify the component.
- Adjusted styles in WeightHistoryCard for better layout and spacing.
- Integrated expo-background-fetch for improved background task handling.
- Updated Info.plist to include background fetch capability.
- Enhanced background task registration and execution logic in backgroundTaskManager.
- Added debug function to manually trigger background task execution for testing purposes.
This commit is contained in:
richarjiang
2025-09-03 16:17:29 +08:00
parent 16b4fc8816
commit 8b9689b269
17 changed files with 163 additions and 85 deletions

View File

@@ -18,7 +18,8 @@
"NSPhotoLibraryUsageDescription": "应用需要访问相册以选择您的体态照片用于AI测评。", "NSPhotoLibraryUsageDescription": "应用需要访问相册以选择您的体态照片用于AI测评。",
"NSPhotoLibraryAddUsageDescription": "应用需要写入相册以保存拍摄的体态照片(可选)。", "NSPhotoLibraryAddUsageDescription": "应用需要写入相册以保存拍摄的体态照片(可选)。",
"UIBackgroundModes": [ "UIBackgroundModes": [
"processing" "background-fetch",
"background-processing"
] ]
} }
}, },
@@ -69,7 +70,12 @@
] ]
} }
], ],
"expo-background-task" [
"expo-background-fetch",
{
"minimumInterval": 15
}
]
], ],
"experiments": { "experiments": {
"typedRoutes": true "typedRoutes": true

View File

@@ -23,6 +23,7 @@ import { useFocusEffect } from '@react-navigation/native';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import Lottie from 'lottie-react-native';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Alert, FlatList, Image, RefreshControl, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { Alert, FlatList, Image, RefreshControl, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
@@ -384,11 +385,12 @@ export default function GoalsScreen() {
borderBottomLeftRadius: 24, borderBottomLeftRadius: 24,
borderBottomRightRadius: 24, borderBottomRightRadius: 24,
}}> }}>
{/* 右下角图片 */} {/* 右下角Lottie动画 */}
<Image <Lottie
source={require('@/assets/images/task/imageTodo.png')} source={require('@/assets/lottie/Goal.json')}
style={styles.bottomRightImage} style={styles.bottomRightImage}
resizeMode="contain" autoPlay
loop
/> />
</View> </View>
@@ -716,10 +718,10 @@ const styles = StyleSheet.create({
}, },
bottomRightImage: { bottomRightImage: {
position: 'absolute', position: 'absolute',
top: 56, top: 40,
right: 36, right: 36,
width: 80, width: 120,
height: 80, height: 120,
}, },
// 任务进度卡片中的按钮样式 // 任务进度卡片中的按钮样式
cardHeaderButtons: { cardHeaderButtons: {

View File

@@ -149,7 +149,7 @@ export default function ExploreScreen() {
}); });
}, [userProfile]); }, [userProfile]);
const { registerTask } = useBackgroundTasks(); const { registerTask, isInitialized } = useBackgroundTasks();
// 心情相关状态 // 心情相关状态
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [isMoodLoading, setIsMoodLoading] = useState(false); const [isMoodLoading, setIsMoodLoading] = useState(false);
@@ -416,27 +416,34 @@ export default function ExploreScreen() {
}, [loadAllData, currentSelectedDate]); }, [loadAllData, currentSelectedDate]);
useEffect(() => { useEffect(() => {
// 注册后台任务 - 只处理健康数据和压力检查 // 只有在后台任务管理器初始化完成后才注册任务
registerTask({ if (isInitialized) {
id: 'health-data-task', console.log('后台任务管理器已初始化,开始注册健康数据任务...');
name: 'health-data-task', registerTask({
handler: async () => { id: 'health-data-task',
try { name: 'health-data-task',
console.log('后台任务:更新健康数据和检查压力水平...'); handler: async () => {
// 后台任务只更新健康数据,强制刷新以获取最新数据 try {
await loadHealthData(undefined, true); console.log('后台任务:更新健康数据和检查压力水平...');
// 后台任务只更新健康数据,强制刷新以获取最新数据
await loadHealthData(undefined, true);
// 执行压力检查 // 执行压力检查
await checkStressLevelAndNotify(); await checkStressLevelAndNotify();
// 执行喝水目标检查 // 执行喝水目标检查
await checkWaterGoalAndNotify(); await checkWaterGoalAndNotify();
} catch (error) { } catch (error) {
console.error('健康数据任务执行失败:', error); console.error('健康数据任务执行失败:', error);
} }
}, },
}); }).then(() => {
}, []); console.log('健康数据任务注册成功');
}).catch((error) => {
console.error('健康数据任务注册失败:', error);
});
}
}, [isInitialized]);
// 检查压力水平并发送通知 // 检查压力水平并发送通知
const checkStressLevelAndNotify = React.useCallback(async () => { const checkStressLevelAndNotify = React.useCallback(async () => {
@@ -599,16 +606,18 @@ export default function ExploreScreen() {
</View> </View>
</View> </View>
<WeightHistoryCard />
{/* 日期选择器 */} {/* 日期选择器 */}
<DateSelector <DateSelector
selectedIndex={selectedIndex} selectedIndex={selectedIndex}
onDateSelect={onSelectDate} onDateSelect={onSelectDate}
showMonthTitle={true} showMonthTitle={false}
disableFutureDates={true} disableFutureDates={true}
/> />
{/* 营养摄入雷达图卡片 */} {/* 营养摄入雷达图卡片 */}
<NutritionRadarCard <NutritionRadarCard
nutritionSummary={nutritionSummary} nutritionSummary={nutritionSummary}
@@ -624,6 +633,8 @@ export default function ExploreScreen() {
}} }}
/> />
<WeightHistoryCard />
{/* 真正瀑布流布局 */} {/* 真正瀑布流布局 */}
<View style={styles.masonryContainer}> <View style={styles.masonryContainer}>
{/* 左列 */} {/* 左列 */}
@@ -768,7 +779,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 20, paddingHorizontal: 20,
}, },
headerContainer: { headerContainer: {
marginBottom: 20, marginBottom: 10,
}, },
headerContent: { headerContent: {
flexDirection: 'row', flexDirection: 'row',
@@ -1002,8 +1013,8 @@ const styles = StyleSheet.create({
masonryContainer: { masonryContainer: {
marginBottom: 16, marginBottom: 16,
flexDirection: 'row', flexDirection: 'row',
gap: 12, gap: 16,
marginTop: 16, marginTop: 6,
}, },
masonryColumn: { masonryColumn: {
flex: 1, flex: 1,
@@ -1023,6 +1034,7 @@ const styles = StyleSheet.create({
elevation: 6, elevation: 6,
minHeight: 100, minHeight: 100,
justifyContent: 'center', justifyContent: 'center',
marginTop: 6
}, },
basalMetabolismCardOverride: { basalMetabolismCardOverride: {
margin: -16, // 抵消 masonryCard 的 padding margin: -16, // 抵消 masonryCard 的 padding

View File

@@ -527,7 +527,7 @@ export default function FoodLibraryScreen() {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: '#F8F9FA', backgroundColor: Colors.light.pageBackgroundEmphasis,
}, },
customButton: { customButton: {
paddingHorizontal: 8, paddingHorizontal: 8,

1
assets/lottie/Goal.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -133,14 +133,13 @@ const styles = StyleSheet.create({
zIndex: 1, zIndex: 1,
}, },
value: { value: {
fontSize: 24, fontSize: 16,
fontWeight: '800', fontWeight: '600',
color: '#0F172A', color: '#0F172A',
lineHeight: 28, lineHeight: 28,
}, },
unit: { unit: {
fontSize: 14, fontSize: 12,
fontWeight: '500',
color: '#64748B', color: '#64748B',
marginLeft: 6, marginLeft: 6,
}, },

View File

@@ -182,7 +182,7 @@ export const DateSelector: React.FC<DateSelectorProps> = ({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
paddingVertical: 8,
}, },
monthTitle: { monthTitle: {
fontSize: 18, fontSize: 18,

View File

@@ -10,7 +10,7 @@ interface MoodCardProps {
isLoading?: boolean; isLoading?: boolean;
} }
export function MoodCard({ moodCheckin, onPress, isLoading = false }: MoodCardProps) { export function MoodCard({ moodCheckin, onPress }: MoodCardProps) {
const moodConfig = moodCheckin ? getMoodConfig(moodCheckin.moodType) : null; const moodConfig = moodCheckin ? getMoodConfig(moodCheckin.moodType) : null;
const animationRef = useRef<LottieView>(null); const animationRef = useRef<LottieView>(null);
@@ -21,7 +21,7 @@ export function MoodCard({ moodCheckin, onPress, isLoading = false }: MoodCardPr
}, []); }, []);
return ( return (
<TouchableOpacity onPress={onPress} style={styles.moodCardContent} disabled={isLoading}> <TouchableOpacity onPress={onPress} style={styles.moodCardContent} >
<View style={styles.moodCardHeader}> <View style={styles.moodCardHeader}>
<Text style={styles.cardTitle}></Text> <Text style={styles.cardTitle}></Text>
<LottieView <LottieView
@@ -32,11 +32,7 @@ export function MoodCard({ moodCheckin, onPress, isLoading = false }: MoodCardPr
style={styles.lottieAnimation} style={styles.lottieAnimation}
/> />
</View> </View>
{isLoading ? ( {moodCheckin ? (
<View style={styles.moodPreview}>
<Text style={styles.moodLoadingText}>...</Text>
</View>
) : moodCheckin ? (
<View style={styles.moodPreview}> <View style={styles.moodPreview}>
<Text style={styles.moodPreviewText}> <Text style={styles.moodPreviewText}>
{moodConfig?.label || moodCheckin.moodType} {moodConfig?.label || moodCheckin.moodType}
@@ -69,8 +65,8 @@ const styles = StyleSheet.create({
}, },
lottieAnimation: { lottieAnimation: {
width: 40, width: 30,
height: 40, height: 30,
}, },
moodPreview: { moodPreview: {

View File

@@ -210,6 +210,7 @@ const styles = StyleSheet.create({
shadowOpacity: 0.1, shadowOpacity: 0.1,
shadowRadius: 3.84, shadowRadius: 3.84,
elevation: 5, elevation: 5,
marginTop: 12
}, },
cardHeader: { cardHeader: {
flexDirection: 'row', flexDirection: 'row',
@@ -300,7 +301,7 @@ const styles = StyleSheet.create({
gap: 4, gap: 4,
}, },
mainValue: { mainValue: {
fontSize: 12, fontSize: 14,
fontWeight: '600', fontWeight: '600',
color: '#192126', color: '#192126',
}, },
@@ -320,7 +321,7 @@ const styles = StyleSheet.create({
fontWeight: '500', fontWeight: '500',
}, },
calculationValue: { calculationValue: {
fontSize: 9, fontSize: 11,
fontWeight: '700', fontWeight: '700',
color: '#192126', color: '#192126',
}, },

View File

@@ -61,12 +61,12 @@ const styles = StyleSheet.create({
alignItems: 'flex-end', alignItems: 'flex-end',
}, },
value: { value: {
fontSize: 20, fontSize: 16,
fontWeight: '600', fontWeight: '600',
color: '#192126', color: '#192126',
}, },
unit: { unit: {
fontSize: 14, fontSize: 12,
color: '#666', color: '#666',
marginLeft: 4, marginLeft: 4,
marginBottom: 2, marginBottom: 2,

View File

@@ -195,19 +195,6 @@ export function WeightHistoryCard() {
}; };
}); });
// 如果正在加载,显示加载状态
if (isLoading) {
return (
<TouchableOpacity style={styles.card} onPress={navigateToWeightRecords} activeOpacity={0.8}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}></Text>
</View>
<View style={styles.emptyContent}>
<Text style={styles.emptyDescription}>...</Text>
</View>
</TouchableOpacity>
);
}
// 如果没有体重数据,显示引导卡片 // 如果没有体重数据,显示引导卡片
if (!hasWeight) { if (!hasWeight) {
@@ -574,6 +561,7 @@ const styles = StyleSheet.create({
shadowOpacity: 0.1, shadowOpacity: 0.1,
shadowRadius: 8, shadowRadius: 8,
elevation: 3, elevation: 3,
marginTop: 16
}, },
cardHeader: { cardHeader: {
flexDirection: 'row', flexDirection: 'row',
@@ -649,6 +637,7 @@ const styles = StyleSheet.create({
summaryInfo: { summaryInfo: {
position: 'absolute', position: 'absolute',
width: '100%', width: '100%',
marginTop: 10,
}, },
chartContainer: { chartContainer: {
position: 'absolute', position: 'absolute',

View File

@@ -1,4 +1,5 @@
import { BackgroundTaskType as BackgroundTask, backgroundTaskManager, TaskStatusType as TaskStatus } from '@/services/backgroundTaskManager'; import { BackgroundTaskType as BackgroundTask, backgroundTaskManager, TaskStatusType as TaskStatus } from '@/services/backgroundTaskManager';
import * as BackgroundFetch from 'expo-background-fetch';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
export interface UseBackgroundTasksReturn { export interface UseBackgroundTasksReturn {
@@ -16,7 +17,7 @@ export interface UseBackgroundTasksReturn {
cleanupTaskStatuses: () => Promise<void>; cleanupTaskStatuses: () => Promise<void>;
// 后台任务状态 // 后台任务状态
backgroundTaskStatus: string | null; backgroundTaskStatus: BackgroundFetch.BackgroundFetchStatus | null;
getBackgroundTaskStatus: () => Promise<void>; getBackgroundTaskStatus: () => Promise<void>;
} }
@@ -24,7 +25,7 @@ export const useBackgroundTasks = (): UseBackgroundTasksReturn => {
const [isInitialized, setIsInitialized] = useState(false); const [isInitialized, setIsInitialized] = useState(false);
const [taskStatuses, setTaskStatuses] = useState<TaskStatus[]>([]); const [taskStatuses, setTaskStatuses] = useState<TaskStatus[]>([]);
const [registeredTasks, setRegisteredTasks] = useState<BackgroundTask[]>([]); const [registeredTasks, setRegisteredTasks] = useState<BackgroundTask[]>([]);
const [backgroundTaskStatus, setBackgroundTaskStatus] = useState<string | null>(null); const [backgroundTaskStatus, setBackgroundTaskStatus] = useState<BackgroundFetch.BackgroundFetchStatus | null>(null);
// 初始化 // 初始化
useEffect(() => { useEffect(() => {
@@ -87,7 +88,7 @@ export const useBackgroundTasks = (): UseBackgroundTasksReturn => {
const getBackgroundTaskStatus = useCallback(async () => { const getBackgroundTaskStatus = useCallback(async () => {
try { try {
const status = await backgroundTaskManager.getBackgroundTaskStatus(); const status = await backgroundTaskManager.getBackgroundTaskStatus();
setBackgroundTaskStatus(status ? status.toString() : null); setBackgroundTaskStatus(status);
} catch (error) { } catch (error) {
console.error('获取后台任务状态失败:', error); console.error('获取后台任务状态失败:', error);
} }

View File

@@ -40,6 +40,8 @@ PODS:
- ExpoModulesCore - ExpoModulesCore
- ExpoAsset (11.1.7): - ExpoAsset (11.1.7):
- ExpoModulesCore - ExpoModulesCore
- ExpoBackgroundFetch (13.1.6):
- ExpoModulesCore
- ExpoBackgroundTask (0.2.8): - ExpoBackgroundTask (0.2.8):
- ExpoModulesCore - ExpoModulesCore
- ExpoBlur (14.1.5): - ExpoBlur (14.1.5):
@@ -1994,6 +1996,7 @@ DEPENDENCIES:
- Expo (from `../node_modules/expo`) - Expo (from `../node_modules/expo`)
- ExpoAppleAuthentication (from `../node_modules/expo-apple-authentication/ios`) - ExpoAppleAuthentication (from `../node_modules/expo-apple-authentication/ios`)
- ExpoAsset (from `../node_modules/expo-asset/ios`) - ExpoAsset (from `../node_modules/expo-asset/ios`)
- ExpoBackgroundFetch (from `../node_modules/expo-background-fetch/ios`)
- ExpoBackgroundTask (from `../node_modules/expo-background-task/ios`) - ExpoBackgroundTask (from `../node_modules/expo-background-task/ios`)
- ExpoBlur (from `../node_modules/expo-blur/ios`) - ExpoBlur (from `../node_modules/expo-blur/ios`)
- ExpoFileSystem (from `../node_modules/expo-file-system/ios`) - ExpoFileSystem (from `../node_modules/expo-file-system/ios`)
@@ -2136,6 +2139,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-apple-authentication/ios" :path: "../node_modules/expo-apple-authentication/ios"
ExpoAsset: ExpoAsset:
:path: "../node_modules/expo-asset/ios" :path: "../node_modules/expo-asset/ios"
ExpoBackgroundFetch:
:path: "../node_modules/expo-background-fetch/ios"
ExpoBackgroundTask: ExpoBackgroundTask:
:path: "../node_modules/expo-background-task/ios" :path: "../node_modules/expo-background-task/ios"
ExpoBlur: ExpoBlur:
@@ -2351,6 +2356,7 @@ SPEC CHECKSUMS:
Expo: 8685113c16058e8b3eb101dd52d6c8bca260bbea Expo: 8685113c16058e8b3eb101dd52d6c8bca260bbea
ExpoAppleAuthentication: 8a661b6f4936affafd830f983ac22463c936dad5 ExpoAppleAuthentication: 8a661b6f4936affafd830f983ac22463c936dad5
ExpoAsset: ef06e880126c375f580d4923fdd1cdf4ee6ee7d6 ExpoAsset: ef06e880126c375f580d4923fdd1cdf4ee6ee7d6
ExpoBackgroundFetch: 6dcade705c90ae5b7e2d0836b9145cae8f5f3070
ExpoBackgroundTask: 6c1990438e45b5c4bbbc7d75aa6b688d53602fe8 ExpoBackgroundTask: 6c1990438e45b5c4bbbc7d75aa6b688d53602fe8
ExpoBlur: 3c8885b9bf9eef4309041ec87adec48b5f1986a9 ExpoBlur: 3c8885b9bf9eef4309041ec87adec48b5f1986a9
ExpoFileSystem: 7f92f7be2f5c5ed40a7c9efc8fa30821181d9d63 ExpoFileSystem: 7f92f7be2f5c5ed40a7c9efc8fa30821181d9d63

View File

@@ -68,6 +68,7 @@
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>
<array> <array>
<string>processing</string> <string>processing</string>
<string>fetch</string>
</array> </array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>SplashScreen</string> <string>SplashScreen</string>

13
package-lock.json generated
View File

@@ -23,6 +23,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"expo": "~53.0.20", "expo": "~53.0.20",
"expo-apple-authentication": "6.4.2", "expo-apple-authentication": "6.4.2",
"expo-background-fetch": "^13.1.6",
"expo-background-task": "~0.2.8", "expo-background-task": "~0.2.8",
"expo-blur": "~14.1.5", "expo-blur": "~14.1.5",
"expo-constants": "~17.1.7", "expo-constants": "~17.1.7",
@@ -7073,6 +7074,18 @@
"react-native": "*" "react-native": "*"
} }
}, },
"node_modules/expo-background-fetch": {
"version": "13.1.6",
"resolved": "https://mirrors.tencent.com/npm/expo-background-fetch/-/expo-background-fetch-13.1.6.tgz",
"integrity": "sha512-hl4kR32DaxoHFYqNsILLZG2mWssCkUb4wnEAHtDGmpxUP4SCnJILcAn99J6AGDFUw5lF6FXNZZCXNfcrFioO4Q==",
"license": "MIT",
"dependencies": {
"expo-task-manager": "~13.1.6"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-background-task": { "node_modules/expo-background-task": {
"version": "0.2.8", "version": "0.2.8",
"resolved": "https://registry.npmjs.org/expo-background-task/-/expo-background-task-0.2.8.tgz", "resolved": "https://registry.npmjs.org/expo-background-task/-/expo-background-task-0.2.8.tgz",

View File

@@ -27,6 +27,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"expo": "~53.0.20", "expo": "~53.0.20",
"expo-apple-authentication": "6.4.2", "expo-apple-authentication": "6.4.2",
"expo-background-fetch": "^13.1.6",
"expo-background-task": "~0.2.8", "expo-background-task": "~0.2.8",
"expo-blur": "~14.1.5", "expo-blur": "~14.1.5",
"expo-constants": "~17.1.7", "expo-constants": "~17.1.7",

View File

@@ -1,5 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import * as ExpoBackgroundTask from 'expo-background-task'; import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager'; import * as TaskManager from 'expo-task-manager';
// 任务类型定义 // 任务类型定义
@@ -63,13 +63,17 @@ class BackgroundTaskManager {
// 注册后台任务 // 注册后台任务
private async registerBackgroundTask(): Promise<void> { private async registerBackgroundTask(): Promise<void> {
const BACKGROUND_TASK = 'background-task'; const BACKGROUND_FETCH_TASK = 'background-fetch-task';
console.log('注册后台任务'); console.log('注册后台获取任务');
// 定义后台任务
TaskManager.defineTask(BACKGROUND_TASK, async () => { // 定义后台获取任务
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
console.log('后台获取任务被系统调用');
const now = new Date();
try { try {
console.log('开始执行后台任务'); console.log(`开始执行后台任务 - ${now.toISOString()}`);
// 执行所有注册的任务 // 执行所有注册的任务
const results = await this.executeAllTasks(); const results = await this.executeAllTasks();
@@ -77,19 +81,29 @@ class BackgroundTaskManager {
console.log('后台任务执行完成:', results); console.log('后台任务执行完成:', results);
// 返回成功状态 // 返回成功状态
return ExpoBackgroundTask.BackgroundTaskResult.Success; return BackgroundFetch.BackgroundFetchResult.NewData;
} catch (error) { } catch (error) {
console.error('后台任务执行失败:', error); console.error('后台任务执行失败:', error);
return ExpoBackgroundTask.BackgroundTaskResult.Failed; return BackgroundFetch.BackgroundFetchResult.Failed;
} }
}); });
// 注册后台任务 // 注册后台获取任务
await ExpoBackgroundTask.registerTaskAsync(BACKGROUND_TASK, { try {
minimumInterval: 15, // 最小间隔60分钟 const status = await BackgroundFetch.getStatusAsync();
}); if (status === BackgroundFetch.BackgroundFetchStatus.Available) {
await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
console.log('后台任务注册成功'); minimumInterval: 15 * 60, // 15分钟以秒为单位
stopOnTerminate: false,
startOnBoot: true,
});
console.log('后台获取任务注册成功');
} else {
console.warn('后台获取不可用,状态:', status);
}
} catch (error) {
console.error('注册后台获取任务失败:', error);
}
} }
// 注册自定义任务 // 注册自定义任务
@@ -212,8 +226,8 @@ class BackgroundTaskManager {
} }
// 检查后台任务状态 // 检查后台任务状态
public async getBackgroundTaskStatus(): Promise<ExpoBackgroundTask.BackgroundTaskStatus | null> { public async getBackgroundTaskStatus(): Promise<BackgroundFetch.BackgroundFetchStatus | null> {
return await ExpoBackgroundTask.getStatusAsync(); return await BackgroundFetch.getStatusAsync();
} }
// 保存任务状态到本地存储 // 保存任务状态到本地存储
@@ -254,6 +268,42 @@ class BackgroundTaskManager {
await this.saveTaskStatuses(); await this.saveTaskStatuses();
} }
// 调试函数:强制触发后台任务执行
public async debugExecuteBackgroundTask(): Promise<void> {
console.log('=== 调试:手动触发后台任务执行 ===');
try {
// 获取后台任务状态
const status = await this.getBackgroundTaskStatus();
console.log('后台获取状态:', status);
// 执行所有注册的任务
console.log('当前注册的任务数量:', this.tasks.size);
this.tasks.forEach((task, id) => {
console.log(`- 任务ID: ${id}, 名称: ${task.name}`);
});
const results = await this.executeAllTasks();
console.log('任务执行结果:', results);
// 显示任务状态
const taskStatuses = this.getAllTaskStatuses();
taskStatuses.forEach(status => {
console.log(`任务 ${status.id} 状态:`, {
isRegistered: status.isRegistered,
executionCount: status.executionCount,
lastExecution: status.lastExecution?.toISOString(),
lastError: status.lastError
});
});
} catch (error) {
console.error('调试执行失败:', error);
}
console.log('=== 调试执行完成 ===');
}
} }
// 导出单例实例 // 导出单例实例