I have put android back button exit the app functionality in my react native app in my home screen. But when I press android back button on other screens then also it is getting called.
componentDidMount() {
if (Platform.OS == "android") {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
this._setupGoogleSignin();
this._getUserDetails();
const { navigate } = this.props.navigation;
console.log("object url is", this.state.postsArray[0].url);
}
handleBackButton = () => {
Alert.alert(
'Exit App',
'Exiting the application?', [{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
}, {
text: 'OK',
onPress: () => BackHandler.exitApp()
}, ], {
cancelable: false
}
)
return true;
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
React Native provides the BackHandler component to handle exit functionality in android. when you call BackHandler. exitApp(); app will close but it will remain in android's recent tab.
To handle the Android Back Button Press in the React Native we have to register the hardwareBackPress event listener with a callback function, which will be called after pressing the Back Button.
Exit app when back button is pressed twice in React Native.
By default React Navigation will handle the Android back button for you, however we'll need to override the defaults. If you're at the top of the stack and press the android back button the application will close. If you've navigated within the stack anywhere then the screen will pop.
If your HomeScreen is still mounted when you navigate to other screens or while unmounting the HomeScreen
if you don't remove the EventListener it will be still called.
You should clear the EventListener on navigate or unmount,
onButtonPress = () => {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
// then navigate
navigate('NewScreen');
}
handleBackButton = () => {
Alert.alert(
'Exit App',
'Exiting the application?', [{
text: 'Cancel',
onPress: () = > console.log('Cancel Pressed'),
style: 'cancel'
}, {
text: 'OK',
onPress: () = > BackHandler.exitApp()
}, ], {
cancelable: false
}
)
return true;
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
If you don't want the Alert message to appear in other component/screen but only in one specific component/screen, you can follow this.
import { withNavigationFocus } from 'react-navigation';
class TestComponent extends Component {
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () => {
if (this.props.isFocused) {
Alert.alert(
'Exit App',
'Exiting the application?',
[
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
},
{
text: 'OK',
onPress: () => BackHandler.exitApp()
}
],
{
cancelable: false
}
);
return true;
}
};
}
export default withNavigationFocus(TestComponent );
The BackHandler that will show an Alert message will only work in TestComponent
We can add subscriptions for didfocus inside our main App Container.We can add our logic to check for button tapped with a static variable.
import { Alert, BackHandler, ToastAndroid } from 'react-native';
import { StackActions } from 'react-navigation';
import { Toast } from 'native-base';
// common statless class variable.
let backHandlerClickCount = 0;
class App extends React.Component {
constructor(props) {
super(props);
// add listener to didFocus
this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', () => this.onBackButtonPressAndroid(payload)));
}
// remove listener on unmount
componentWillUnmount() {
if (this._didFocusSubscription) {
this._didFocusSubscription.remove();
}
}
onBackButtonPressAndroid = () => {
const shortToast = message => {
// ToastAndroid.showWithGravityAndOffset(
// message,
// ToastAndroid.SHORT,
// ToastAndroid.BOTTOM,
// 25,
// 50
// );
// ios & android
Toast.show({
text: message,
type: 'warning',
position: 'top',
duration: 3000,
});
}
const {
clickedPosition
} = this.state;
backHandlerClickCount += 1;
if ((clickedPosition !== 1)) {
if ((backHandlerClickCount < 2)) {
shortToast('Press again to quit the application!');
} else {
BackHandler.exitApp();
}
}
// timeout for fade and exit
setTimeout(() => {
backHandlerClickCount = 0;
}, 2000);
if (((clickedPosition === 1) &&
(this.props.navigation.isFocused()))) {
Alert.alert(
'Exit Application',
'Do you want to quit application?', [{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
}, {
text: 'OK',
onPress: () => BackHandler.exitApp()
}], {
cancelable: false
}
);
} else {
this.props.navigation.dispatch(StackActions.pop({
n: 1
}));
}
return true;
}
}
Just adding to other answers
If you are using '@react-navigation/native'
then setting eventListner on backButton will work even when you have navigated to child screens. To overcome this set eventListner on focus
rather than with componentDidMount()
and remove it when blur
event occurs on screen.
Learn more about react-navigation events here
export class sampleScreen extends Component {
constructor(props) {
super(props);
this.state = {
foo: '',
bar: '',
};
this._unsubscribeSiFocus = this.props.navigation.addListener('focus', e => {
console.warn('focus signIn');
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
});
this._unsubscribeSiBlur = this.props.navigation.addListener('blur', e => {
console.warn('blur signIn');
BackHandler.removeEventListener(
'hardwareBackPress',
this.handleBackButton,
);
});
onButtonPress = () => {
BackHandler.removeEventListener(
'hardwareBackPress',
this.handleBackButton,
);
};
}
handleBackButton = () => {
Alert.alert(
'Exit App',
'Exiting the application?',
[{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: 'OK',
onPress: () => BackHandler.exitApp(),
},
], {
cancelable: false,
},
);
return true;
};
componentDidMount() {
// BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
this._unsubscribeSiFocus();
this._unsubscribeSiBlur();
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
}
Guyz please do understand it might not only be the problem with react native. Be careful while integrating it with firebase. The recent firebase version has the problem of integrating back button in react-native apps!! Please downgrade the firebase version to firebase-version @5.0.3 and then recheck whether it works or not! I had the same issue and was worried for days. I finally downgraded to @5.0.3 version and now the back button works perfectly fine! You may downgrade to lower versions if still facing the problem.
You can always dynamically modify what the callback function for the BackHandler.addEventListener
is based on the current scene (using react-native-router-flux
makes this easy).
import { Actions } from 'react-native-router-flux'
handleBackPress = () => {
switch (Actions.currentScene) {
case 'home':
BackHandler.exitApp()
break
default: Actions.pop()
}
return true
}
The full gist can be found here: https://gist.github.com/omeileo/f05a068557e9f0a2d8a24ecccd2f3177
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With