facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.05k stars 24.32k forks source link

AppState 'change' fires redundant 'active' when app is already active the first time the listener is added on Android iOS Prod #45418

Open ashwinkumar6 opened 3 months ago

ashwinkumar6 commented 3 months ago

Description

On Android and iOS PROD when the AppState listener 'change' is added the very first time it automatically also fires the listener with nextState as "active" even though the app is already "active".

This issue occurs specifically on Prod and not Dev. On Dev it works as expected where the listener is not fired the first time it's added. listener is only fired the first time when the app goes to the background.

EXPECTED BEHAVIOR: The behavior should be the same with dev and prod where the listener does not automatically fire with 'active' when it's added the very first time.

Steps to reproduce

  1. Create a new RN app with npx react-native init androidAppStateIssue
  2. Add the AppState 'change' listener on a button click as follows

    
    const addAppStateListener = () => {
    // read 'AppState.currentState' to register current state on prod
    // comment, uncomment this console.log to see difference on prod
    console.log('INITIAL', AppState.currentState);
    
    AppState.addEventListener('change', nextAppState => {
      console.log('nextAppState', nextAppState);
    });
    };

return ( ...

shubhamguptadream11 commented 3 months ago

@ashwinkumar6 I debugged this issue and here are my findings:

With new architecture enabled I found out that the way NativeModule are being initialised is different in debug and release builds.

In order to debug this I put a log here https://github.com/facebook/react-native/blob/65a3259f039416394d2b945ec10565d38b3cad9e/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java#L109

For debug build: All the mentioned native modules constructors are being called on app load it self.

In release builds: Only these SoundManager, NativeAnimatedModule, FrescoModule modules are being called on app load.

Now because of this in debug build: AppStateModule constructor is called on app load itself which calls onHostResume there only which calls triggerAppStateChangeEvent but since there are no listener added in RN side we didn’t get any log.

In release builds: When we click on button to add an eventListener then it firstly loads AppStateModule which calls onHostResume which triggerAppStateChangeEvent and since we have a listener added at that time on RN side we get a log.

I checked AppStateModule here we are using TurboModules to register it.

@cortinico I am just curious to know how it works differently in release and debug builds?

cortinico commented 3 months ago

@cortinico I am just curious to know how it works differently in release and debug builds?

All the native modules you find listed inside MainReactPackage are available to be used inside JS code.

@shubhamguptadream11 if you add a log on getModule as you pointed out, you're not checking if the module is loaded or not, but you're checking if someone from Javascript is accessing it or not.

I haven't investigated this further, but in Debug we do have more modules loaded (for example LogBoxes and the react-devtools debug overlay) which are not loaded in Release. That's most likely the reason why you see "less" calls to getModule.

ashwinkumar6 commented 3 months ago

Hi @cortinico @shubhamguptadream11,

Appreciate the quick response ! After some additional testing, I'm able to reproduce this issue on both Android and iOS PROD environments. I've updated the issue desc to reflect the same. Thank you