diff --git a/app/profile/edit.tsx b/app/profile/edit.tsx index 615e376..8bcdaea 100644 --- a/app/profile/edit.tsx +++ b/app/profile/edit.tsx @@ -6,7 +6,7 @@ import { useCosUpload } from '@/hooks/useCosUpload'; import { fetchMyProfile, updateUserProfile } from '@/store/userSlice'; import { fetchMaximumHeartRate } from '@/utils/health'; import { Ionicons } from '@expo/vector-icons'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import DateTimePicker from '@react-native-community/datetimepicker'; import { Picker } from '@react-native-picker/picker'; import { useFocusEffect } from '@react-navigation/native'; diff --git a/app/profile/goals.tsx b/app/profile/goals.tsx index 5622c9d..4af37ce 100644 --- a/app/profile/goals.tsx +++ b/app/profile/goals.tsx @@ -1,7 +1,7 @@ import { HeaderBar } from '@/components/ui/HeaderBar'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import * as Haptics from 'expo-haptics'; import { useRouter } from 'expo-router'; import React, { useEffect, useMemo, useState } from 'react'; diff --git a/hooks/useAuthGuard.ts b/hooks/useAuthGuard.ts index 52c2420..d57a5dc 100644 --- a/hooks/useAuthGuard.ts +++ b/hooks/useAuthGuard.ts @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { usePathname, useRouter } from 'expo-router'; import { useCallback } from 'react'; import { Alert } from 'react-native'; diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4f5c6f4..00c79bd 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -112,6 +112,8 @@ PODS: - ExpoModulesCore - ExpoSplashScreen (31.0.8): - ExpoModulesCore + - ExpoSQLite (16.0.8): + - ExpoModulesCore - ExpoSymbols (1.0.6): - ExpoModulesCore - ExpoSystemUI (6.0.7): @@ -3065,6 +3067,7 @@ DEPENDENCIES: - ExpoModulesCore (from `../node_modules/expo-modules-core`) - ExpoQuickActions (from `../node_modules/expo-quick-actions/ios`) - ExpoSplashScreen (from `../node_modules/expo-splash-screen/ios`) + - ExpoSQLite (from `../node_modules/expo-sqlite/ios`) - ExpoSymbols (from `../node_modules/expo-symbols/ios`) - ExpoSystemUI (from `../node_modules/expo-system-ui/ios`) - "ExpoUI (from `../node_modules/@expo/ui/ios`)" @@ -3228,6 +3231,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-quick-actions/ios" ExpoSplashScreen: :path: "../node_modules/expo-splash-screen/ios" + ExpoSQLite: + :path: "../node_modules/expo-sqlite/ios" ExpoSymbols: :path: "../node_modules/expo-symbols/ios" ExpoSystemUI: @@ -3442,6 +3447,7 @@ SPEC CHECKSUMS: ExpoModulesCore: 5d150c790fb491ab10fe431fb794014af841258f ExpoQuickActions: fdbda7f5874aed3dd2b1d891ec00ab3300dc7541 ExpoSplashScreen: 1665809071bd907c6fdbfd9c09583ee4d51b41d4 + ExpoSQLite: 7fa091ba5562474093fef09be644161a65e11b3f ExpoSymbols: 3efee6865b1955fe3805ca88b36e8674ce6970dd ExpoSystemUI: 6cd74248a2282adf6dec488a75fa532d69dee314 ExpoUI: 0f109b0549d1ae2fd955d3b8733b290c5cdeec7e diff --git a/package-lock.json b/package-lock.json index b19cc88..1cd96a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "expo-quick-actions": "^5.0.0", "expo-router": "~6.0.4", "expo-splash-screen": "~31.0.8", + "expo-sqlite": "^16.0.8", "expo-status-bar": "~3.0.7", "expo-symbols": "~1.0.6", "expo-system-ui": "~6.0.7", @@ -5578,6 +5579,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/await-lock": { + "version": "2.2.2", + "resolved": "https://mirrors.tencent.com/npm/await-lock/-/await-lock-2.2.2.tgz", + "integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==", + "license": "MIT" + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -8139,6 +8146,20 @@ "expo": "*" } }, + "node_modules/expo-sqlite": { + "version": "16.0.8", + "resolved": "https://mirrors.tencent.com/npm/expo-sqlite/-/expo-sqlite-16.0.8.tgz", + "integrity": "sha512-xw776gFgH4ZM5oGs0spSLNmkHO/kJ/EuRXGzE4/22yII9EmG84vm7aM/M2aEb8taBTqwhSGYUpkwkRT5YFFmsg==", + "license": "MIT", + "dependencies": { + "await-lock": "^2.2.2" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-status-bar": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-3.0.7.tgz", diff --git a/package.json b/package.json index 3e98360..40d64dd 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "expo-quick-actions": "^5.0.0", "expo-router": "~6.0.4", "expo-splash-screen": "~31.0.8", + "expo-sqlite": "^16.0.8", "expo-status-bar": "~3.0.7", "expo-symbols": "~1.0.6", "expo-system-ui": "~6.0.7", @@ -81,4 +82,4 @@ "typescript": "~5.9.2" }, "private": true -} \ No newline at end of file +} diff --git a/services/aiCoachSession.ts b/services/aiCoachSession.ts index c2a4966..a1e06c9 100644 --- a/services/aiCoachSession.ts +++ b/services/aiCoachSession.ts @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; export type AiCoachChatMessage = { id: string; diff --git a/services/api.ts b/services/api.ts index 72ca486..6bba1c9 100644 --- a/services/api.ts +++ b/services/api.ts @@ -1,5 +1,5 @@ import { buildApiUrl } from '@/constants/Api'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; diff --git a/services/backgroundTaskManager.ts b/services/backgroundTaskManager.ts index 815f9d0..e1d0fb6 100644 --- a/services/backgroundTaskManager.ts +++ b/services/backgroundTaskManager.ts @@ -1,7 +1,7 @@ import { store } from '@/store'; import { log } from '@/utils/logger'; import { StandReminderHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import * as BackgroundTask from 'expo-background-task'; import * as TaskManager from 'expo-task-manager'; import { TaskManagerTaskBody } from 'expo-task-manager'; diff --git a/store/challengeSlice.ts b/store/challengeSlice.ts index 8ddc8df..8a8325d 100644 --- a/store/challengeSlice.ts +++ b/store/challengeSlice.ts @@ -1,5 +1,5 @@ import { buildDefaultCustomFromPlan, DayPlan, ExerciseCustomConfig, generatePilates30DayPlan, PilatesLevel } from '@/utils/pilatesPlan'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; export type DayStatus = 'locked' | 'available' | 'completed'; diff --git a/store/exerciseLibrarySlice.ts b/store/exerciseLibrarySlice.ts index 9e1dbfd..d65bc8e 100644 --- a/store/exerciseLibrarySlice.ts +++ b/store/exerciseLibrarySlice.ts @@ -5,7 +5,7 @@ import { type ExerciseConfigResponse, type ExerciseLibraryItem, } from '@/services/exercises'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; export interface ExerciseLibraryState { diff --git a/store/trainingPlanSlice.ts b/store/trainingPlanSlice.ts index 2dacef1..9411f26 100644 --- a/store/trainingPlanSlice.ts +++ b/store/trainingPlanSlice.ts @@ -1,5 +1,5 @@ import { CreateTrainingPlanDto, PlanGoal, PlanMode, TrainingPlan, trainingPlanApi } from '@/services/trainingPlanApi'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; diff --git a/store/userSlice.ts b/store/userSlice.ts index 78404c7..6876d6f 100644 --- a/store/userSlice.ts +++ b/store/userSlice.ts @@ -1,6 +1,6 @@ import { api, setAuthToken, STORAGE_KEYS } from '@/services/api'; import { updateUser, UpdateUserDto } from '@/services/users'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { createAsyncThunk, createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit'; import dayjs from 'dayjs'; diff --git a/utils/devTools.ts b/utils/devTools.ts index d30578a..ac2bf99 100644 --- a/utils/devTools.ts +++ b/utils/devTools.ts @@ -1,5 +1,5 @@ import { STORAGE_KEYS } from '@/services/api'; -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { resetAllGuides } from './guideHelpers'; /** diff --git a/utils/guideHelpers.ts b/utils/guideHelpers.ts index 74b599d..99e5058 100644 --- a/utils/guideHelpers.ts +++ b/utils/guideHelpers.ts @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; // 引导状态存储键 const GUIDE_KEYS = { diff --git a/utils/kvStore.ts b/utils/kvStore.ts new file mode 100644 index 0000000..f1be569 --- /dev/null +++ b/utils/kvStore.ts @@ -0,0 +1,23 @@ +// 直接使用 expo-sqlite/kv-store 作为 AsyncStorage 的替代品 +// 这是 expo-sqlite 提供的现成 key-value store 实现,完全兼容 AsyncStorage API +import Storage from 'expo-sqlite/kv-store'; + +// 重新导出所有方法,保持与原 AsyncStorage 相同的接口 +export const getItem = Storage.getItem.bind(Storage); +export const setItem = Storage.setItem.bind(Storage); +export const removeItem = Storage.removeItem.bind(Storage); +export const getAllKeys = Storage.getAllKeys.bind(Storage); +export const multiGet = Storage.multiGet.bind(Storage); +export const multiSet = Storage.multiSet.bind(Storage); +export const multiRemove = Storage.multiRemove.bind(Storage); +export const clear = Storage.clear.bind(Storage); + +// 同步方法(expo-sqlite/kv-store 的特色功能) +export const getItemSync = Storage.getItemSync.bind(Storage); +export const setItemSync = Storage.setItemSync.bind(Storage); +export const removeItemSync = Storage.removeItemSync.bind(Storage); +export const getAllKeysSync = Storage.getAllKeysSync.bind(Storage); +export const clearSync = Storage.clearSync.bind(Storage); + +// 默认导出,与 AsyncStorage 接口完全兼容 +export default Storage; \ No newline at end of file diff --git a/utils/logger.ts b/utils/logger.ts index d601ef8..10660ee 100644 --- a/utils/logger.ts +++ b/utils/logger.ts @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; interface LogEntry { id: string; diff --git a/utils/notificationHelpers.ts b/utils/notificationHelpers.ts index 38ad824..7a3d43b 100644 --- a/utils/notificationHelpers.ts +++ b/utils/notificationHelpers.ts @@ -670,7 +670,7 @@ export class WaterNotificationHelpers { // 检查是否在过去2小时内已经发送过喝水提醒,避免重复打扰 const lastNotificationKey = '@last_water_notification'; - const AsyncStorage = (await import('@react-native-async-storage/async-storage')).default; + const AsyncStorage = (await import('@/utils/kvStore')).default; const lastNotificationTime = await AsyncStorage.getItem(lastNotificationKey); const now = new Date().getTime(); const twoHoursAgo = now - (2 * 60 * 60 * 1000); // 2小时前 diff --git a/utils/userPreferences.ts b/utils/userPreferences.ts index 47c9920..b24fa35 100644 --- a/utils/userPreferences.ts +++ b/utils/userPreferences.ts @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; // 用户偏好设置的存储键 const PREFERENCES_KEYS = { diff --git a/utils/widgetDataSync.ts b/utils/widgetDataSync.ts index 50383c8..73c81cf 100644 --- a/utils/widgetDataSync.ts +++ b/utils/widgetDataSync.ts @@ -1,4 +1,4 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; +import AsyncStorage from '@/utils/kvStore'; import { NativeModules } from 'react-native'; // Widget数据同步服务