Please provide the following:
- SDK Version: 35
- Platforms(Android/iOS/web/all):Android
I’m using the SplashScreen.preventAutoHide() and the SplashScreen.hide() so that I can load my assets as well has have an animated type splash screen for the user. As per the other countless threads I’ve read, iOS works as it should, both on the emulator/device expo apps and on the standalone app. But on android …
- emulator/device w/ expo - on every other load, there’s a white flicker between the splash screen and the actual app.
- on the standalone app - every load shows the white flicker but the flicker isn’t that long.
Here’s my source code for app.js
import React from 'react'
import { AppState, StatusBar, Platform } from 'react-native'
import { SplashScreen } from 'expo'
import { Block, GalioProvider } from 'galio-framework'
import { PersistGate } from 'redux-persist/integration/react'
import AppContainer from './src/navigation/Screens'
import { argonTheme } from './src/constants'
import { store, persistor } from './src/store/store'
import { Provider } from 'react-redux'
import { ApolloProvider } from 'react-apollo'
import { AppearanceProvider } from 'react-native-appearance'
import client from './src/data/apolloClient'
import {
setTopLevelNavigator,
navigate,
} from './src/navigation/NavigationService'
import {
listenForNotifications,
setUpChannel,
checkPermissions,
} from './src/data/notifications'
import AppLoader from './src/components/AppLoader'
import { setNotificationPermission } from './src/store/slices/deviceInfoSlice'
StatusBar.setBarStyle('dark-content')
if (Platform.OS === 'android') {
StatusBar.setTranslucent(true)
StatusBar.setBackgroundColor('transparent')
}
class App extends React.Component {
constructor(props) {
super(props)
SplashScreen.preventAutoHide()
}
state = {
appState: AppState.currentState,
}
componentDidMount() {
listenForNotifications(this.newPostNavigation)
setUpChannel()
AppState.addEventListener('change', this._handleAppStateChange)
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange)
}
newPostNavigation = (id, location) => {
navigate(location, { id })
}
checkNotificationStatus = async () => {
checkPermissions().then((results) => {
const reduxState = store.getState()
const { notificationPermission } = reduxState.deviceInfo
if (notificationPermission !== results) {
store.dispatch(setNotificationPermission(results))
}
})
}
// Sets a top level navigator to access navigation in root component
navigateWithUid = (navigatorRef) => {
setTopLevelNavigator(navigatorRef)
const reduxState = store.getState()
// Comment this conditional to disable auto navigation from onboarding screens
if (reduxState.deviceInfo && !reduxState.deviceInfo.deviceUid) {
navigate('OnBoarding', {})
}
}
//if application is in the background and user changes notification settings in their phone settings,
//this will catch the change and update the app
_handleAppStateChange = (nextAppState) => {
if (
this.state.appState.match(/inactive|background/) &&
nextAppState === 'active'
) {
this.checkNotificationStatus()
}
this.setState({ appState: nextAppState })
}
render() {
return (
<ApolloProvider client={client}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<GalioProvider theme={argonTheme}>
<AppLoader>
<AppearanceProvider>
<Block flex>
<AppContainer
ref={(navigatorRef) => this.navigateWithUid(navigatorRef)}
/>
</Block>
</AppearanceProvider>
</AppLoader>
</GalioProvider>
</PersistGate>
</Provider>
</ApolloProvider>
)
}
}
export default App
and here’s my source code for AppLoader that does the caching
import React, { Component } from 'react'
import { SplashScreen, AppLoading } from 'expo'
import { Asset } from 'expo-asset'
import {
Animated,
Platform,
StatusBar,
StyleSheet,
View,
Image,
} from 'react-native'
import * as Font from 'expo-font'
import { Images, Gifs } from '../constants'
const assetImages = [
Images.GoAnnualHorizontal,
Images.LogoBlueStacked,
Images.splashWhite,
]
const fonts = [
{ 'open-sans-regular': require('../../assets/font/OpenSans-Regular.ttf') },
{ 'open-sans-light': require('../../assets/font/OpenSans-Light.ttf') },
{ 'open-sans-bold': require('../../assets/font/OpenSans-Bold.ttf') },
]
function cacheFonts(fonts) {
return fonts.map((font) => Font.loadAsync(font))
}
function cacheImages(images) {
return images.map((image) => {
if (typeof image === 'string') {
return Image.prefetch(image)
} else {
return Asset.fromModule(image).downloadAsync()
}
})
}
export default class AppLoader extends Component {
constructor(props) {
super(props)
}
state = {
isReady: false,
splashAnimation: new Animated.Value(0),
splashAnimationComplete: false,
}
componentDidMount() {
this._loadResourcesAsync()
.then(() => this.setState({ isReady: true }))
.catch((error) =>
console.error(`Unexpected error thrown when loading: ${error}`)
)
}
_loadResourcesAsync = async () => {
const imageAssets = cacheImages([...assetImages])
const fontAssets = cacheFonts([...fonts])
return await Promise.all([...fontAssets, ...imageAssets])
}
render() {
const { isReady } = this.state
if (!isReady)
return (
<View style={{ flex: 1 }}>
<Image
source={require('../../assets/splash.png')}
style={{
width: undefined,
height: undefined,
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
resizeMode: 'cover',
}}
fadeDuration={0}
/>
</View>
)
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle='default' />}
{this.props.children}
{this._maybeRenderLoadingImage()}
</View>
)
}
_maybeRenderLoadingImage = () => {
if (this.state.splashAnimationComplete) {
return null
}
return (
<Animated.View
style={{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
opacity: this.state.splashAnimation.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
}),
}}
>
<Animated.Image
source={require('../../assets/splash.png')}
style={{
width: undefined,
height: undefined,
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
resizeMode: 'cover',
}}
onLoadEnd={this._animateOut}
fadeDuration={0}
/>
</Animated.View>
)
}
_animateOut = () => {
SplashScreen.hide()
Animated.timing(this.state.splashAnimation, {
toValue: 1,
delay: 100,
duration: 500,
useNativeDriver: true,
}).start(() => {
this.setState({ splashAnimationComplete: true })
})
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
})
Any help would be greatly appreciated!