React-native-router-flux: Back navigation won't work on Android

Created on 16 Jul 2017  路  24Comments  路  Source: aksonov/react-native-router-flux

I've noticed that, on Android:

  • When moving from a screen to another, not only the back button won't be shown (as reported on #2023), but also the physical back button will put the app in background instead of leading to the previous screen.
  • When the app is put in foreground again, the initial screen is rendered, instead of previously opened screen.

All of these issues can be reproduced using the Example project.

Most helpful comment

I solved this way:
<Router backAndroidHandler={this.onBackPress}>
and:

onBackPress = () => {
    if (Actions.state.index === 0) {
      return false
    }
    Actions.pop()
    return true
}

All 24 comments

Sorry, I'm actively looking for Android contributor right now because I'm working on iOS app only.

A workaround for the Android hardware back button closing the app is to use react-native's BackHandler. Would be something like this:

Docs are here: https://facebook.github.io/react-native/releases/0.45/docs/backhandler.html

import React, { Component } from 'react'
import { BackHandler } from 'react-native'
import { Actions } from 'react-native-router-flux'

export default class Page extends Component {
  constructor (props) {
    super(props)
  }

  componentDidMount () {
    BackHandler.addEventListener('hardwareBackPress', () => this.backAndroid()) // Listen for the hardware back button on Android to be pressed
  }

  componentWillUnmount () {
    BackHandler.removeEventListener('hardwareBackPress', () => this.backAndroid()) // Remove listener
  }

  backAndroid () {
    Actions.pop() // Return to previous screen
    return true // Needed so BackHandler knows that you are overriding the default action and that it should not close the app
  }

  // ...other stuff
}

Thanks for the fast reply, @aksonov and @hofuchi! I'm going to take the day to investigate this issue a bit further.

Considering the current scenario, my initial hypothesis is that the scenes aren't being stacked correctly on Android. It would explain why it can't identify where to go when the app is put back in foreground and also won't pop when expected (or show the back button on header).

Do you think that this is a valid approach? 馃槉

Again, thanks for you help, @hofuchi! I'm already working on it. It seems that the initial issue displaying the back button is related to its positioning, as aksonov initially suggested on #2023.

The scenes are being correctly stacked, so the physical back button problem on android is something else. I hope to submit a pull request soon. 馃槃

Hey guys, I've just submitted a pull request with a fix for the issue #2023. It seems that, even though different from v3, it's expected that the back button action on android is going to be implemented by the user when using react-navigation (at least, this is what I could take out of this thread).

Following what was suggested by hofuchi and here, I'm handling the physical back button with:

import React, { Component } from 'react'
import { BackHandler } from 'react-native'
import { Actions } from 'react-native-router-flux'

class App extends Component {
  constructor (props) {
    super(props);
  }

  componentDidMount () {
    BackHandler.addEventListener('hardwareBackPress', this.onBackPress);
  }

  componentWillUnmount () {
    BackHandler.removeEventListener('hardwareBackPress', this.onBackPress);
  }

  onBackPress () {
    if (Actions.state.index === 0) {
      return false;
    }

    Actions.pop();
    return true;
  }

  // ...
}

@diegocouto We could also add it to v4 ('App' component within src/Router.js), could do you submit PR?

@aksonov Sure, I'm glad to help!

@diegocouto did you check it with Example app?

@quarryman Yep! It should look like this:

Register screen

@diegocouto are you on master or your PR branch?

Just did clean install on master and back button is still not there

@quarryman Example doesn't use master branch but latest beta, are you sure that you are using master?

@aksonov that was the issue.
It works after switching example router dependency to master
Do you think it makes sense to merge this fix into beta branch not to confuse new users trying example app.
It will at least prevent this issue reports from being submitted by those who try example.

@diegocouto thanx for a fix

The Actions.state.index always has the same value in the onBackPress (). This solution does not work for me.

I solved this way:
<Router backAndroidHandler={this.onBackPress}>
and:

onBackPress = () => {
    if (Actions.state.index === 0) {
      return false
    }
    Actions.pop()
    return true
}

