React Native WebView에서 iOS 스와이프 뒤로가기 (문제 해결)

Devinix·2026년 3월 20일

[문제 해결]

목록 보기
41/43

문제 상황

WebView 화면에서 사용자가 여러 웹 페이지를 탐색한 뒤 iOS 스와이프 뒤로가기를 하면, 웹 페이지 내부에서 이전 페이지로 돌아가는 것이 아니라 WebView 화면 자체가 닫혀버리는 현상이 발생했다.예를 들어 WebView 안에서 A 페이지 → B 페이지 → C 페이지 순서로 이동한 상태에서 스와이프를 하면, C에서 B로 돌아가는 것이 아니라 WebView 화면이 통째로 사라지고 앱의 이전 네이티브 화면으로 돌아가버리는 것이다.

Android에서는 하드웨어 뒤로가기 버튼을 BackHandler로 가로채서 WebView 내부 히스토리를 처리하고 있었기 때문에 문제가 없었지만, iOS의 스와이프 제스처는 별도의 처리가 필요했다.

원인

이 문제의 핵심 원인은 iOS 스와이프 뒤로가기 제스처의 주체가 WebView가 아니라 React Navigation이라는 점이다.

프로젝트에서 사용하고 있는 @react-navigation/native-stack은 iOS의 네이티브 네비게이션 컨트롤러(UINavigationController)를 기반으로 동작한다. 화면 왼쪽 가장자리에서 오른쪽으로 스와이프하는 제스처는 이 네이티브 네비게이션 컨트롤러가 처리하며, 이 제스처가 인식되면 현재 화면을 스택에서 pop하는 동작이 실행된다.

즉, 스와이프 제스처가 WebView 내부의 웹 히스토리와는 전혀 무관하게 navigation.goBack()과 동일한 효과를 내고 있었던 것이다.처음에는 beforeRemove 이벤트 리스너로 화면 이탈을 가로채는 방법을 시도했다. WebView에 히스토리가 남아있을 때 e.preventDefault()로 화면 닫힘을 막고 대신 WebView 내부에서 뒤로가기를 시키려는 접근이었다. 하지만 native-stack에서는 iOS 스와이프 제스처가 네이티브 레벨에서 처리되기 때문에, JavaScript 단의 beforeRemove에서 e.preventDefault()를 호출해도 스와이프 제스처를 막을 수 없었다. 이것은 @react-navigation/native-stack의 알려진 제한사항이다.

만약 @react-navigation/stack(JS 기반 스택)을 사용하고 있었다면 beforeRemove 접근이 동작했겠지만, native-stack을 쓰는 이상 다른 방법이 필요했다.

해결 과정

해결은 두 가지 설정의 조합으로 이루어졌다.

[WebView의 자체 스와이프 제스처 활성화]

react-native-webview에는 allowsBackForwardNavigationGestures라는 iOS 전용 prop이 있다. 이것은 내부적으로 WKWebView의 allowsBackForwardNavigationGestures 속성을 활성화하는 것으로, 이 값을 true로 설정하면 WebView 영역 안에서 스와이프할 때 웹 히스토리를 따라 뒤로가기와 앞으로가기가 동작한다.

  <WebView        
    allowsBackForwardNavigationGestures={true}
    // ...기존 props                                                                                                                                                                          
  />

이것만으로 WebView 내부의 스와이프 뒤로가기는 활성화된다. 하지만 여기서 한 가지 문제가 더 있다.

[제스처 충돌 해결]

allowsBackForwardNavigationGestures를 켜더라도 React Navigation의 스와이프 제스처가 여전히 살아있다. 화면 왼쪽 가장자리에서 스와이프를 하면 두 제스처가 동시에 경쟁하게 되고, Navigation의 제스처가 우선 인식되어 화면이 닫혀버리는 현상이 그대로 발생할 수 있다.

이를 해결하기 위해 WebView에 뒤로갈 히스토리가 있을 때는 React Navigation의 스와이프 제스처를 비활성화했다. 이미 onNavigationStateChange에서 canGoBack 상태를 추적하고 있었기 때문에, 이 값을 활용하면 된다.

  useEffect(() => {
    navigation.setOptions({
      gestureEnabled: !canGoBackInWebView,
    });
  }, [navigation, canGoBackInWebView]);

이렇게 하면 다음과 같이 동작한다.

WebView 내부에 뒤로갈 페이지가 있을 때는 Navigation 스와이프가 꺼지고 WebView 자체 스와이프만 동작하기 때문에, 스와이프하면 웹 히스토리를 따라 이전 페이지로 이동한다. 반대로 WebView가 첫 페이지인 상태에서는 Navigation 스와이프가 다시 켜지기 때문에, 스와이프하면 WebView 화면이 닫히고 앱의 이전 화면으로 돌아간다.

결론

이 문제의 본질은 "스와이프 제스처의 주체가 누구인가"였다. iOS에서 화면 왼쪽 가장자리 스와이프는 React Navigation의 네이티브 네비게이션 컨트롤러가 먼저 가져가기 때문에, WebView 입장에서는 스와이프 이벤트를 받을 기회조차 없었다.
beforeRemove같은 JavaScript 레벨의 우회는 native-stack 환경에서 통하지 않았고, 결국 WebView 자체의 네이티브 스와이프 기능(allowsBackForwardNavigationGestures)을 활성화하고 Navigation 제스처와의 충돌을 gestureEnabled 옵션으로 제어하는 것이 정답이었다.

profile
React, Next.Js, React-Native

0개의 댓글