Skip to content

Commit

Permalink
fix: app freeze on splash screen
Browse files Browse the repository at this point in the history
  • Loading branch information
mstrk committed Nov 29, 2020
1 parent 0cb9bad commit e463db2
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 21 deletions.
59 changes: 42 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import 'react-native-gesture-handler'
import React from 'react'
import messaging from '@react-native-firebase/messaging'
import { AppRegistry, LogBox } from 'react-native'
import { App } from './src/App'
import messaging from '@react-native-firebase/messaging'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { MESSAGES_KEY } from 'constants/global'
import { name as appName } from './app.json'
import { onMessage } from 'store/auth/helpers'

if (__DEV__) {
LogBox.ignoreLogs([
// This warning occurs because we pass callbacks in some route navigations i.e. Dialog
// and because fuctions are not serializable, just remember taht state persistance and deep-linking
// features became unavailable for those screens
'Non-serializable values were found in the navigation state',
])

import('./src/util/reactotronConfig').then(() => console.log('Reactotron Configured'))
}

// This should be called as soon as possible
messaging().setBackgroundMessageHandler(async (message) => {
if (__DEV__) {
console.log('Background Message received:', JSON.stringify(message, null, 2))
}

onMessage(message)
// Save messages in the device to be fired once we get out of background - see App.tsx
try {
const messages = await AsyncStorage.getItem(MESSAGES_KEY)

if (messages == null) {
await AsyncStorage.setItem(MESSAGES_KEY, JSON.stringify([message]))

throw new Error(`Invalid ${MESSAGES_KEY} state after read called from setBackgroundMessageHandler`)
}

const parsed = JSON.parse(messages)

if (Array.isArray(parsed)) {
console.log('messages stored', parsed.length)
await AsyncStorage.setItem(MESSAGES_KEY, JSON.stringify([...parsed, message]))
} else {
await AsyncStorage.setItem(MESSAGES_KEY, JSON.stringify([message]))
}
} catch (error) {
if (__DEV__) {
console.log(error)
}
}
})

function HeadlessCheck ({ isHeadless }) {
Expand All @@ -31,6 +41,21 @@ function HeadlessCheck ({ isHeadless }) {
return null
}

require('react-native-gesture-handler')
const React = require('react')
const { App } = require('./src/App')

if (__DEV__) {
LogBox.ignoreLogs([
// This warning occurs because we pass callbacks in some route navigations i.e. Dialog
// and because fuctions are not serializable, just remember taht state persistance and deep-linking
// features became unavailable for those screens
'Non-serializable values were found in the navigation state',
])

import('./src/util/reactotronConfig').then(() => console.log('Reactotron Configured'))
}

return <App />
}

Expand Down
49 changes: 49 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React from 'react'
import { AppState, AppStateStatus } from 'react-native'
import { GS_WEB_CLIENT_ID } from '@env'
import { enableScreens } from 'react-native-screens'
import { GoogleSignin } from '@react-native-community/google-signin'
import { FirebaseMessagingTypes } from '@react-native-firebase/messaging'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { firebase as pfb } from '@react-native-firebase/perf'
import { firebase as afb } from '@react-native-firebase/analytics'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { MESSAGES_KEY } from 'constants/global'
import { StoreProvider } from 'store'
import { onMessage } from 'store/auth/helpers'
import { ThemeProvider } from 'components/ThemeProvider'
import { RootNavigator } from 'routes/RootNavigator'

Expand All @@ -22,6 +27,50 @@ if (!__DEV__) {
}

export const App = () => {
const appState = React.useRef(AppState.currentState)

const handleAppStateChange = async (nextState: AppStateStatus) => {
// fire all the messages that we stored when in background - see the root index.js
if (appState.current.match(/inactive|background/) && nextState === 'active') {
try {
const messages = await AsyncStorage.getItem(MESSAGES_KEY)

if (messages == null) {
await AsyncStorage.setItem(MESSAGES_KEY, JSON.stringify([]))

throw new Error(`Invalid ${MESSAGES_KEY} state after read`)
}

const parsed = JSON.parse(messages)

if (Array.isArray(parsed)) {
parsed.forEach((message: FirebaseMessagingTypes.RemoteMessage) => {
onMessage(message)
})

if (parsed.length) {
// Reset the messages stored
await AsyncStorage.setItem(MESSAGES_KEY, JSON.stringify([]))
}
}
} catch (error) {
if (__DEV__) {
console.log(error)
}
}
}

appState.current = nextState
}

React.useEffect(() => {
AppState.addEventListener('change', handleAppStateChange)

return () => {
AppState.removeEventListener('change', handleAppStateChange)
}
}, [])

return (
<SafeAreaProvider>
<StoreProvider>
Expand Down
2 changes: 2 additions & 0 deletions src/constants/global.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export const MESSAGES_KEY = '@messages'
16 changes: 12 additions & 4 deletions src/store/preferences/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Platform, StatusBar } from 'react-native'
import { AppState, Platform, StatusBar } from 'react-native'
import changeNavigationBarColor from 'react-native-navigation-bar-color'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { StoreonModule } from 'storeon'
Expand Down Expand Up @@ -59,17 +59,25 @@ export const preferences: StoreonModule<State, Events> = (store) => {
}

function updateSatusBar (themeType: ThemeType) {
// if the app is not active this function call is useless and can cause problems
if (AppState.currentState !== 'active') return

const { colors } = theme(themeType)
const isLightContent = themeType === 'dark'
const color = colors.surface

StatusBar.setBarStyle(isLightContent ? 'light-content' : 'dark-content', true)
try {
StatusBar.setBarStyle(isLightContent ? 'light-content' : 'dark-content', true)
} catch (error) {
if (__DEV__) {
console.error(error)
}
}

// Only possible on android
if (Platform.OS === 'android') {
StatusBar.setBackgroundColor(color, true)

try {
StatusBar.setBackgroundColor(color, true)
changeNavigationBarColor(color, !isLightContent, true)
} catch (error) {
if (__DEV__) {
Expand Down

0 comments on commit e463db2

Please sign in to comment.