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

When Modal Component renders then AppState blur event listener calls in Android #36865

Open
ims7inc opened this issue Apr 11, 2023 · 15 comments
Open
Labels
API: AppState Component: Modal Needs: Attention Issues where the author has responded to feedback.

Comments

@ims7inc
Copy link

ims7inc commented Apr 11, 2023

Description

When Modal/Alert component renders in our React Native App the App State goes blur

React Native Version

0.71.6

Output of npx react-native info

info Fetching system and libraries information...
System:
OS: macOS 12.6.1
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 81.42 MB / 16.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 16.15.0 - ~/.nvm/versions/node/v16.15.0/bin/node
Yarn: 1.22.0 - /usr/local/bin/yarn
npm: 8.5.5 - ~/.nvm/versions/node/v16.15.0/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.3 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 21.4, iOS 16.0, macOS 12.3, tvOS 16.0, watchOS 9.0
Android SDK: Not Found
IDEs:
Android Studio: 2021.2 AI-212.5712.43.2112.8512546
Xcode: 14.0.1/14A400 - /usr/bin/xcodebuild
Languages:
Java: 11.0.15 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.6 => 0.71.6
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Steps to reproduce

When Modal/Alert component renders in our React Native App the App State goes blur

AppState.addEventListener('blur', callback);

here this callback method is triggering

Snack, code example, screenshot, or link to a repository

/**

`/**

  • Sample React Native App

  • https://github.com/facebook/react-native

  • @Format
    */

     import React, {useEffect, useState} from 'react';
     import {
       SafeAreaView,
       StatusBar,
       Text,
       useColorScheme,
       Modal,
       TouchableOpacity,
       AppState,
       View,
     } from 'react-native';
     
     import {Colors} from 'react-native/Libraries/NewAppScreen';
     
     function App(): JSX.Element {
       const isDarkMode = useColorScheme() === 'dark';
       const [isVisible, setVisible] = useState(false);
     
       useEffect(() => {
         const blurEventListener = AppState.addEventListener('blur', () => {
           console.log('blur event trigger');
         });
         const focusEventListener = AppState.addEventListener('focus', () => {
           console.log('focus event trigger');
         });
         return () => {
           focusEventListener && focusEventListener.remove();
           blurEventListener && blurEventListener.remove();
         };
       }, []);
     
       const backgroundStyle = {
         backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
         flex: 1,
       };
     
       return (
         <SafeAreaView style={backgroundStyle}>
           <StatusBar
             barStyle={isDarkMode ? 'light-content' : 'dark-content'}
             backgroundColor={backgroundStyle.backgroundColor}
           />
           <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
             <TouchableOpacity onPress={() => setVisible(!isVisible)}>
               <Text>Open Modal</Text>
             </TouchableOpacity>
           </View>
     
           <Modal visible={isVisible}>
             <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
               <TouchableOpacity onPress={() => setVisible(!isVisible)}>
                 <Text>Close Modal</Text>
               </TouchableOpacity>
             </View>
           </Modal>
         </SafeAreaView>
       );
     }
     
     export default App;
    

