WebView 상태가 날아가는 문제를 커스텀 네비게이션으로 해결한 키친보드의 KMP 도전기
![]()
주문서를 한참 작성하다가 다른 화면으로 잠깐 갔다 돌아왔는데, 쓰던 내용이 전부 사라져 있어요. 요식업 매장에서 이런 일이 벌어지면 사용자 경험은 치명적으로 무너지죠. 스포카 FE팀이 키친보드 앱의 KMP/CMP 마이그레이션에서 마주한 가장 큰 난관이 바로 이 WebView 화면 상태 유실 문제였어요.
키친보드는 요식업 매장과 식자재 유통사의 주문, 결제, 커뮤니케이션을 통합 관리하는 B2B SaaS 플랫폼이에요. Android와 iOS 네이티브 앱을 각각 운영해왔는데, 서비스 성장과 함께 양쪽 플랫폼의 기능 격차를 줄이고 배포 속도를 높여야 하는 상황이었죠.
Compose Navigation을 도입하려다 마이그레이션 자체를 포기할 뻔했다
KMP/CMP를 선택한 핵심 이유는 기존 Kotlin 비즈니스 로직과 Compose UI를 재활용하면서도 100% 네이티브 성능을 유지할 수 있다는 점이었어요. DeepLink, Push, MLKit 같은 네이티브 기능도 완전 지원하고요. 그런데 문제는 네비게이션에서 터졌어요.
Compose Navigation의 NavHost는 화면 전환 시 destination을 재구성(Recomposition)하는 특성이 있어요. 이게 WebView 객체를 초기화시키면서 작성 중이던 폼 데이터 손실, 스크롤 위치 초기화, 불필요한 네트워크 요청 재발생으로 이어졌죠. 핵심 화면이 WebView 기반 주문서 작성인 키친보드에게는 치명적인 결함이었어요.

FragmentManager와 UINavigationController 기반으로 직접 만들었다
포기하는 대신 Compose Navigation을 걷어내고 커스텀 네비게이션 아키텍처를 설계했어요. Android에서는 FragmentManager, iOS에서는 UINavigationController 기반이에요. 타입 안전성을 보장하기 위해 NavDestination abstract class와 NavScreen enum을 설계해서, 각 화면의 Route 패턴과 파라미터를 Type Safety하게 정의했죠.
이 접근의 장점은 WebView 인스턴스가 네비게이션에 의해 파괴되지 않는다는 거예요. 화면을 떠났다 돌아와도 상태가 그대로 유지되죠. "정말 프로덕션에서 가능할까?"라는 질문에서 시작한 이 도전은, 프레임워크의 한계를 만났을 때 포기 대신 우회로를 찾는 엔지니어링의 본질을 보여주는 사례에요.