In "react-native-router-flux" version ( 3.41.0 )
You can use ActionConst.RESET to exit the app from any Component.

import { Router, Scene , ActionConst } from 'react-native-router-flux'
<Router>
    <Scene duration={0} key="main" type={ActionConst.RESET}>
</Router>
const onBackAndroid = () => {
  return Actions.pop();
};

<Router backAndroidHandler={onBackAndroid}>
</Router>

How do you exit app without terminating the app? I think I have tried all the above combinations and app is terminated and must relaunch from scratch.

Users may be in the middle of uploading or downloading and this kills the process. I expect the Android back button to minimize app and show home NOT terminate it.

1) Anytime I return false from either the router backAndroidHandler or the React Native BackHandler, my app terminates and closes completely.
2) Calling BackHandler.exitApp() and returning true still terminates app.

When I try to resume, I see the splash screen so I know app is restarting from scratch.

Anytime the app the back handler returns false the app is shut down and closed completyely.

````

routerBackAndroidHandler = () => {
const result = Actions.pop();
console.log('dbg: Actions.pop()', result);

// returning false will close app completely
return true;

}
````

Using:
"react": "^16.2.0", "react-native": "^0.52.2", "react-native-router-flux": "4.0.0-beta.27",

I think this is because of Android behaviour.

On my end : When I exit the app with the backButton because my route stack is empty, the app exits but is not killed. If I come back quickly to the app, I will still be on my latest screen (which for me is a home page (with a type reset)).
If I open a new app or wait a bit, the app will start again from the beginning.

@Blapi A MainActivity.java fix was the only thing that prevented app from terminating.

````
import android.content.Intent;

public class MainActivity extends ReactActivity {

// Prevent back button from terminating app
// https://github.com/react-navigation/react-navigation/issues/1372#issuecomment-299432731
@Override
public void invokeDefaultOnBackPressed() {
moveTaskToBack(true);
}
````

Nice info to know, thanks

Firstly my BackHandler works fine, but when i'm on Home screen (consider as one or last screen) the app actually navigating to Sign in page(it's throwing the user out of application)
Below are my files

_### AppNavigatorContainer.js_

class AppNavigatorContainer extends Component {

addListener = createReduxBoundAddListener("root")

constructor(props) {
super(props)
this.state = {
didReceiveNotificationThatCanBeHandled: false,
notification: null,
didNetworkBecomeUnreachable: false
}
this.onBackPress = this.onBackPress.bind(this)
}
componentWillReceiveProps(nextProps) {
//TODO: Uncomment once VPN problem is fixed
// if (nextProps.isNetworkReachable !== this.props.isNetworkReachable) {
// this.state.didNetworkBecomeUnreachable = !nextProps.isNetworkReachable
// }
}

componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.onBackPress)
}

componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.onBackPress)
//TODO: Uncomment once VPN problem is fixed
// stopListening()
}

onBackPress() {
console.log(this.props);
const { dispatch, navigationState } = this.props
dispatch(NavigationActions.back());
return true;
}

_AppNavigator.js_

import React from 'react'
import {
StackNavigator,
addNavigationHelpers
} from 'react-navigation';
import stackConfiguration from './stackConfiguration'
import routeConfiguration from './routeConfiguration'

export const AppNavigator = StackNavigator(
routeConfiguration,
stackConfiguration
);

export default ({
dispatch,
navigationState,
addListener
}) => {
return (
dispatch,
state: navigationState,
addListener
})} />
)
}

can anyone respond to my previous comment please

I solved this way:
<Router backAndroidHandler={this.onBackPress}>
and:

onBackPress = () => {
    if (Actions.state.index === 0) {
      return false
    }
    Actions.pop()
    return true
}

Thanks @ecavalcant IT WORKS FOR ME. IM USING ROUTER FLUX V-4.0.1(STABLE). KEEP IT UP BRO GOD BLESS YOU. :)

Was this page helpful?
0 / 5 - 0 ratings