끄적이는 개발노트

React Native - Hardware 뒤로 가기 버튼으로 어플 종료 본문

React Native

React Native - Hardware 뒤로 가기 버튼으로 어플 종료

크런키스틱 2025. 2. 11. 22:52
728x90

react-native로 개발을 하다보면 물리적인(Hardware) 버튼으로 뒤로가기나 앱이 종료될 수 있기 때문에 이에 따른 처리가 필요하다. 뒤로가기는 각 페이지의 navigation 형태나 원하지 않는 페이지에서 block을 해주는 등 다양한 방법이 있다.

어플 종료의 경우, 대다수의 어플이 1∽2초 안에 뒤로가기 버튼을 두번 누를 경우 Toast Message와 함께 어플실행이 종료된다. 이번 글에서는 해당 기능을 구현한 방법을 정리해본다.

 

1. Custom Hook을 통한 기능 구현

// useExitApp.ts

import {showBottomToast} from '@/utils/toastMessage';
import {useNavigation} from '@react-navigation/native';
import {useEffect} from 'react';
import {BackHandler} from 'react-native';

const useExitApp = () => {
  const navigation = useNavigation();
  let backPressCount = 0;

  // Hardware BackButton Handler
  const onPressHardwareBackButton = () => {
    if (navigation.isFocused()) {
      if (backPressCount < 1) {
        backPressCount += 1;

        showBottomToast(
          'blackOpacity',
          "'뒤로' 버튼을 한번 더 누르시면 종료됩니다.",
        );
      } else if (backPressCount === 1) {
        BackHandler.exitApp();
      }
      setTimeout(() => {
        backPressCount = 0;
      }, 2000);

      return true;
    }
  };

  useEffect(() => {
    BackHandler.addEventListener(
      'hardwareBackPress',
      onPressHardwareBackButton,
    );
    return () => {
      BackHandler.removeEventListener(
        'hardwareBackPress',
        onPressHardwareBackButton,
      );
    };
  }, []);
};

export default useExitApp;

 

작동하는 원리를 간단하게 설명해보자면,

  1. useNavigation의 isFocused를 통해 해당 hook을 적용한 스크린에서만 이벤트가 발생하도록 설정
  2. 기본 react-native에서 제공하는 BackHandler를 통해 물리적인 뒤로가기 버튼을 인식한다.
  3. backPressCount라는 변수를 선언해 뒤로가기 버튼의 press 횟수를 카운팅한다.
  4. 첫 press가 이루어지면, Toast Message를 통해 안내를 해주고, count를 더한다.
  5. 만약, 2초 안에 한번 더 press가 이루어지면(count가 이미 1인 상태에서 press가 인식되면) exitApp을 통해 어플을 종료하고 그렇지 않다면 count를 다시 0으로 초기화한다.

 

2. toast message 디자인

지난번에 작성한 toast.config.tsx 파일에 본인이 원하는 디자인의 toast message를 커스텀해 추가해준다.

// toast.config.tsx

import {
  SuccessToast,
  ErrorToast,
  InfoToast,
  ToastProps,
} from 'react-native-toast-message';
import {StyleSheet, Text, View} from 'react-native';
import CheckCircleOutline from '@assets/svg/check-circle-outline.svg';

export const toastConfig = {
  ...
  ,
  blackOpacity: ({text1}: any) => (
    <View style={toastStyle.blackOpacityToast}>
      <Text style={toastStyle.toastText1}>{text1}</Text>
    </View>
  ),
  ...
};

const toastStyle = StyleSheet.create({
  ...
  ,
  blackOpacityToast: {
    height: 50,
    width: '80%',
    backgroundColor: 'rgba(0,0,0, 0.6)',
    borderLeftColor: 'rgba(0,0,0, 0.6)',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    paddingHorizontal: 5,
    borderRadius: 100,
  },
  ...
});

 

 

3. 스크린에 적용

적용방법은 굉장히 간단하게 아래와 같다.

// Home.tsx

import CustomText from '@/components/text';
import useExitApp from '@/hook/useExitApp';
import {countState} from '@/recoil/count';
import {HomeProps} from '@/types/stack';
import {Button, Text, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {useRecoilState} from 'recoil';

const HomeScreen = ({navigation}: HomeProps) => {
  const [count, setCount] = useRecoilState(countState);
  useExitApp(); <= 커스텀 훅 적용

  return (
    <SafeAreaView className="flex-1">
      <View className="w-full h-full flex justify-center items-center bg-white">
        <CustomText className="text-success text-xl" children="홈 화면" />
        <View className="w-full flex flex-row justify-center items-center">
          <Button
            title="-"
            onPress={() => {
              setCount(count - 1);
            }}
          />
          <Text className="text-success text-xl mx-4">{count}</Text>
          <Button
            title="+"
            onPress={() => {
              setCount(count + 1);
            }}
          />
        </View>
      </View>
    </SafeAreaView>
  );
};

export default HomeScreen;

 

 

4. 실행

실행해보면 아래와 같이 잘 적용된 것을 확인할 수 있다.

 

 

5. 추가

내용을 정리하면서 알게 된 내용으로, 해당 이벤트는 어플을 완전히 종료(kill) 하는 것이 아닌 백그라운드 상태로 보내는 것이며, android에서만 적용된다고 한다.

 

react-native-exit-app이라는 라이브러리를 활용하면 android, ios 모두 사용가능하며 어플을 완전히 종료(kill) 시켜준다고 한다. 다음에 기회가 되면 적용해봐야겠다.

https://www.npmjs.com/package/react-native-exit-app

 

react-native-exit-app

Exit,close,kill,shutdown app completely for React Native on iOS and Android.. Latest version: 2.0.0, last published: 2 years ago. Start using react-native-exit-app in your project by running `npm i react-native-exit-app`. There are 12 other projects in the

www.npmjs.com

 

728x90