Intro
- Android에서 뒤로가기를 눌렀을 때 앱이 곧장 종료되는 문제가 있어, 홈 탭인지 여부를 확인해 제어해야 했습니다.
- 저는 Expo Router와 BackHandler를 이용해 더블백(exit) 패턴을 구현하고 안내 토스트를 띄웠습니다.
핵심 아이디어 요약
- 루트 경로인지 확인하는 헬퍼를 전달받아 더블백 동작 여부를 결정했습니다.
router.canGoBack()으로 히스토리가 있으면 기본 뒤로 이동을 허용했습니다.
- 루트가 아니면 첫 번째 뒤로에서 홈으로 replace하고, 루트면 안내 메시지를 보여준 뒤 1.5초 안에 한 번 더 눌러야 종료하도록 했습니다.
준비와 선택
- Expo Router가 제공하는
useRouter를 활용해 네비게이션 상태를 체크했습니다.
- 토스트는 이미 사용 중인
infoMessage 컴포넌트를 재사용했습니다.
- 타이밍을 쉽게 제어하기 위해
useRef로 마지막 백버튼 시간을 저장했습니다.
구현 여정
- 조건부 활성화: Android에서만 작동하도록
Platform.OS를 체크했습니다.
- 루트 판별: 외부에서 전달된
isAtFeedRoot 함수를 사용해 현재 경로가 홈인지 확인했습니다.
- 홈이 아닐 때 처리: 첫 번째 뒤로는 홈으로
router.replace('/')하고, 1.5초 내 다시 누르면 앱을 종료했습니다.
- 홈일 때 처리: 안내 메시지를 띄우고, 1.5초 내 다시 누르면
BackHandler.exitApp()을 호출했습니다.
- 정리 작업: 언마운트 시 이벤트 리스너를 제거했습니다.
export function useAndroidDoubleBackExit({
isAtFeedRoot,
pathname,
}: AndroidDoubleBackExitOptions) {
const router = useRouter();
const lastBackPressRef = useRef(0);
useEffect(() => {
if (Platform.OS !== 'android') return;
const onBackPress = () => {
const canGoBack = router?.canGoBack ? router.canGoBack() : false;
if (canGoBack) return false;
if (!isAtFeedRoot(pathname)) {
const now = Date.now();
if (now - lastBackPressRef.current < 1500) {
BackHandler.exitApp();
return true;
}
lastBackPressRef.current = now;
router.replace('/');
return true;
}
const now = Date.now();
if (now - lastBackPressRef.current < 1500) {
BackHandler.exitApp();
return true;
}
lastBackPressRef.current = now;
infoMessage('뒤로가기를 한 번 더 누르시면 종료됩니다');
return true;
};
const sub = BackHandler.addEventListener('hardwareBackPress', onBackPress);
return () => sub.remove();
}, [router, pathname, isAtFeedRoot]);
}
결과와 회고
- 홈 탭에서는 두 번 눌러야 앱이 종료되고, 다른 스택에서는 홈으로 안전하게 돌아오면서 사용자 이탈이 줄었습니다.
- QA가 “이제 뒤로가기가 자연스럽다”라고 피드백을 주었고, 토스트 메시지도 한글로 통일했습니다.
- 다음에는 툴바에서 뒤로 버튼을 눌렀을 때도 동일한 로직을 적용할 계획입니다.
- 여러분 팀은 Android 백버튼을 어떻게 제어하고 있나요? 좋은 패턴이 있다면 공유해주세요.
Reference