feat: implement app update checks and add app configuration file

This commit is contained in:
imeepos 2026-01-27 11:52:59 +08:00
parent 533b58ccf4
commit 3bc113bf9c
3 changed files with 170 additions and 2 deletions

121
app.config.js Normal file
View File

@ -0,0 +1,121 @@
export const PROJECT_ID = '97a8e5b1-e6e8-45aa-ad95-f273b6c307ef'
export const APPNAME = 'popcore'
export const EXPO_PROJECT = 'popcore'
export const SCHEME = 'popcore'
export const EXPO_OWER = 'bowong'
export const ANDROID_ID = 'com.bowong.popcore'
export const IOS_ID = ANDROID_ID
// 原生版本,原生代码变更时需要更新此版本号
export const VERSION = '1.0.0'
// JavaScript版本JS代码变更时需要更新此版本号
export const APP_VERSION = 'dev202601271200'
export default ({ config }) => {
return {
...config,
expo: {
name: APPNAME,
slug: EXPO_PROJECT,
version: VERSION,
orientation: 'portrait',
icon: './assets/images/icon.png',
scheme: SCHEME,
userInterfaceStyle: 'automatic',
owner: EXPO_OWER,
newArchEnabled: true,
ios: {
supportsTablet: true,
infoPlist: {
NSBluetoothPeripheralUsageDescription:
'This app uses Bluetooth to act as a peripheral device for testing and development purposes.',
ITSAppUsesNonExemptEncryption: false,
},
bundleIdentifier: IOS_ID,
},
android: {
adaptiveIcon: {
backgroundColor: '#E6F4FE',
foregroundImage: './assets/images/android-icon-foreground.png',
backgroundImage: './assets/images/android-icon-background.png',
monochromeImage: './assets/images/android-icon-monochrome.png',
},
edgeToEdgeEnabled: true,
predictiveBackGestureEnabled: false,
permissions: [
'android.permission.BLUETOOTH',
'android.permission.BLUETOOTH_ADMIN',
'android.permission.BLUETOOTH_SCAN',
'android.permission.BLUETOOTH_CONNECT',
'android.permission.BLUETOOTH_ADVERTISE',
'android.permission.ACCESS_FINE_LOCATION',
'android.permission.READ_EXTERNAL_STORAGE',
'android.permission.WRITE_EXTERNAL_STORAGE',
'android.permission.READ_MEDIA_VISUAL_USER_SELECTED',
'android.permission.ACCESS_MEDIA_LOCATION',
'android.permission.READ_MEDIA_IMAGES',
'android.permission.READ_MEDIA_VIDEO',
'android.permission.READ_MEDIA_AUDIO',
'android.permission.RECORD_AUDIO',
],
package: ANDROID_ID,
},
web: {
output: 'static',
favicon: './assets/images/favicon.png',
bundler: 'metro',
},
plugins: [
'expo-router',
[
'react-native-ble-plx',
{
isBackgroundEnabled: true,
modes: ['peripheral', 'central'],
bluetoothAlwaysPermission: 'Allow $(PRODUCT_NAME) to connect to bluetooth devices',
},
],
[
'expo-media-library',
{
photosPermission: 'Allow $(PRODUCT_NAME) to access your photos.',
savePhotosPermission: 'Allow $(PRODUCT_NAME) to save photos.',
isAccessMediaLocationEnabled: true,
},
],
[
'expo-image-picker',
{
photosPermission: 'The app accesses your photos to let you upload your avatar or post images.',
},
],
],
experiments: {
typedRoutes: true,
reactCompiler: true,
},
extra: {
router: {},
eas: {
projectId: PROJECT_ID,
},
},
runtimeVersion: {
policy: 'appVersion',
},
updates: {
url: `https://u.expo.dev/${PROJECT_ID}`,
fallbackToCacheTimeout: 0,
checkAutomatically: 'NEVER',
},
},
}
}

View File

@ -6,7 +6,8 @@ import { StatusBar } from 'expo-status-bar'
import { useEffect } from 'react'
import 'react-native-reanimated'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { View, ActivityIndicator } from 'react-native'
import { View, ActivityIndicator, AppState } from 'react-native'
import * as Updates from 'expo-updates'
import { useColorScheme } from '@/hooks/use-color-scheme'
import { KeyboardProvider } from 'react-native-keyboard-controller'
@ -112,6 +113,48 @@ export default function RootLayout() {
function Providers({ children }: { children: React.ReactNode }) {
const colorScheme = useColorScheme()
// 热更新检查
useEffect(() => {
// 检查更新的函数
async function checkForUpdates() {
// 开发环境不检查更新
if (__DEV__) return
try {
const update = await Updates.checkForUpdateAsync()
if (update.isAvailable) {
await Updates.fetchUpdateAsync()
// 提示用户重启应用
;(global as any).toast?.show({
type: 'success',
message: '发现新版本,即将重启应用',
})
// 延迟重启,让用户看到提示
setTimeout(() => {
Updates.reloadAsync()
}, 2000)
}
} catch (error) {
console.error('检查更新失败:', error)
}
}
// App 启动时检查
checkForUpdates()
// 监听 App 状态变化,从后台返回前台时检查
const subscription = AppState.addEventListener('change', (nextAppState) => {
if (nextAppState === 'active') {
checkForUpdates()
}
})
return () => {
subscription.remove()
}
}, [])
return (
<SafeAreaProvider>
<GestureHandlerRootView style={{ flex: 1 }}>

View File

@ -16,7 +16,11 @@
"lint": "expo lint",
"test": "./node_modules/.bin/jest",
"test:watch": "./node_modules/.bin/jest --watch",
"test:coverage": "./node_modules/.bin/jest --coverage"
"test:coverage": "./node_modules/.bin/jest --coverage",
"update:dev": "eas update --branch development --message",
"update:preview": "eas update --branch preview --message",
"update:production": "eas update --branch production --message",
"update:auto": "eas update --auto"
},
"dependencies": {
"@better-auth/expo": "1.3.34",