wix / wix/react-native-navigation

Android Hardware Back Button causes Blank Screen

Open
#7,643 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

needs triage triage: bug
Dominant language
MDX
Stars
13.2k
Forks
2.6k
Avg merge
6d 2h
Merged PRs (30d)
1

Description

🐛 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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the navigation setup in index.js and the Android hardwareBackButton options, then follow the listed reproduction steps on the reported React Native and Android versions. Compare the relaunch behavior with the Native Back Handler workaround; done means relaunching after the hardware Back Button does not show a blank screen.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, javascript, react-native
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.