fix: 修复 Android 闪退问题 - SecureStore 异步调用

问题:
- NativeStorage 使用了同步方法调用 expo-secure-store
- expo-secure-store 的正确 API 是异步的(getItemAsync/setItemAsync/deleteItemAsync)
- 在 Android 上同步调用不存在的方法导致应用崩溃

修复:
- 将 Storage 接口改为异步方法
- 使用 SecureStore.getItemAsync/setItemAsync/deleteItemAsync
- removeItem 使用 deleteItemAsync 而不是设置空字符串

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
imeepos 2025-11-12 14:44:42 +08:00
parent 3ebcc24e9b
commit 67f3c0b70e
10 changed files with 101 additions and 89 deletions

View File

@ -20,7 +20,8 @@
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false,
"package": "com.anonymous.bwexpoappv3"
"package": "com.anonymous.bwexpoappv3",
"versionCode": 3
},
"web": {
"output": "static",
@ -42,7 +43,8 @@
],
"expo-video",
"expo-audio",
"expo-web-browser"
"expo-web-browser",
"expo-asset"
],
"experiments": {
"typedRoutes": true,
@ -53,6 +55,6 @@
"projectId": "191f0396-3e0c-40ec-bd06-b15f58278b8f"
}
},
"owner": "imeepos"
"owner": "bowong"
}
}

View File

@ -1,10 +1,29 @@
import { ThemedView } from '@/components/themed-view';
import { VideoView, useVideoPlayer } from 'expo-video';
import * as MediaLibrary from 'expo-media-library';
import * as FileSystem from 'expo-file-system';
import { Platform } from 'react-native';
import { ThemedText } from '@/components/themed-text';
import { getTemplateGeneration } from '@/lib/api/template-runs';
import * as Clipboard from 'expo-clipboard';
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import { router, useLocalSearchParams } from 'expo-router';
import { VideoView, useVideoPlayer } from 'expo-video';
import {
ArrowLeft,
Copy,
Download,
Maximize2,
Plus,
X,
} from 'lucide-react';
import React, { useEffect, useState } from 'react';
import {
ActivityIndicator,
Alert,
Dimensions,
Image, Modal, Platform, ScrollView,
StyleSheet, Text,
TouchableOpacity,
View
} from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
// ResizeMode 兼容映射 - 移除 'stretch'expo-video 不支持
const ResizeMode = {
@ -12,43 +31,33 @@ const ResizeMode = {
COVER: 'cover' as const,
STRETCH: 'fill' as const, // 使用 'fill' 替代 'stretch'
};
import { router, useLocalSearchParams } from 'expo-router';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
Copy,
Download,
Maximize2,
Plus,
X,
ArrowLeft,
} from 'lucide-react';
import React, { useEffect, useState } from 'react';
import {
ActivityIndicator,
Alert,
Dimensions,
Image,
ImageStyle,
Modal,
ScrollView,
StyleSheet,
StyleProp,
Text,
TouchableOpacity,
View,
ViewStyle,
FlatList,
} from 'react-native';
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
const HERO_HEIGHT = screenWidth * 0.58;
const VIDEO_HEIGHT = screenHeight * 0.6;
// 原生视频播放组件
const NativeVideoPlayer: React.FC<{ url: string; style?: any }> = ({ url, style }) => {
const player = useVideoPlayer(url, player => {
player.loop = false;
});
return (
<VideoView
player={player}
style={style}
contentFit="contain"
allowsFullscreen
allowsPictureInPicture
/>
);
};
interface ResultWithTemplate {
id: string;
userId: string;
templateId: string;
type: 'TEXT' | 'IMAGE' | 'VIDEO';
type: 'UNKNOWN' | 'TEXT' | 'IMAGE' | 'VIDEO';
resultUrl: string[];
status: 'pending' | 'running' | 'completed' | 'failed';
creditsCost?: number;
@ -233,7 +242,7 @@ export default function ResultPage() {
if (!result || result.type !== 'TEXT') return;
try {
await navigator.clipboard?.writeText?.(result.resultUrl[0]);
await Clipboard.setStringAsync(result.resultUrl[0]);
Alert.alert('复制成功', '文本已复制到剪贴板');
} catch (error) {
Alert.alert('复制失败', '无法复制文本');
@ -306,9 +315,10 @@ export default function ResultPage() {
playsInline
/>
) : (
<View style={{ width: '100%', height: VIDEO_HEIGHT }}>
<ThemedText>Video: {url}</ThemedText>
</View>
<NativeVideoPlayer
url={url}
style={{ width: '100%', height: VIDEO_HEIGHT }}
/>
)
) : (
<Image
@ -435,9 +445,10 @@ export default function ResultPage() {
controls
/>
) : (
<View style={styles.fullscreenMediaContent}>
<ThemedText>Video Player</ThemedText>
</View>
<NativeVideoPlayer
url={fullscreenContent.url}
style={styles.fullscreenMediaContent}
/>
)}
</>
)}

