[tolli #6] 웹뷰와 RN 사이의 UI 트러블슈팅 모음

2026. 7. 5. 19:34·프로젝트
728x90

💡 읽기 전 필요한 지식 💡
- 웹뷰가 결국 브라우저 엔진이고, 그 엔진에도 버전이 존재한다는 정도의 감
- SSR/Hydration(즉, 서버가 만든 HTML에 React가 나중에 이벤트를 붙이는 과정)이라는 말을 들어본 적이 있으면 좋음
- iOS와 Android가 같은 코드도 다르게 그릴 수 있다는 점

📖 읽고 나면 얻을 수 있는 것 📖
- "내 PC 브라우저에서는 되는데 실기기에서는 안된다"라는 문제를 어떤 순서로 풀어가는지 감을 잡게 된다
- 웹뷰 환경이 일반 브라우저와 어떻게 다른지, 그게 왜 버그로 이어지는지 이해하게 된다
- 기기마다 다른 화면의 곡선 같은 문제를 네이티브 모듈로 해결하는 흐름을 엿볼 수 있다

일단 이 글을 읽기 전에 이전 글들을 읽으면 도움이 될 것이다.

 

[tolli #1] 무거운 성경암송 앱이 싫다

💡 읽기 전 필요한 지식 💡- 모바일 앱이 "기획 -> 개발 -> 출시"의 단계를 거친다는 정도의 큰 그림- 듀오링고 같은 학습 앱을 한 번이라도 써본 경험- "타겟 사용자"나 "문제 정의"라는 말이 어떤

bbin-guuuu.tistory.com

 

[tolli #2] 왜 React Native + WebView 하이브리드였을까?

💡 읽기 전 필요한 지식 💡- React와 React Native(RN)가 서로 다른 것이라는 정도의 구분- SSR과 CSR이라는 말을 들어본 경험- 앱이 웹뷰(앱 안에 띄우는 브라우저 창)로 웹을 띄울 수 있다는 사실📖 읽

bbin-guuuu.tistory.com

 

[tolli #3] switch로 쪼갠 화면이 협업 단위가 됐다

💡 읽기 전 필요한 지식 💡- 컴포넌트라는 개념에 대한 가벼운 이해- switch문이 값에 따라 분기하는 문법이라는 정도의 지식- 여러 명이 하나의 레포에서 함께 개발한다는 상황에 대한 감📖 읽

bbin-guuuu.tistory.com

 

[tolli #4] AOS 애플로그인 트러블슈팅

💡 읽기 전 필요한 지식 💡- OAuth 소셜 로그인이 "토큰을 주고받는 과정"이라는 정도의 큰 그림- 딥링크(tolli:// 같은 주소로 앱을 여는 것)와 WebView가 메시지를 주고받는다는 개념- Firebase 로그인

bbin-guuuu.tistory.com

 

[tolli #5] 웹뷰에서 구글로그인 구현하기

💡 읽기 전 필요한 지식 💡- 웹뷰(앱 안에 띄우는 브라우저 창)에서 웹 페이지가 돌아간다는 정도의 감 (2편 참고)- Firebase 로그인, idToken(구글이 서명한 임시 토큰)이라는 개념에 대한 가볍운 이

bbin-guuuu.tistory.com

 

이번 글에서는 웹뷰와 RN, 그리고 플랫폼(iOS, AOS)사이의 UI관련 트러블 슈팅들을 모아봤다.

이 글이 필자와 같은 문제를 마주치고 있는 개발자들에게 도움이 되길 바라며 순서대로 풀어보려고 한다!


같은 웹인데 왜 어떤 폰에선 레이아웃이 깨지지?...

결론부터 말하자면, 웹뷰 버전 이슈이다.

위 사진을 보면 왼쪽 화면이 의도한 UI이고 오른쪽이 깨져있는 UI이다.

분명 필자는 웹브라우저에서 확인을 했을 떄 해당 로그인 페이지 UI가 정말 잘 뜨는 상황이었는데,

갤럭시 S10 5G 기준으로 앱에 들어갔을 때 오른쪽 사진과 같이 레이아웃이 깨져있었다. (정말 오래된 폰이긴 하다...)

 

일단 필자는 tailwindCSS 버전4를 사용하고 있는데, 이 4 버전의 라이브러리가 이 오래된 폰의 웹뷰에서 호환이 안되는건가?라고 생각해보았다.

밑의 링크에 나와있는 것과 같이 일단 안드로이드 기기의 원격 디버깅을 지원해주는 chrome inspect를 사용해보았다.

 

Android 기기 원격 디버그  |  Chrome DevTools  |  Chrome for Developers

Windows, Mac 또는 Linux 컴퓨터에서 Android 기기의 라이브 콘텐츠를 원격으로 디버그합니다.

developer.chrome.com

아니나다를까, 웹뷰버전이 83.xx 버전이었고, tailwindcss 4를 지원하지 않는다고 한다...

즉, TailwindCSS 4가 지원하지 않는 오래된 브라우저 엔진이었던 것이다.

 

웹뷰는 시스템의 WebView 구현(안드로이드의 경우 Android System WebView)에 따라 버전이 결정된다.

그래서 찾아보았을때 개발자 옵션의 "웹뷰 구현"항목에서 웹뷰 버전을 선택할 수 있다는 것을 알게 됐고,

플레이스토어에서 151버전을 다운 받아 83버전에서 151버전으로 바꿔서 해결했다!


2. 웹에서는 되는데 iOS 웹뷰에서 버튼이 아예 동작을 안한다...

가장 골치 아팠던 건 iOS에서 버튼이 아예 동작하지 않던 문제였다.

맥북 브라우저에선 잘 동작했는데 iOS Expo Go의 웹뷰에서는 onClick도, onTouchStart도 무반응이었다...(심지어 콘솔 로그조차 찍히지 않는 상황)

일단 단서를 하나씩 좁혀가면서 범위를 좁혀나가보았다.

 

1. 먼저 WebView 전체의 onTouchStart(RN쪽)는 동작해서 웹뷰가 터치를 받고 있는건 확인했다.
injectedJavaScript로 DOM 이벤트를 확인해보았는데 click도 버튼까지 정상 도달하는 것을 볼 수 있었다.

그런데 React의 onClick핸들러만 실행되지 않는 문제가 있었다...
더 깊게 확인해보니 button이란 element에 _reactFiber 키가 없었다...
즉 React hydration 자체가 실패해서 Next.js 번들이 실행되지 않고 있었다...
2. Turbopack 모드에선 "chunk path empty but not in a worker", Webpack모드에선 "Expected document.currentScript to be a <script> element. Received null" 에러가 떴다..
근본 원인은 여기에 있었다고 볼 수 있다.
Next.js 16 (React 19)은 bootstrapScripts를 'async' 속성이 붙은 script 태그로 삽입하는데,
HTML 스펙상 async 스크립트를 실행할 때 document.currentScript는 null을 반환해야 한다.

즉, Next.js 내부가 이 값에 의존해서 스크립트가 중단되고 hydration이 실패하고 있었던 것이다.

재미있는건 환경별로 달랐다는 점이다.

  • iOS Safari 브라우저는 async 스크립트에서도 currentScript를 비표준적으로 관대하게 처리해서 동작하고 있었는데,
  • iOS WKWebView는 스펙을 엄격히 지켜서 null을 반환해 실패했다.

해결은 Next.js를 15로, React를 18버전으로 다운그레이드하는 거이었다.

// apps/web/package.json
{
  "dependencies": {
    "next": "15.3.9",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  }
}

이유를 설명해보겠다.

Next.js 15는 async없는 일반 script 태그를 삽입하기 때문에 document.currentScript가 정상 동작한다.

그래서 iOS WKWebView에서도 hydration에 성공하게 된다.

최신버전이 항상 답은 아니지 않을까? 라고 다시 한 번 생각해보자!

 


3. 기기마다 다른 화면의 곡선....

톨리에서는 디자인상 화면 테두리에 그라디언트를 입혀야되는 페이지가 있다.

그렇다면 테두리의 border-radius를 알아야하는데 기기마다 다르다는 것은 누구나 아는 사실이다.

하나의 기기에 맞춰 하드코딩을 한다?는 말이 안되는 방법이다. (아래와 같은 대참사가 발생할 수 있다)

결국 기기의 실제 곡률을 읽어와야 했는데,

처음엔 react-native-device-info 같은 라이브러리를 찾았는데 기기의 border-radius를 가져오는 API가 없었다..

다른 오픈소스 라이브러리들도 더이상 커밋이 없거나, issue들이 남은 상태로 남아있다...

그래서 네이티브 모듈을 직접 작성해보기로 했다.

 

iOS의 경우 UIKit의 private API(_displayCornerRadius KVC key)를 통해 실제 기기의 곡률을 읽을 수 있다고 한다.

 

iOS 26 UIkit 업데이트 정리

안녕하세요 주니오스입니다. 아래 글에 iOS 26과 UIKit에 대한 내용이 자세히 정리되어 있습니다.필요한 내용들을 정리해 보고자 이번 포스팅을 작성하게 되었습니다.https://sebvidal.com/blog/whats-new-in-

ios-adventure-with-aphelios.tistory.com

AOS의 경우 API 31(Android 12)부터 WindowInsets.getRoundedCorner()를 통해 각 모서리의 radius를 공식 API로 읽을 수 있다.

 

핵심은 단위 차이이다.

  • iOS는 포인트(pt)로 반환되서 CSS의 dp와 개념이 같아 그대로 써도 되지만,
  • Android는 물리 픽셀(px)로 반환되서 dp로 따로 변환해주어야 한다.
    따라서 네이티브 코틀린 모듈 안에서 density로 변환해주어 JS는 dp만 받도록 인터페이스를 통일해보았다.
    (displayMetrics.density 사용해서!)

 


트러블슈팅들에서 느낀 점

이 문제들은 물론 주제는 제각각이었지만 결국 한 줄기로 연결되었던 것 같다.

"웹뷰는 일반 브라우저가 아니다"는 것이다.

 

버전 차이, 스펙 준수에 대한 여부, 기기마다 다른 물리적 특성이 전부 실기기의 웹뷰에서 문제가 되는점들이 많았다.

그래서 항상 실기기에서, 그리고 여러 기기에서 테스트하는 게 중요하다는 것을 몸소 느꼈다.

 

또한 항상 느끼는 부분이지만, 웹만으로 안 되는 일은 네이티브 모듈로 내려가 직접 해결해보고,

플랫폼의 차이는 네이티브단에서 흡수해서 웹은 단순한 값만 받도록 하는 역할 분리가 좋지 않나라는 생각을 반복해서 하고있다.

 

다음 글은 tolli의 MVP 시리즈의 마지막이다.
앱스토어와 플레이스토어에 출시한 후 간략한 회고를 다뤄보려 한다.
728x90

'프로젝트' 카테고리의 다른 글

[tolli #5] 웹뷰에서 구글로그인 구현하기  (0) 2026.07.01
[tolli #4] AOS 애플로그인 트러블슈팅  (0) 2026.06.30
[tolli #3] switch로 쪼갠 화면이 협업 단위가 됐다  (0) 2026.06.22
[tolli #2] 왜 React Native + WebView 하이브리드였을까?  (0) 2026.06.20
[tolli #1] 무거운 성경암송 앱이 싫다  (0) 2026.06.16
'프로젝트' 카테고리의 다른 글
  • [tolli #5] 웹뷰에서 구글로그인 구현하기
  • [tolli #4] AOS 애플로그인 트러블슈팅
  • [tolli #3] switch로 쪼갠 화면이 협업 단위가 됐다
  • [tolli #2] 왜 React Native + WebView 하이브리드였을까?
프론트 개발자 김현중
프론트 개발자 김현중
👋반갑습니다 저는 나눔을 실천하는 개발자 꿈나무 김현중입니다⌨️🚀
  • 프론트 개발자 김현중
    삥구의 개발블로그
    프론트 개발자 김현중
  • 전체
    오늘
    어제
    • 분류 전체보기 (117)
      • React (39)
      • JavaScript (5)
      • TypeScript (5)
      • Next.js (13)
      • React Native (1)
      • 프로젝트 (6)
      • 오픈소스 (1)
      • 우아한테크코스 (9)
      • 알고리즘 (5)
      • Swift (3)
      • 컴퓨터네트워크 (1)
      • Docker (1)
      • SQL (8)
      • Database (2)
      • 배포 (1)
      • Spring (9)
      • Git (1)
      • 회고 (1)
      • 컴퓨터그래픽스 (2)
      • Python (1)
      • Brew (1)
      • LangChain (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    톨리
    Backend
    Spring
    springboot
    웹개발
    ReactHooks
    appRouter
    회고
    database
    우아한테크코스
    typescript
    데이터베이스
    Next.js
    java
    frontend
    프론트엔드
    javascript
    react
    nextjs
    우테코
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.1
프론트 개발자 김현중
[tolli #6] 웹뷰와 RN 사이의 UI 트러블슈팅 모음
상단으로

티스토리툴바