에러 텔레메트리로 발견한 Flutter 웹뷰 크래시 버그 수정기
에러 텔레메트리로 발견한 Flutter 웹뷰 크래시 버그 수정기
ttapp을 운영하면서 에러 텔레메트리 시스템을 도입했는데, 덕분에 사용자가 직접 신고하지 않아도 조용히 쌓이던 버그를 발견하고 수정할 수 있었습니다.
발견 경위
Firebase error_logs 컬렉션을 조회해보니, 최근 20건 중 14건이 동일한 에러였습니다.
MissingPluginException(No implementation found for method canGoBack
on channel com.pichillilorenzo/flutter_inappwebview_1)
사용자는 아무 신고도 안 했지만, 로그에 조용히 쌓이고 있었던 것입니다.
원인 분석
flutter_inappwebview는 컨트롤러 객체 생성(onWebViewCreated)과 네이티브 플러그인 채널 등록(onLoadStart) 사이에 타이밍 갭이 존재합니다.
기존 코드는 controller == null 체크만 하고 있었는데, 컨트롤러 객체는 존재하지만 채널이 아직 준비되지 않은 상태에서 canGoBack()을 호출하면 예외가 발생합니다.
// 기존 코드 — null 체크만 있음
Future<void> _goBack() async {
final controller = _webViewController;
if (controller == null) return; // ← null은 아닌데...
if (await controller.canGoBack()) { // ← 여기서 크래시!
await controller.goBack();
}
}
타임라인:
onWebViewCreated→ 컨트롤러 객체 할당 (채널은 아직 미준비)- 사용자가 뒤로가기 버튼 탭
canGoBack()→ 네이티브 채널 호출 →MissingPluginException
수정 방법
_webViewReady 플래그를 추가해 채널이 실제로 준비된 시점을 추적했습니다.
bool _webViewReady = false;
// 웹뷰 재생성 시 항상 리셋
onWebViewCreated: (controller) {
_webViewController = controller;
_webViewReady = false; // 채널 준비 안 됨
}
// 네이티브 채널이 실제로 준비되는 시점
onLoadStart: (controller, url) {
setState(() {
_webViewReady = true; // 이제 호출 가능
...
});
}
// 준비되지 않으면 early return
Future<void> _goBack() async {
final controller = _webViewController;
if (controller == null || !_webViewReady) return; // ← 수정
if (await controller.canGoBack()) {
await controller.goBack();
}
}
추가로 잡은 엣지케이스
단순히 onLoadStart에서만 true로 설정하면 한 가지 문제가 더 있습니다.
히스토리 화면 → URL 탐색 시 InAppWebView 위젯이 트리에서 완전히 제거되었다가 다시 생성됩니다. 이때 onWebViewCreated가 다시 호출되지만, _webViewReady는 이전 값인 true로 남아있어 동일한 크래시가 재현될 수 있습니다.
onWebViewCreated에서 _webViewReady = false로 리셋하는 것이 핵심입니다.
교훈
에러 텔레메트리의 가치를 다시 한번 느꼈습니다. 사용자는 대부분 버그를 신고하지 않고 그냥 넘어갑니다. 조용히 쌓이는 에러를 주기적으로 확인하는 것만으로도 사용자 경험을 크게 개선할 수 있습니다.
앱에 아직 에러 로깅 시스템이 없다면, Firebase + Cloud Functions 조합으로 간단하게 구축할 수 있습니다.
이 글 공유하기
// SPONSORED
[>]댓글
아직 댓글이 없어요. 첫 댓글을 남겨보세요!