View File

@ -87,6 +87,7 @@ export default function TemplateDetailScreen() {
const [menuVisible, setMenuVisible] = useState(false);
const [loadingLooks, setLoadingLooks] = useState(true);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [retryTrigger, setRetryTrigger] = useState(0);
const abortControllerRef = useRef<AbortController | null>(null);
const imageCache = useRef(new Set<string>());
@ -242,22 +243,15 @@ export default function TemplateDetailScreen() {
cache.delete(`tag:${current?.title}`);
setErrorMessage(null);
setLoadingLooks(true);
const event = new Event('retry');
window.dispatchEvent(event);
setRetryTrigger(prev => prev + 1);
}, [id, current?.title]);
useEffect(() => {
const handleRetryEvent = () => {
if (retryTrigger > 0) {
const newController = new AbortController();
abortControllerRef.current = newController;
};
window.addEventListener('retry', handleRetryEvent);
return () => {
window.removeEventListener('retry', handleRetryEvent);
};
}, []);
}
}, [retryTrigger]);
const handleGenerate = () => {
if (!resolvedTemplateId) {

View File

@ -16,8 +16,11 @@
"better-auth": "1.3.27",
"eas-cli": "^16.22.0",
"expo": "54.0.23",
"expo-asset": "~12.0.9",
"expo-audio": "~1.0.14",
"expo-clipboard": "~8.0.7",
"expo-constants": "~18.0.10",
"expo-crypto": "~15.0.7",
"expo-dev-client": "~6.0.17",
"expo-file-system": "~19.0.17",
"expo-font": "~14.0.9",
@ -312,7 +315,7 @@
"@expo/fingerprint": ["@expo/fingerprint@0.15.3", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "getenv": "^2.0.0", "glob": "^10.4.2", "ignore": "^5.3.1", "minimatch": "^9.0.0", "p-limit": "^3.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-8YPJpEYlmV171fi+t+cSLMX1nC5ngY9j2FiN70dHldLpd6Ct6ouGhk96svJ4BQZwsqwII2pokwzrDAwqo4Z0FQ=="],
"@expo/image-utils": ["@expo/image-utils@0.6.5", "https://registry.npmmirror.com/@expo/image-utils/-/image-utils-0.6.5.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "fs-extra": "9.0.0", "getenv": "^1.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-RsS/1CwJYzccvlprYktD42KjyfWZECH6PPIEowvoSmXfGLfdViwcUEI4RvBfKX5Jli6P67H+6YmHvPTbGOboew=="],
"@expo/image-utils": ["@expo/image-utils@0.8.7", "https://registry.npmmirror.com/@expo/image-utils/-/image-utils-0.8.7.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w=="],
"@expo/json-file": ["@expo/json-file@8.3.3", "https://registry.npmmirror.com/@expo/json-file/-/json-file-8.3.3.tgz", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.2", "write-file-atomic": "^2.3.0" } }, "sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A=="],
@ -1072,6 +1075,8 @@
"expo-audio": ["expo-audio@1.0.14", "", { "peerDependencies": { "expo": "*", "expo-asset": "*", "react": "*", "react-native": "*" } }, "sha512-UU8n1mIDPfO9zFQbPnIpnzhHeqC8c8WQUoOOFvlgI5CeOJMUrQ6UXDpX+LBcHxw/amSBhF5HP6VMr58foPKwbA=="],
"expo-clipboard": ["expo-clipboard@8.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q=="],
"expo-constants": ["expo-constants@18.0.10", "", { "dependencies": { "@expo/config": "~12.0.10", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-Rhtv+X974k0Cahmvx6p7ER5+pNhBC0XbP1lRviL2J1Xl4sT2FBaIuIxF/0I0CbhOsySf0ksqc5caFweAy9Ewiw=="],
"expo-crypto": ["expo-crypto@15.0.7", "https://registry.npmmirror.com/expo-crypto/-/expo-crypto-15.0.7.tgz", { "dependencies": { "base64-js": "^1.3.0" }, "peerDependencies": { "expo": "*" } }, "sha512-FUo41TwwGT2e5rA45PsjezI868Ch3M6wbCZsmqTWdF/hr+HyPcrp1L//dsh/hsrsyrQdpY/U96Lu71/wXePJeg=="],
@ -2216,8 +2221,6 @@
"@expo/cli/@expo/env": ["@expo/env@2.0.7", "https://registry.npmmirror.com/@expo/env/-/env-2.0.7.tgz", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" } }, "sha512-BNETbLEohk3HQ2LxwwezpG8pq+h7Fs7/vAMP3eAtFT1BCpprLYoBBFZH7gW4aqGfqOcVP4Lc91j014verrYNGg=="],
"@expo/cli/@expo/image-utils": ["@expo/image-utils@0.8.7", "https://registry.npmmirror.com/@expo/image-utils/-/image-utils-0.8.7.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w=="],
"@expo/cli/@expo/json-file": ["@expo/json-file@10.0.7", "https://registry.npmmirror.com/@expo/json-file/-/json-file-10.0.7.tgz", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-z2OTC0XNO6riZu98EjdNHC05l51ySeTto6GP7oSQrCvQgG9ARBwD1YvMQaVZ9wU7p/4LzSf1O7tckL3B45fPpw=="],
"@expo/cli/@expo/osascript": ["@expo/osascript@2.3.7", "https://registry.npmmirror.com/@expo/osascript/-/osascript-2.3.7.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "exec-async": "^2.2.0" } }, "sha512-IClSOXxR0YUFxIriUJVqyYki7lLMIHrrzOaP01yxAL1G8pj2DWV5eW1y5jSzIcIfSCNhtGsshGd1tU/AYup5iQ=="],
@ -2288,7 +2291,7 @@
"@expo/fingerprint/semver": ["semver@7.7.3", "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"@expo/image-utils/fs-extra": ["fs-extra@9.0.0", "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.0.0.tgz", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^1.0.0" } }, "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g=="],
"@expo/image-utils/getenv": ["getenv@2.0.0", "https://registry.npmmirror.com/getenv/-/getenv-2.0.0.tgz", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="],
"@expo/image-utils/semver": ["semver@7.7.3", "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
@ -2332,6 +2335,8 @@
"@expo/plugin-warn-if-update-available/tslib": ["tslib@2.8.1", "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@expo/prebuild-config/@expo/image-utils": ["@expo/image-utils@0.6.5", "https://registry.npmmirror.com/@expo/image-utils/-/image-utils-0.6.5.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "fs-extra": "9.0.0", "getenv": "^1.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-RsS/1CwJYzccvlprYktD42KjyfWZECH6PPIEowvoSmXfGLfdViwcUEI4RvBfKX5Jli6P67H+6YmHvPTbGOboew=="],
"@expo/prebuild-config/@expo/json-file": ["@expo/json-file@9.1.5", "https://registry.npmmirror.com/@expo/json-file/-/json-file-9.1.5.tgz", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA=="],
"@expo/prebuild-config/@react-native/normalize-colors": ["@react-native/normalize-colors@0.76.2", "https://registry.npmmirror.com/@react-native/normalize-colors/-/normalize-colors-0.76.2.tgz", {}, "sha512-ICoOpaTLPsFQjNLSM00NgQr6wal300cZZonHVSDXKntX+BfkLeuCHRtr/Mn+klTtW+/1v2/2FRm9dXjvyGf9Dw=="],
@ -2480,8 +2485,6 @@
"expo/@expo/config-plugins": ["@expo/config-plugins@54.0.2", "https://registry.npmmirror.com/@expo/config-plugins/-/config-plugins-54.0.2.tgz", { "dependencies": { "@expo/config-types": "^54.0.8", "@expo/json-file": "~10.0.7", "@expo/plist": "^0.4.7", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^10.4.2", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-jD4qxFcURQUVsUFGMcbo63a/AnviK8WUGard+yrdQE3ZrB/aurn68SlApjirQQLEizhjI5Ar2ufqflOBlNpyPg=="],
"expo-asset/@expo/image-utils": ["@expo/image-utils@0.8.7", "https://registry.npmmirror.com/@expo/image-utils/-/image-utils-0.8.7.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w=="],
"expo-asset/expo-constants": ["expo-constants@18.0.9", "https://registry.npmmirror.com/expo-constants/-/expo-constants-18.0.9.tgz", { "dependencies": { "@expo/config": "~12.0.9", "@expo/env": "~2.0.7" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-sqoXHAOGDcr+M9NlXzj1tGoZyd3zxYDy215W6E0Z0n8fgBaqce9FAYQE2bu5X4G629AYig5go7U6sQz7Pjcm8A=="],
"expo-constants/@expo/config": ["@expo/config@12.0.10", "https://registry.npmmirror.com/@expo/config/-/config-12.0.10.tgz", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~54.0.2", "@expo/config-types": "^54.0.8", "@expo/json-file": "^10.0.7", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "3.35.0" } }, "sha512-lJMof5Nqakq1DxGYlghYB/ogSBjmv4Fxn1ovyDmcjlRsQdFCXgu06gEUogkhPtc9wBt9WlTTfqENln5HHyLW6w=="],
@ -2704,8 +2707,6 @@
"@expo/fingerprint/minimatch/brace-expansion": ["brace-expansion@2.0.2", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"@expo/image-utils/fs-extra/universalify": ["universalify@1.0.0", "https://registry.npmmirror.com/universalify/-/universalify-1.0.0.tgz", {}, "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="],
"@expo/metro-config/@expo/config/@babel/code-frame": ["@babel/code-frame@7.10.4", "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.10.4.tgz", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="],
"@expo/metro-config/@expo/config/@expo/config-plugins": ["@expo/config-plugins@54.0.2", "https://registry.npmmirror.com/@expo/config-plugins/-/config-plugins-54.0.2.tgz", { "dependencies": { "@expo/config-types": "^54.0.8", "@expo/json-file": "~10.0.7", "@expo/plist": "^0.4.7", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^10.4.2", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-jD4qxFcURQUVsUFGMcbo63a/AnviK8WUGard+yrdQE3ZrB/aurn68SlApjirQQLEizhjI5Ar2ufqflOBlNpyPg=="],
@ -2742,6 +2743,8 @@
"@expo/plugin-warn-if-update-available/@oclif/core/supports-color": ["supports-color@8.1.1", "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"@expo/prebuild-config/@expo/image-utils/fs-extra": ["fs-extra@9.0.0", "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.0.0.tgz", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^1.0.0" } }, "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g=="],
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
@ -2804,10 +2807,6 @@
"eas-cli/minimatch/brace-expansion": ["brace-expansion@2.0.2", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"expo-asset/@expo/image-utils/getenv": ["getenv@2.0.0", "https://registry.npmmirror.com/getenv/-/getenv-2.0.0.tgz", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="],
"expo-asset/@expo/image-utils/semver": ["semver@7.7.3", "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"expo-asset/expo-constants/@expo/config": ["@expo/config@12.0.10", "https://registry.npmmirror.com/@expo/config/-/config-12.0.10.tgz", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~54.0.2", "@expo/config-types": "^54.0.8", "@expo/json-file": "^10.0.7", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^10.4.2", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "3.35.0" } }, "sha512-lJMof5Nqakq1DxGYlghYB/ogSBjmv4Fxn1ovyDmcjlRsQdFCXgu06gEUogkhPtc9wBt9WlTTfqENln5HHyLW6w=="],
"expo-asset/expo-constants/@expo/env": ["@expo/env@2.0.7", "https://registry.npmmirror.com/@expo/env/-/env-2.0.7.tgz", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" } }, "sha512-BNETbLEohk3HQ2LxwwezpG8pq+h7Fs7/vAMP3eAtFT1BCpprLYoBBFZH7gW4aqGfqOcVP4Lc91j014verrYNGg=="],
@ -2850,8 +2849,6 @@
"expo-splash-screen/@expo/prebuild-config/@expo/config-types": ["@expo/config-types@54.0.8", "https://registry.npmmirror.com/@expo/config-types/-/config-types-54.0.8.tgz", {}, "sha512-lyIn/x/Yz0SgHL7IGWtgTLg6TJWC9vL7489++0hzCHZ4iGjVcfZmPTUfiragZ3HycFFj899qN0jlhl49IHa94A=="],
"expo-splash-screen/@expo/prebuild-config/@expo/image-utils": ["@expo/image-utils@0.8.7", "https://registry.npmmirror.com/@expo/image-utils/-/image-utils-0.8.7.tgz", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w=="],
"expo-splash-screen/@expo/prebuild-config/@expo/json-file": ["@expo/json-file@10.0.7", "https://registry.npmmirror.com/@expo/json-file/-/json-file-10.0.7.tgz", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-z2OTC0XNO6riZu98EjdNHC05l51ySeTto6GP7oSQrCvQgG9ARBwD1YvMQaVZ9wU7p/4LzSf1O7tckL3B45fPpw=="],
"expo-splash-screen/@expo/prebuild-config/@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.4", "https://registry.npmmirror.com/@react-native/normalize-colors/-/normalize-colors-0.81.4.tgz", {}, "sha512-9nRRHO1H+tcFqjb9gAM105Urtgcanbta2tuqCVY0NATHeFPDEAB7gPyiLxCHKMi1NbhP6TH0kxgSWXKZl1cyRg=="],
@ -2954,6 +2951,8 @@
"@expo/plugin-warn-if-update-available/@oclif/core/js-yaml/argparse": ["argparse@1.0.10", "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
"@expo/prebuild-config/@expo/image-utils/fs-extra/universalify": ["universalify@1.0.0", "https://registry.npmmirror.com/universalify/-/universalify-1.0.0.tgz", {}, "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="],
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
"@oclif/plugin-autocomplete/@oclif/core/js-yaml/argparse": ["argparse@1.0.10", "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
@ -3016,8 +3015,6 @@
"expo-splash-screen/@expo/prebuild-config/@expo/config-plugins/glob": ["glob@10.4.5", "https://registry.npmmirror.com/glob/-/glob-10.4.5.tgz", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"expo-splash-screen/@expo/prebuild-config/@expo/image-utils/getenv": ["getenv@2.0.0", "https://registry.npmmirror.com/getenv/-/getenv-2.0.0.tgz", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="],
"expo/@expo/config-plugins/@expo/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="],
"expo/@expo/config-plugins/@expo/plist/xmlbuilder": ["xmlbuilder@15.1.1", "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="],

View File

@ -1,6 +1,7 @@
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { ArrowLeft } from 'lucide-react';
import { router } from 'expo-router';
import { Colors, Spacing, FontSize, Layout } from '@/constants/theme';
interface CommonHeaderProps {
@ -23,9 +24,7 @@ export const CommonHeader: React.FC<CommonHeaderProps> = ({
onBack();
return;
}
if (typeof window !== 'undefined' && window.history) {
window.history.back();
}
router.back();
};
return (

View File

@ -122,7 +122,7 @@ export function TemplateCard({
)}
{template.category && (
<View style={styles.watermark} className='template-category'>
<View style={styles.watermark}>
<View style={styles.categoryBadge}>
<ThemedText style={styles.categoryText}>
{template.category.name}
@ -132,7 +132,7 @@ export function TemplateCard({
)}
{template.tags.length > 0 && (
<View style={styles.tagOverlay} className='template-tags'>
<View style={styles.tagOverlay}>
{template.tags.slice(0, 2).map((tag) => (
<View key={tag.id} style={styles.tagBadge}>
<ThemedText style={styles.tagText}>

View File

@ -41,7 +41,7 @@ export function UserCountBadge({
const displayText = formatCount(count);
return (
<View className='UserCountBadge' style={[styles.badge, { backgroundColor: badgeColor, ...badgeSize }, style]}>
<View style={[styles.badge, { backgroundColor: badgeColor, ...badgeSize }, style]}>
{showIcon && (
<IconSymbol
name="person.fill"

View File

@ -2,23 +2,23 @@ import * as SecureStore from "expo-secure-store";
import { Platform } from "react-native";
interface Storage {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
removeItem(key: string): Promise<void>;
}
class WebStorage implements Storage {
getItem(key: string): string | null {
async getItem(key: string): Promise<string | null> {
if (typeof window === "undefined") return null;
return window.localStorage.getItem(key);
}
setItem(key: string, value: string) {
async setItem(key: string, value: string): Promise<void> {
if (typeof window === "undefined") return;
window.localStorage.setItem(key, value);
}
removeItem(key: string) {
async removeItem(key: string): Promise<void> {
if (typeof window === "undefined") return;
console.log(`[WebStorage] Removing key: ${key}`);
window.localStorage.removeItem(key);
@ -27,18 +27,18 @@ class WebStorage implements Storage {
}
class NativeStorage implements Storage {
getItem(key: string): string | null {
return SecureStore.getItem(key);
async getItem(key: string): Promise<string | null> {
return await SecureStore.getItemAsync(key);
}
setItem(key: string, value: string) {
SecureStore.setItem(key, value);
async setItem(key: string, value: string): Promise<void> {
await SecureStore.setItemAsync(key, value);
}
removeItem(key: string) {
async removeItem(key: string): Promise<void> {
console.log(`[NativeStorage] Removing key: ${key}`);
SecureStore.setItem(key, "");
console.log(`[NativeStorage] Key set to empty string`);
await SecureStore.deleteItemAsync(key);
console.log(`[NativeStorage] Key removed`);
}
}

View File

@ -25,8 +25,11 @@
"better-auth": "1.3.27",
"eas-cli": "^16.22.0",
"expo": "54.0.23",
"expo-asset": "~12.0.9",
"expo-audio": "~1.0.14",
"expo-clipboard": "~8.0.7",
"expo-constants": "~18.0.10",
"expo-crypto": "~15.0.7",
"expo-dev-client": "~6.0.17",
"expo-file-system": "~19.0.17",
"expo-font": "~14.0.9",

6
todo.md Normal file
View File

@ -0,0 +1,6 @@
/plan 检查代码中不符合expo/react-native最佳实践规范的代码如div/video/img等只有h5中才有的标签没有适配多平台等问题
我的目标是三个端正常运行:
1. h5 web 端
2. android 端
3. ios 端