🐦 Flutter

[Flutter] iOS 웹뷰 흰 화면 뜨는 현상 2탄

ji-hyun 2025. 2. 1. 19:32

지난번 썼던 글이 생각보다 찾는 사람이 많다는 것을 알게 되면서 좀 더 보완할 겸 2탄으로 돌아오게 되었다.
또한 이번 회사에서 하는 업무도 웹뷰가 상당 부분 구성되어 있는 앱을 만들게 되면서 다시 똑같은 이슈를 맞닿뜨리게 되었다.


1탄에서는 unity webgl 이라는 기술을 사용해서 flutter 앱 안에 웹뷰를 띄우는 방식이었는데 이번 회사에서는 앱 안에 react 로 만들어진 웹뷰를 띄우는 방식이었다.


이직한 첫 날, 회사 사람들이 내게 질문했었다.
다른 개발자들: 시간이 지나면 하얀색 화면이 뜨는데 혹시 ***님은 이유를 아시나요?
나: 혹시 iOS 에서 발생하는 걸까요?
다른 개발자들: 네 그랬던 것 같아요.


그때 내가 맞닿뜨렸던 이슈가 생각나면서 unity webgl 과 같은 무거운 웹뷰뿐만 아니라 거의 모든 웹뷰가 이 현상이 발생하는 것이라는 것을 깨닫게 되었다. (iOS 한정)


1탄에서 내가 생각했던 해결책은 아래와 같았다.
1. webviewController 를 reload 하기 (대부분이 1번에서 해결할 것으로 추정함. 하지만 나 같은 경우, webgl 이라는 무거운 기술을 사용했기에 백그라운드 환경에서 reload 가 수없이 반복되다가 제한되는 현상이 발생함 >> 2번으로 해결하였음)
2. 앱이 paused 상태일 때 webviewController 를 null 로 해제해버리고 resumed 상태가 되면 webviewController 다시 할당


2번처럼 해결했기에 앱을 껐다가 키면 웹뷰가 무조건 로드되는 현상을 맞이하게 되었다.
그때 당시 이 문제를 100% 해결하지 않았었다고 생각했고 입사 첫 날, 다시 이 해결책에 대해 고민해본 것 같다.





토스가 하는 방식


해결하기 어려울 땐 비슷한 기술을 구현해낸 어플을 찾아보고 모방하는 편이다. 그 중 토스 어플을 대상으로 테스트해보기로 했다.
(토스는 웹뷰가 상당수 구성된 React-Native 앱이다.)


<테스트 결과>
토스 앱의 웹뷰 화면을 켜두고 내려두었다가 다시 켜본다 -> 그대로 남아있음
토스 앱의 웹뷰 화면을 켜두고 내려두었다가 다른 앱을 10개 이상 켜본다 -> 그 결과, 토스 앱을 다시 켜보았을 때 메인 화면으로 리다이렉트되는 현상을 보였다.


여기서 힌트를 얻었다.





2탄의 해결책


토스 어플이 메인 화면으로 리다이렉트가 되는 이유가 정확히 이것(= 웹뷰 백화 현상) 때문인지는 확신할 수 없지만 내 생각에는 왠지 그렇지 않을까…? 추측해본다.
토스와 비슷하게 구현해내기 위해서 아래와 같이 생각해봤다.


1. 앱을 사용중일 때만 webviewController 를 reload 하기
앱을 사용중일 때만 <— 이 조건이 하나 붙었다. 즉, 앱이 paused 된 경우가 아닐 때에만 reload 시키자.
isPausedOnIOS 라는 변수를 맨 처음에 false 로 선언해둔다.

bool _isPausedOnIOS = false;




이때 다음과 같이 웹뷰가 종료된 이벤트가 오게 되면 아래와 같이 isPausedOnIOS 가 false 인 경우만 reload 처리한다.

onWebResourceError: (error) {
            if (error.errorType == WebResourceErrorType.webContentProcessTerminated) {
              if (_isPausedOnIOS == false) {
                _controller.reload(); // 앱 실행중일 때만 reload 처리
                return;
              }
            }
          },




2. 백그라운드에서 종료되는 현상 해결하기
백그라운드에서는 웹뷰가 kill 되어도 내비둘 것이다.
웹뷰가 kill 되도록 내버려둔 이유는 iOS 정책(백그라운드에서 웹뷰를 종료해버리는 현상)을 그대로 따르는 것이 좋다고 생각했기 때문이다.
이제 다른 앱을 10개 이상 켜본다.
그러면 웹뷰가 kill 되었을 것이다. 앱을 paused 된 상태에서는 웹뷰를 reload 를 하지 않았기에 그대로 웹뷰의 currentUrl 이 null (url 이 about:blank) 이 된다.


앱을 다시 사용하려고 키게 될 경우, currentUrl 이 null 이 되었는지 확인하고 null 이 맞다면 웹뷰를 초기화시킨다. (혹은 다른 화면으로 리다이렉트시켜줘도 됨)


if (state == AppLifecycleState.resumed) {
      _isPausedOnIOS = false;
      if (await _controller.currentUrl() == null) {
        _initializeWebView();
        return;
      }
    } else if (state == AppLifecycleState.paused) {
      if (Platform.isIOS) _isPausedOnIOS = true;
    }





결론


2탄의 해결책으로 앱을 출시하였고 현재 별 문제가 없는 것 같다.
또한 1탄의 해결책으로 했던 문제점 (앱을 킬 때마다 웹뷰 초기화)‘앱을 켰을 때의 웹뷰가 메모리 이슈로 종료되었을 때만 초기화시키기’ 로 해결해서 앱을 킬 때마다 로드가 안되는 현상이 사용성 측면에서 장점이 보였다.


웹뷰 흰 화면 뜨는 현상에 대해 많은 분들이 검색하는 것 같은데 1탄에서 해결을 완전히 해결하지 못하였기에 조금 부끄러운 글이 되어버린 것 같다. (하지만 후회는 하지 않는다. 내가 생각했던 최선의 방법이었다.)
2탄으로 작성한 이 글도 flutter 개발자들에게 많은 도움이 되었으면 한다.
더 좋은 해결책 있다면 언제든 환영입니다! ^^