8

I am trying to change the UI just before the user leaves the app (user is in multi-tasking view or switches to some other app). To be more specific when user leaves the app I want to add a fullscreen view with the app logo.

I am using AppState for that.

On iOS it works as expected: in multitasking view app gets inactive state and once switched to other app state goes to background. When state is inactive I can still change UI.

However, on Android the state is either active or background. Problem is that in background state I cannot change the UI anymore.

Is this a bug on Android? If not, what are my options to get it working on Android.

Thanks.

algizmo
  • 81
  • 1
  • 3
  • 2
    Its not a bug. Android implementation of AppState component has only 'active' and 'background' state. Just curious, why do you want to show a fullscreen view with the app logo when user is about the leave the app? – Jickson Nov 03 '16 at 16:21
  • 3
    I want to show it so that sensitive data is not visible in the multitasking view. I guess I need to dig in to native stuff. – algizmo Nov 04 '16 at 07:10
  • i have a same problem. any help will be appreciated – Emad Bayat Oct 20 '19 at 14:01
  • @algizmo if you want to ensure that no sensitive data is displayed, you should not rely on code - your app might be killed without any chance to execute code. What you should do is to prevent screenshots. This can be done by setting the SECURE flag on the window: https://stackoverflow.com/questions/28606689/how-to-prevent-screen-capture-in-android; but I don't know if react has support for that – Kurt Huwig Feb 13 '20 at 12:47

2 Answers2

8

If you need to, you can simulate the same states as iOS by adding some code to MainActivity.java to listen to its lifecycle events

//onResume = 'active'  
//onPause = 'inactive'  
//onStop = 'background' 

@Override
public void onResume() {
    super.onResume();
    ReactContext reactContext = getReactInstanceManager().getCurrentReactContext();
    WritableMap params = Arguments.createMap();
    params.putString("event", "active");

    // when app starts reactContext will be null initially until bridge between Native and React Native is established
    if(reactContext != null) {
        getReactInstanceManager().getCurrentReactContext()
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
            .emit("ActivityStateChange", params);
    }
}

@Override
public void onPause() {
    super.onPause();
    ReactContext reactContext = getReactInstanceManager().getCurrentReactContext();
    WritableMap params = Arguments.createMap();
    params.putString("event", "inactive");

    if(reactContext != null) {
        getReactInstanceManager().getCurrentReactContext()
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("ActivityStateChange", params);
    }
}

@Override
public void onStop() {
    super.onStop();
    ReactContext reactContext = getReactInstanceManager().getCurrentReactContext();
    WritableMap params = Arguments.createMap();
    params.putString("event", "background");

    if(reactContext != null) {
        getReactInstanceManager().getCurrentReactContext()
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("ActivityStateChange", params);
    }
}

Then in your JS listen to these lifecycle changes using DeviceEventEmitter

const nativeEventListener = DeviceEventEmitter.addListener('ActivityStateChange',
  (e)=>{
      console.log(e.event);
})
Brien Crean
  • 2,317
  • 5
  • 19
  • 42
  • I don't see any difference to this and react native's implementation. It doesn't consider fragments https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java – evanjmg Mar 08 '18 at 16:36
  • It looks different to me; he's emitting "inactive" onPause whereas react native emits "background". He then emits "background" onStop. That said, I tried this and it didn't work / correctly simulate iOS appstate behavior. – cbartondock Apr 02 '18 at 05:07
0

For android you can use 'background' instead of 'inactive' like this:

  AppState.addEventListener('change', state => {

  if ( state === 'background') {
    //write your code here
   }

});
Vishal Dhaduk
  • 474
  • 5
  • 13