본문 바로가기
react deep dive

인앱웹뷰에서 다이얼로그를 띄운 후 안드로이드 뒤로가기 버튼을 눌렀을 때 다이얼로그를 끄려면?

by rami_ 2025. 5. 20.

우리는 다이얼로그를 띄우고 없애기를 반복한다. 웹에서는 구현이 어렵지 않다. 사용자가 다이얼로그 바깥 부분(딤 영역)을 누르거나 취소 버튼을 누르면 사라지게 된다. 모든 것이 마우스 이벤트로 진행된다. 인앱웹뷰에서는 '터치'라는 이벤트가 발생하게 된다. 터치 이벤트 또한 쉽게 다룰 수 있다. 하지만 안드로이드에는 '뒤로가기' 물리 버튼이 존재한다. 뒤로가기 물리 버튼이 클릭된 것을 감지하여 다이얼로그를 꺼야 하는 상황이 왔다. 어떻게 해결할 것인가?

 

제일 처음 생각했던 방법은 안드로이드에서 뒤로가기 버튼을 눌렀을 때 네이티브 영역에서 인앱웹뷰 영역으로 데이터를 넘겨주는 것이었다. 이렇게 할 경우 네이티브를 담당하는 개발자에게도 공수가 들게 되어 좀 더 간단한 방법에 대해 알아보게 되었다.

뒤로가기 버튼을 눌렀을 때 웹페이지일 경우 router 히스토리 스택에서 제일 위에 있는 것을 내보내게 된다는 것을 떠올리게 되었다. 그래서 다이얼로그를 띄우면 임의적으로 히스토리에 스택을 쌓고 뒤로가기 버튼을 누르면 히스토리 스택에서 제외하는 것으로 설계하였다.

 

이 문제를 해결하기 위해 Next.js의 라우팅 시스템과 URL 쿼리 파라미터를 활용한 커스텀 훅을 구현했다. 핵심 아이디어는 다이얼로그가 열릴 때 URL에 쿼리 파라미터를 추가하고, 다이얼로그가 닫힐 때 해당 파라미터를 제거하는 것이다. 이렇게 하면 안드로이드 뒤로가기 버튼을 누를 때 자연스럽게 이전 URL 상태(다이얼로그가 없는 상태)로 돌아가게 된다.

useDialogNavigation 훅의 동작 원리

1. URL과 다이얼로그 상태 동기화

다이얼로그가 열리면 URL에 ?dialog=다이얼로그ID 쿼리 파라미터를 추가하고, 닫히면 이 파라미터를 제거한다. 이를 통해 다이얼로그의 상태를 브라우저의 히스토리 스택과 동기화시킨다.

if (isOpen && !prevIsOpenRef.current && !isDialogInUrl) {
  // 다이얼로그가 열렸을 때 URL에 dialog 파라미터 추가
  const newParams = new URLSearchParams(searchParams.toString());
  newParams.set('dialog', dialogId);
  router.push(`${pathname}?${newParams.toString()}`, { scroll: false });
} else if (!isOpen && prevIsOpenRef.current && isDialogInUrl) {
  // 다이얼로그가 닫혔을 때 URL에서 dialog 파라미터 제거
  const newParams = new URLSearchParams(searchParams.toString());
  newParams.delete('dialog');
  router.push(`${pathname}?${newParams.toString()}`, { scroll: false });
}

 

2. URL 변경 감지와 다이얼로그 제어

URL이 변경되면(예: 뒤로가기 버튼을 눌렀을 때) 다이얼로그 상태를 그에 맞게 업데이트한다. URL에서 dialog 파라미터가 사라졌는데 다이얼로그가 열려있다면, 다이얼로그를 닫는다.

useEffect(() => {
  if (!mounted || urlChangingRef.current) return;
  if (ableBackNavigation) {
    if (!isDialogInUrl && isOpen) {
      onClose();
    }
  }
}, [urlDialogParam, isOpen, onClose, isDialogInUrl, ...]);

 

3. 경쟁 상태 방지

URL 변경이 진행 중일 때는 상태 변경 이벤트를 무시한다.

urlChangingRef.current = true;
router.push(`${pathname}?${newParams.toString()}`, { scroll: false });
setTimeout(() => {
  urlChangingRef.current = false;
}, 100);

 

이 방법을 통해 웹뷰 내에서도 안드로이드 뒤로가기 버튼을 통해 자연스럽게 다이얼로그를 제어할 수 있게 되었다. 사용자 입장에서는 마치 네이티브 앱처럼 직관적인 경험을 제공하면서, 웹 개발자 입장에서는 네이티브 개발자의 도움 없이도 문제를 해결했다.