Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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 this issue Jul 12, 2024 · 3 comments
Labels
API: AppState Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Platform: Android Android applications.

Comments

@ashwinkumar6
Copy link

ashwinkumar6 commented Jul 12, 2024

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 (
...
<Button title="addAppStateListener" onPress={addAppStateListener} />
)
  1. Build on Android/iOS, generate apk/app and install on emulator/simulator (PROD).
  2. Click the addAppStateListener button and notice that the listener is NOT automatically fired with "active" when the listener is added.
  3. Comment the line console.log('INITIAL', AppState.currentState); and rebuild, re-install app.
  4. Click the addAppStateListener button and notice that the listener IS automatically fired with "active" when the listener is added

React Native Version

0.74.3 (current latest)

Affected Platforms

Other (please specify)
Android and iOS PROD

Output of npx react-native info

System:
  OS: macOS 14.5
  CPU: (10) arm64 Apple M1 Pro
  Memory: 89.75 MB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.20.4
    path: ~/.nvm/versions/node/v18.20.4/bin/node
  Yarn:
    version: 1.22.22
    path: ~/.nvm/versions/node/v18.20.4/bin/yarn
  npm:
    version: 10.7.0
    path: ~/.nvm/versions/node/v18.20.4/bin/npm
  Watchman:
    version: 2023.12.04.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.12.1
    path: /usr/local/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.2
      - iOS 17.2
      - macOS 14.2
      - tvOS 17.2
      - visionOS 1.0
      - watchOS 10.2
  Android SDK:
    API Levels:
      - "33"
      - "34"
    Build Tools:
      - 30.0.3
      - 33.0.0
      - 33.0.1
      - 34.0.0
    System Images:
      - android-33 | Google APIs ARM 64 v8a
      - android-34 | Google APIs ARM 64 v8a
      - android-35 | Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2022.3 AI-223.8836.35.2231.10671973
  Xcode:
    version: 15.2/15C500b
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.9
    path: /Users/ashwsrir/.jenv/shims/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.3
    wanted: 0.74.3
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Stacktrace or Logs

When listener is added for the first time in dev vs prod. (make sure to comment the console.log('INITIAL', AppState.currentState)on app)

dev

Running "androidAppStateIssue
listener is added

prod

Running "androidAppStateIssue
listener is added
nextAppState', 'active' <== additional event fired

Reproducer

https://github.com/ashwinkumar6/androidAppStateIssue

Screenshots and Videos

No response

@shubhamguptadream11
Copy link
Contributor

@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

public @Nullable NativeModule getModule(String name, ReactApplicationContext context) {

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 cortinico added Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. and removed Needs: Triage 🔍 labels Jul 15, 2024
@cortinico
Copy link
Contributor

@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 ashwinkumar6 changed the title AppState 'change' fires redundant 'active' when app is already active the first time the listener is added on Android Prod AppState 'change' fires redundant 'active' when app is already active the first time the listener is added on Android iOS Prod Jul 15, 2024
@ashwinkumar6
Copy link
Author

ashwinkumar6 commented Jul 15, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: AppState Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Platform: Android Android applications.
Projects
None yet
Development

No branches or pull requests

3 participants