Changing the iOS task switcher preview image in React Native

Dan Guilak // Jan 11th, 2017


Want to skip straight to the code? I wrote this all up in a sample React Native app on GitHub

We've been using React Native to write the iOS version of ughMoney, and aside from a few gotchas it's been a great experience. We were already using React on our frontend, so it's been a mostly trivial exercise to translate from the latter to the former. The really fun stuff has been figuring out how to accomplish all the cool stuff that's specific to mobile development.

Since our platform deals with personal financial data, we'd like to be able to obscure the preview view in the task switcher, like 1Password or Chase do in their apps.

Demo of changing preview image in task switcher

As it turns out this ends up being a pretty easy exercise in React Native. Basically we'll be using AppState to determine when the app is active and inactive, and rendering different views depending on that.

We'll start by including the correct modules and our initial view, as is shown in the AppState example:

import React, { Component } from 'react';  
import { AppState, Text, View } from 'react-native';

class App extends Component {  
  render() {
    return (
      <View>
        <Text>Sensitive Information</Text>
      </View>
    )
  }
}

Now we'll add an AppState listener in componentDidMount that will trigger a function and we'll remove that listener on componentWillUnmount:

componentDidMount() {  
  AppState.addEventListener('change', this._handleAppStateChange.bind(this));
}

componentWillUnmount() {  
  AppState.removeEventListener('change', this._handleAppStateChange.bind(this));
}

render() {  
  ...
}

And we'll make sure to add the actual this._handleAppStateChange private function:

_handleAppStateChange(currentAppState) {  
  this.setState({ currentAppState, });
}

Now we'll modify the render method in our component to show a different view when the currentAppState is something other than active—i.e., inactive or background:

render() {  
  if (this.state.currentAppState !== 'active') {
    return (
      <View>
        <Text>Unimportant Noninformation</Text>
      </View>
    )
  }
   return (
    <View>
      <Text>Sensitive Information</Text>
    </View>
  )
}

And of course it'd probably be better form just to write the 'inactive' view as a separate component.

Bonus: if you've set up a launch image for your app, you can render that image as your preview screen by using the Image component:

import React, { Component } from 'react';  
import { Image } from 'react-native';

var SCREEN_WIDTH = require('Dimensions').get('window').width;  
var SCREEN_HEIGHT = require('Dimensions').get('window').height;

export default class Inactive extends Component {  
  render() {
    // Just going to use the same image we do for LaunchImage
    return (
      <Image source={{uri: 'LaunchImage'}} style={{width: SCREEN_WIDTH, height: SCREEN_HEIGHT}} />
    )
  }
}

Which will work perfectly for any screen size as long as they're all accounted for in your LaunchImages.launchimage in Images.xcassets.

The full source for this example is available on GitHub.