`

@github-actions github-actions bot added the Type: Unsupported Version Issues reported to a version of React Native that is no longer supported label Apr 11, 2023
@github-actions
Copy link

⚠️ Unsupported Version of React Native
ℹ️ It looks like your issue or the example you provided uses an unsupported version of React Native. Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please upgrade to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on StackOverflow to get further community support.

@ims7inc ims7inc changed the title When Modal Component renders then AppState blur event listener calls When Modal Component renders then AppState blur event listener calls in Android Apr 11, 2023
@ims7inc
Copy link
Author

ims7inc commented Apr 11, 2023

Same issue with latest React Native version also

@github-actions github-actions bot added Needs: Attention Issues where the author has responded to feedback. and removed Needs: Author Feedback labels Apr 11, 2023
@ims7inc
Copy link
Author

ims7inc commented Apr 11, 2023

⚠️ Unsupported Version of React Native
ℹ️ It looks like your issue or the example you provided uses an unsupported version of React Native. Due to the number of issues we receive, we're currently only accepting new issues against one of the supported versions. Please upgrade to latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If you cannot upgrade, please open your issue on StackOverflow to get further community support.

tried in Latest React Native version also

@ims7inc
Copy link
Author

ims7inc commented Apr 11, 2023

My requirement is like, When App will goes to background i want to hide the Screen content and when the app will comes to foreground i want to show the content by setting and clearing FLAG_SECURE. but focus is changing when Modal/Alert components render in screen

@OverRide onWindowFocusChanged method is triggering when Modal component triggers

I tried with onPause() and onResume() also but onPause method is triggering with delay so screen content is not hidden when App goes background

@cortinico cortinico removed the Type: Unsupported Version Issues reported to a version of React Native that is no longer supported label Apr 11, 2023
@ChiBao284
Copy link

Same issue

@sorrelsjack
Copy link

I have the same issue, as well as the same use case. I did do some deep diving into the Android code, and from my understanding, this seems to be caused by the fact that the React Native Modal component is based off the Android Dialog class: https://github.com/facebook/react-native/blob/714b502b0c7a5f897432dbad388c02d3b75b4689/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ModalHostShadowNode.java

I'm going to keep looking to see if I can figure out a workaround or something.

@BishoSBA
Copy link

BishoSBA commented Aug 1, 2023

Was any solution found for this issue?
I am facing it currently as well

@mdcuk34
Copy link

mdcuk34 commented Sep 6, 2023

Facing the same issue as well :( - did anyone find a work around?

@samstoppani-tred
Copy link

Same thing is happening for me too :(

@andydotdaniel
Copy link

In case people still need help on this. I had the same exact requirements as @ims7inc and found a workaround.

The workaround involved building my own Android native module, and showing a native Android dialog, with the following steps:

  1. I detected two events: "home" and "recent apps" button presses which put the app in background. The answer in this StackOverflow thread shows a good way of doing that.
  2. Create a custom class that extends from the Android Dialog class. Set this class up so your dialog takes up the full screen and is just a solid background or whatever you want to hide the screen content. Override the onWindowFocusChanged method in this class to close the dialog when focus is changed to true.
  3. Use the button press callbacks from step 1 to add the FLAG_SECURE flag for when "home" is pressed, and to show the dialog from step 2 when "recent apps" button is pressed (so that it overlays any other existing modals). If you're developing for <= Android 11 (Red Velvet Cake and below), then add FLAG_SECURE instead of the dialog.
  4. Clear the FLAG_SECURE flag using onResume().
  5. The dialog will close itself after you come back to foreground from "recents screen" because the implemented onWindowFocusChanged() will be called, and onResume() is always called when coming back from home (but not necessarily when from recents which is why we need these two different implementations).

If you're wondering why we don't just show the dialog when pressing "home" instead of using FLAG_SECURE, the reason is because there's a delay and the dialog is not shown in time before the app dismisses when pressing home.

If you're wondering why we don't just use FLAG_SECURE for everything, it's because in >= Android 12 (Snow Cone), when pressing the "recents apps" button, I realized that the app isn't actually going in to the background yet (onPause() is not called), so whatever is using the FLAG_SECURE flag won't be called yet. Behavior is different for <= Android 11.

Trying to do this through React led me to nowhere. This was the best approach I could come up with. Hope it helps!

@ys-sherzad
Copy link

Any proper solution for this?

@ys-sherzad
Copy link

@andydotdaniel Mind if I ask to share your solution

@3KINGZ
Copy link

3KINGZ commented May 2, 2024

any work around to this @andydotdaniel @ys-sherzad

@douglasjunior
Copy link

On Android, the background state means that the React Native Activity is in background, and not necessary the entire app.

To handle this, I created a package that implements the Android Lifecycle API for React Native: https://github.com/douglasjunior/react-native-applifecycle

Why Use This?

The original AppState API provided by React Native behaves differently between Android and iOS, particularly regarding the background state:

  • On iOS, the background state signifies that the entire app is in the background.
  • On Android, the background state indicates that the React Native Activity is in the background, which might not necessarily mean the entire app is in the background.

By using react-native-applifecycle, you can handle these differences seamlessly across both platforms, ensuring that the state background will be dispatched only when the entire app is in background.

@samstoppani-tred
Copy link

@douglasjunior... you're a legend! 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: AppState Component: Modal Needs: Attention Issues where the author has responded to feedback.
Projects
None yet
Development

No branches or pull requests