react-native-navigation icon indicating copy to clipboard operation
react-native-navigation copied to clipboard

Android Hardware Back Button causes Blank Screen

Open idortulov opened this issue 3 years ago • 2 comments

🐛 Bug Report

Only on Android, when the user uses the Hardware Back Button and they are at the landing screen, the Activity closes. Then when the application is started again I see a blank screen. This happens only if I use the hardware back. If I minimize the application using the hardware home button, then there are no issues.

I read somewhere that I should use the events().registerAppLaunchedListener but that doesn't get invoked.

Have you read the Contributing Guidelines on issues?

Yes, I have read them.

To Reproduce

  1. Create a blank application using the React Native CLI
  2. Install the latest version of the navigation library
  3. Create a Bottom Navigation
  4. As the first tab create a Stack Navigator
  5. Press the hardware back button on the phone
  6. Enter the application again

ERROR: Blank screen.

NOTES: I am using a legacy project that somebody else wrote and I am trying to maintain/update it.

The way the bottom tab bar is created is very weird to me. I found that this code causes the tab bar to appear, however, without this code the tab bar is missing:

// hide the tab bar when navigating to screens that are not in tabBarScreens
Navigation.events().registerCommandListener((name, params) => {
let componentNames = params &&
    params.layout &&
    params.layout.data && [params.layout.data.name]

componentNames =
    componentNames ||
    (params &&
    params.layout &&
    Array.isArray(params.layout) &&
    params.layout
        .map((layout) => layout.data && layout.data.name)
        .filter((c) => c !== undefined))

if (componentNames && componentNames.length === 0) {
    componentNames = undefined
}

componentNames =
    componentNames ||
    (params &&
    params.layout &&
    params.layout.children &&
    params.layout.children
        .map((child) => child.data && child.data.name)
        .filter((c) => c !== undefined))

if (componentNames && componentNames.length === 0) {
    componentNames = undefined
}

componentNames =
    componentNames ||
    (params &&
    params.layout &&
    params.layout.root &&
    params.layout.root.children &&
    params.layout.root.children
        .map((child) => child.data && child.data.name)
        .filter((c) => c !== undefined))
console.log({ name, params })
switch (name) {
    case 'push':
    case 'showModal':
    if (componentNames && componentNames.length > 0) {
        if (
        getTabBarScreen(componentNames[componentNames.length - 1]) ===
        undefined
        ) {
        store.dispatch(setShouldBeVisible(false))
        screenStack.push({
            componentName: componentNames[componentNames.length - 1],
            tabBarVisible: false,
        })
        } else {
        screenStack.push({
            componentName: componentNames[componentNames.length - 1],
        })
        }
    }
    break
    case 'pop':
    case 'dismissModal':
    if (screenStack.length > 1) {
        screenStack.pop()
    }
    break
    case 'popToRoot':
    screenStack = [screenStack[0]]
    break
    case 'setRoot':
    case 'setStackRoot':
    if (componentNames && componentNames.length > 0) {
        screenStack = componentNames.map((c) => {
        return { componentName: c }
        })
    }
    break
}
})

The stack navigation is created as follows:

// This code is executed in the index.js file
let navStack = [
    {
        screenName: MainScreen.screenName(),
        passProps: {
            initial: true,
            navigateToRunning: true,
        },
    },
]
          
const createNavigationStack = (screenList) => {
  return screenList.map((item) => {
    return {
      component: {
        name: item.screenName,
        passProps: item.passProps,
        options: {
          animations: {
            setStackRoot: {
              enabled: false,
            },
          },
          popGesture: false,
          hardwareBackButton: {
            dismissModalOnPress: true,
            popStackOnPress: true,
            bottomTabsOnPress: 'previous',
          },
        },
      },
    }
  })
}
          
Navigation.setRoot(createNavigationStack(navStack))

I have no idea why things are done this way. The only workaround to my problem was to override the Native Back Handler and just disable it:

BackHandler.addEventListener('hardwareBackPress', () => true);

Expected behavior

I expect that the application will return to the last screen that was displayed when it is relaunched.

Actual Behavior

A Blank screen is shown

Your Environment

  • React Native Navigation version: 7.30.2
  • React Native version: 0.70.5
  • Platform(s) (iOS, Android, or both?): Android 11
  • Device info (Simulator/Device? OS version? Debug/Release?): Simulator + Samsung Galaxy S20 FE, both Debug and Release

Reproducible Demo

N/A, the code is proprietry.

Are you willing to resolve this issue by submitting a Pull Request?

  • ✖️   Yes, I have the time, and I know how to start.
  • ✖️   Yes, I have the time, but I don't know how to start. I would need guidance.
  • ✅   No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.

idortulov avatar Nov 23 '22 09:11 idortulov

Did you end up figure out why this is happening? I can reproduce the issue in 7.40.1

I thought this was related to codepush and ignored it, but just removed codepush and it was still the case in some scenarios.

If you have any details when digging into it, I would appreciate it, I want to look into this

birkir avatar Oct 28 '24 15:10 birkir

@birkir I don't think I figured it out in the end. It was for a project I did for a company I used to work for, so I do not have access to the source code. If memory serves me right, this was an issue only on Android. What I did to work around it was to use a Hardware backhandler and manually manage the stack. If my stack had only 1 item, I would send the app in the background, instead of poping the stack and getting to the black screen.

idortulov avatar Oct 30 '24 09:10 idortulov