Flutter WebView에서 iOS의 localStorage 인증 실패 해결기 – WKWebView의 함정과 우회법

Carl's Space·2025년 3월 25일

Flutter

목록 보기
4/4
post-thumbnail

❓ 문제 상황

Flutter 앱에서 WebView를 띄우고, 앱이 보유한 access token을 JS 측 localStorage에 전달해야 하는 상황.
Android에서는 문제 없이 동작하지만, iOS에서는 다음과 같은 현상이 발생했다.

  • window.localStorage.setItem('x-api-token', token) 호출
  • 이후 getItem() 결과는 null
  • 웹 API 요청 → ⚠️ 401 Unauthorized 오류

🧠 근본 해결 방향

iOS의 WKWebView 특성상 보안 context가 완전히 준비되기 전에는 localStorage에 접근하거나 데이터를 주입하는 것이 제한될 수 있다.
이에 따라 다음과 같은 방식들이 장기적인 해결책으로 제안된다.

🔁 1. 웹이 앱에게 토큰 요청 (JS → Flutter → JS)

window.HeartField.postMessage('requestToken');

Flutter는 이 메시지를 받아 다시 JS로 토큰을 삽입:

webViewController.runJavascript("localStorage.setItem('x-api-token', '\$token');");

🔐 2. 앱이 토큰을 쿠키나 URL 파라미터로 전달

  • 예: https://example.com?token=abc123
  • 웹에서 localStorage.setItem(...) 수행

⚠️ 보안상 민감함 → HTTPS + 짧은 생명주기 토큰 필수

🍪 3. 서버가 HTTP-only 쿠키로 토큰 내려주기

  • 인증 요청 시 서버가 세션 쿠키 발급
  • JS 없이도 인증 유지 가능
  • 단, WebView는 3rd-party 쿠키 이슈 존재

🧪 임시 해결: preload HTML + redirect 방식

웹/서버 코드를 수정할 수 없는 경우엔, 다음 방식이 가장 확실하다:

if (Platform.isIOS) {
  final html = '''
    <html>
      <script>
        localStorage.setItem('x-api-token', '\$token');
        location.replace('\$realUrl'); // ✅ 히스토리에 남지 않음
      </script>
    </html>
  ''';

  webViewController.loadHtmlString(html, baseUrl: Uri.parse('https://yourdomain.com'));
} else {
  webViewController.loadRequest(Uri.parse(realUrl));
}

✅ 장점

  • localStorage에 토큰 확실히 저장됨
  • 웹이 처음부터 인증 상태로 시작
  • location.replace() 덕분에 히스토리에 안 남음

⚠️ 단점

  • 한 번의 리디렉션 발생

🧹 전체 세션 정리: dispose에서 clearHistory()

WebView의 전체 히스토리를 지우고 싶을 땐 아래처럼:


void dispose() {
  webViewController.clearHistory(); // 🧼 히스토리 초기화
  super.dispose();
}

📌 flutter_inappwebview 전용 기능이므로, webview_flutter에선 지원되지 않음.


✅ 결론

Flutter WebView + iOS 환경에서는 단순한 JS 삽입만으로 localStorage에 토큰을 심는 것이 불안정하다.
보안 정책을 우회하기 위해 preload HTML 기법을 사용해 문제를 해결할 수 있으며,
장기적으로는 앱과 웹 간 통신 구조를 개선하는 방향이 필요하다. 🚀

profile
성장중...

0개의 댓글