mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[APP-107] OTA updates (#587)

* add 1000ms fallbackToCacheTimeout

* add listener via useOTAUpdate hook and show modal if update is available

* finish expo-updates setup

* setup useOTAUpdate hook

* add 1000ms fallbackToCacheTimeout

* add listener via useOTAUpdate hook and show modal if update is available

* finish expo-updates setup

* setup useOTAUpdate hook

* add OTA updates

* Update build.md

* temporarily disable ota updates

* refactor useOTAUpdate code

authored by

Ansh and committed by
GitHub
ba4bb46c ad4eaf5e

+95 -3
+10 -2
app.json
··· 5 5 "scheme": "bluesky", 6 6 "owner": "blueskysocial", 7 7 "version": "1.29.0", 8 + "runtimeVersion": { 9 + "policy": "appVersion" 10 + }, 8 11 "orientation": "portrait", 9 12 "icon": "./assets/icon.png", 10 13 "userInterfaceStyle": "light", ··· 63 66 "web": { 64 67 "favicon": "./assets/favicon.png" 65 68 }, 69 + "updates": { 70 + "enabled": true, 71 + "fallbackToCacheTimeout": 1000, 72 + "url": "https://u.expo.dev/55bd077a-d905-4184-9c7f-94789ba0f302" 73 + }, 66 74 "plugins": [ 67 75 "expo-localization", 68 76 "react-native-background-fetch", 77 + "sentry-expo", 69 78 [ 70 79 "expo-build-properties", 71 80 { ··· 79 88 { 80 89 "username": "blueskysocial" 81 90 } 82 - ], 83 - "sentry-expo" 91 + ] 84 92 ], 85 93 "extra": { 86 94 "eas": {
+5
docs/build.md
··· 115 115 --dist <iOS Update ID> \ 116 116 --rewrite \ 117 117 dist/bundles/main.jsbundle dist/bundles/ios-<hash>.map` 118 + 119 + ### OTA updates 120 + To create OTA updates, run `eas update` along with the `--branch` flag to indicate which branch you want to push the update to, and the `--message` flag to indicate a message for yourself and your team that shows up on https://expo.dev. ALl the channels (which make up the options for the `--branch` flag) are given in `eas.json`. [See more here](https://docs.expo.dev/eas-update/getting-started/) 121 + 122 + The clients which can receive an OTA update is governed by the `runtimeVersion` property in `app.json`. Right now, it is set so that only apps with the same `appVersion` (same as `version` property in `app.json`) can receive the update and install it. However, we can manually set `"runtimeVersion": "1.34.0"` or anything along those lines as well. This is useful if very little native code changes from update-to-update. If we are manually setting `runtimeVersion`, we should increment the version each time native code is changed. [See more here](https://docs.expo.dev/eas-update/runtime-versions/)
+3
src/lib/app-info.ts
··· 1 1 import VersionNumber from 'react-native-version-number' 2 + import * as Updates from 'expo-updates' 3 + export const updateChannel = Updates.channel 4 + 2 5 export const appVersion = `${VersionNumber.appVersion} (${VersionNumber.buildVersion})`
+74
src/lib/hooks/useOTAUpdate.ts
··· 1 + import * as Updates from 'expo-updates' 2 + import {useCallback, useEffect} from 'react' 3 + import {AppState} from 'react-native' 4 + import {useStores} from 'state/index' 5 + 6 + export function useOTAUpdate() { 7 + const store = useStores() 8 + 9 + // HELPER FUNCTIONS 10 + const showUpdatePopup = useCallback(() => { 11 + store.shell.openModal({ 12 + name: 'confirm', 13 + title: 'Update Available', 14 + message: 15 + 'A new version of the app is available. Please update to continue using the app.', 16 + onPressConfirm: async () => { 17 + Updates.reloadAsync().catch(err => { 18 + throw err 19 + }) 20 + }, 21 + }) 22 + }, [store.shell]) 23 + const checkForUpdate = useCallback(async () => { 24 + store.log.debug('useOTAUpdate: Checking for update...') 25 + try { 26 + // Check if new OTA update is available 27 + const update = await Updates.checkForUpdateAsync() 28 + // If updates aren't available stop the function execution 29 + if (!update.isAvailable) { 30 + return 31 + } 32 + // Otherwise fetch the update in the background, so even if the user rejects switching to latest version it will be done automatically on next relaunch. 33 + await Updates.fetchUpdateAsync() 34 + // show a popup modal 35 + showUpdatePopup() 36 + } catch (e) { 37 + console.error('useOTAUpdate: Error while checking for update', e) 38 + store.log.error('useOTAUpdate: Error while checking for update', e) 39 + } 40 + }, [showUpdatePopup, store.log]) 41 + const updateEventListener = useCallback( 42 + (event: Updates.UpdateEvent) => { 43 + store.log.debug('useOTAUpdate: Listening for update...') 44 + if (event.type === Updates.UpdateEventType.ERROR) { 45 + throw new Error(event.message) 46 + } else if (event.type === Updates.UpdateEventType.NO_UPDATE_AVAILABLE) { 47 + // Handle no update available 48 + // do nothing 49 + } else if (event.type === Updates.UpdateEventType.UPDATE_AVAILABLE) { 50 + // Handle update available 51 + // open modal, ask for user confirmation, and reload the app 52 + showUpdatePopup() 53 + } 54 + }, 55 + [showUpdatePopup, store.log], 56 + ) 57 + 58 + useEffect(() => { 59 + // ADD EVENT LISTENERS 60 + const updateEventSubscription = Updates.addListener(updateEventListener) 61 + const appStateSubscription = AppState.addEventListener('change', state => { 62 + if (state === 'active' && !__DEV__) { 63 + checkForUpdate() 64 + } 65 + }) 66 + 67 + // REMOVE EVENT LISTENERS (CLEANUP) 68 + return () => { 69 + updateEventSubscription.remove() 70 + appStateSubscription.remove() 71 + } 72 + }, []) // eslint-disable-line react-hooks/exhaustive-deps 73 + // disable exhaustive deps because we don't want to run this effect again 74 + }
+1 -1
src/view/screens/Settings.tsx
··· 445 445 </Link> 446 446 ) : null} 447 447 <Text type="sm" style={[styles.buildInfo, pal.textLight]}> 448 - Build version {AppInfo.appVersion} 448 + Build version {AppInfo.appVersion} {AppInfo.updateChannel} 449 449 </Text> 450 450 <View style={s.footerSpacer} /> 451 451 </ScrollView>
+2
src/view/shell/index.tsx
··· 18 18 import {isStateAtTabRoot} from 'lib/routes/helpers' 19 19 import {isAndroid} from 'platform/detection' 20 20 import {SafeAreaProvider} from 'react-native-safe-area-context' 21 + import {useOTAUpdate} from 'lib/hooks/useOTAUpdate' 21 22 22 23 const ShellInner = observer(() => { 23 24 const store = useStores() 25 + useOTAUpdate() // this hook polls for OTA updates every few seconds 24 26 const winDim = useWindowDimensions() 25 27 const safeAreaInsets = useSafeAreaInsets() 26 28 const containerPadding = React.useMemo(