Frontend
앱과 웹의 연결고리 : 여기어때 통합 WebView 구축기
Taron여기어때
2024년 12월 10일
원문에서 보기 ↗
Photo by JJ Ying on Unsplash
안녕하세요. 여기어때컴퍼니 Android개발팀 태런입니다.
앱 개발 방식에는 네이티브 앱, 웹 앱, 하이브리드 앱 이렇게 세 가지가 있습니다. 각 방식은 개발 목적이나 사용 환경에 따라 선택되는데요. 여기어때 앱은 모바일 기기에 최적화된 네이티브 언어(예: Swift, Kotlin)로 개발된 네이티브 앱입니다. 구글 플레이 스토어나 앱 스토어에 등록된 대부분의 앱이 네이티브 앱에 해당하죠.
그런데 네이티브 앱에서도 웹 콘텐츠를 사용하는 경우도 있는데요. 이럴 때는 웹뷰(WebView)를 활용하여 앱 내에서 웹페이지를 불러올 수 있습니다. 웹뷰로 외부 웹페이지를 앱 안에서 렌더링해 사용자 경험을 자연스럽게 유지할 수 있습니다.
여기어때 앱에서도 웹뷰를 사용하나요?
여기어때 앱 내에서도 웹뷰가 사용되고 있다는 사실, 알고 계셨나요? 저는 이 웹뷰에 대해 이야기해 보려고 합니다. 웹뷰가 무엇인지, 그리고 앱과 웹이 어떻게 연동되는지 설명하면서, 기존 여기어때 앱에서 파편화된 웹뷰를 통합했던 경험도 말씀드리겠습니다. 궁금하시다면 끝까지 읽어주세요!
네이티브 앱과 웹의 연결고리 웹뷰(WebView)
웹뷰란 무엇일까요? 네이티브 또는 크로스 플랫폼 앱 내부에 웹 브라우저 기능을 내장해 웹 콘텐츠를 표시할 수 있는 컴포넌트입니다. 간단히 말해, 앱 안에서 웹페이지를 직접 로드하고 보여주는 임베디드 브라우저라고 볼 수 있습니다. 웹뷰의 가장 큰 장점은 네이티브 앱과 웹의 강점을 결합해 개발 효율성을 극대화할 수 있다는 것입니다.
그럼 웹뷰가 제공하는 주요 이점들을 살펴보겠습니다.
첫째, 개발 비용을 절감 할 수 있습니다.
웹뷰를 활용하면 하나의 웹페이지로 Android, iOS, 웹 등 다양한 플랫폼에서 동일한 콘텐츠를 제공할 수 있습니다. 이를 통해 개발 시간과 비용을 대폭 절감하고 유지보수도 간소화할 수 있죠. 특히 리소스가 제한된 스타트업이나 다양한 플랫폼 지원이 필요한 기업에게는 최적의 솔루션이 될 수 있습니다.
둘째, 실시간 콘텐츠 업데이트가 가능합니다.
웹뷰를 사용하면 앱을 재배포하지 않고도 웹 콘텐츠를 즉시 수정할 수 있습니다. 특히 빠른 업데이트가 필요한 상황에서 매우 유용합니다. 스토어 심사 절차를 거치지 않고도 콘텐츠를 바로 변경할 수 있어 긴급한 이슈에도 신속하게 대응할 수 있습니다.
셋째, 앱을 빠르게 개발하여 출시할 수 있습니다.
시장에 빠르게 진입하기 위해 초기 버전의 앱을 웹뷰로 구현하는 경우가 많습니다. 웹 기술을 활용해 빠르게 프로토타입을 만들고, 이후 필요에 따라 네이티브 기능으로 전환할 수 있습니다.
이러한 장점을 바탕으로 개발 효율성과 유연성이 필요할 때 웹뷰를 사용한다면 강력한 도구가 될 것입니다. 다만, 속도 저하나 UI/UX 제약 같은 단점을 충분히 고려하여 사용해야 합니다. 특히, 빠른 시장 대응과 개발 비용 절감이 중요한 프로젝트라면 웹뷰는 좋은 선택이 될 수 있습니다.
웹뷰에서 앱과 웹 연동하기
웹뷰는 앱과 웹 간의 데이터 교환을 가능하게 하여, 네이티브 앱과 웹 콘텐츠가 원활하게 연동되도록 도와줍니다. 이제 웹뷰에서 앱과 웹이 어떻게 데이터를 주고받고 연동할 수 있는지 알아보겠습니다.
웹뷰와 네이티브를 연결하는 방식에는 두 가지가 있습니다.
첫 번째 방식은 Scheme을 이용한 방식입니다.
이 방법은 Scheme을 정의하고, 해당 Scheme을 실행하면 앱이 구동되거나 앱 내의 특정 동작이 호출되는 방식입니다. 보통 자체 규격을 만들어서 사용하는데, 여기어때는 아래와 같은 형식으로 사용합니다.
window.location = "withcall://nativecall/{method}?{parameterName1}={value1}&{parameterName2}={value2}"
이 방식의 장점은 웹뷰 내에서 Scheme을 호출하면 네이티브 내부 동작을 호출할 수 있다는 것입니다. 페이지 이동부터 카메라 호출과 같은 네이티브 기능까지 호출이 가능합니다. 또한 Scheme 뒤에 쿼리 스트링을 붙여서 데이터도 전달할 수 있습니다.
Scheme 방식의 단점은 호출 이후 결과를 받을 방법이 없다는 점입니다. 웹페이지에서 Scheme이 제대로 동작하는지 확인할 수 없으며, 동작 이후 결과에 따라 추가 작업을 수행하기 어렵습니다. 즉, 단방향 통신입니다. 양방향 통신이 불가능하다는 의미는 아니지만, 대부분 단방향 통신 방식으로 구현되어 있습니다.
두 번째 방식은 브릿지(Bridge) 방식입니다.
웹뷰에서 데이터를 네이티브로 전달할 때에는
- iOS는
WebKit Message Handler를 통해 메시지를 전송하며, - Android는
JavaScript Interface를 호출하는 방식을 사용합니다.
이 방식의 장점은 모든 네이티브 동작을 정의할 수 있고 호출 할 수 있다는 것입니다. 또한, Scheme 방식과 달리 양향방 통신도 가능합니다.
현재 여기어때 앱에서도 이러한 브릿지 방식을 활용하고 있습니다.
그럼 이제, 안드로이드 웹뷰에서 네이티브와 어떻게 연동하는지 자세히 알아보겠습니다.

그림은 안드로이드에서 웹뷰 연동 방식을 도식화한 것입니다. 왼쪽은 안드로이드 네이티브 페이지의 구조를, 오른쪽은 웹뷰에서 렌더링되는 웹페이지의 구조를 나타내죠. 네이티브 앱과 웹이 어떻게 연동이 되는지 감이 좀 오시나요? 이제 앱에서 웹, 웹에서 앱으로 어떻게 데이터를 주고 받는지 자세히 설명 드릴게요!
Android → Web
네이티브에서 웹으로 연동하는 코드 예시입니다.
// Web
window.NativeInterface = {
methodName: () => {
// javascript code
},
}
- 웹페이지의 코드입니다. 네이티브에서 호출하기 위한 모듈을 정의하고 import 합니다. 전역 scope로 생성됩니다. 개발 방식에 따라 다를수는 있습니다.
// Android
webView.loardUrl("javascript:window.NativeInterface.methodName()")
webView.evaluateJavascript("window.NativeInterface.methodName()")
- 안드로이드 코드입니다. WebView에서 제공하는 loadUrl 또는 evaluateJavascript를 사용하여 Web에서 구현한 javascript method를 호출 할수 있습니다.
Web -> Android
웹에서 네이티브로 연동하는 코드 예시입니다.
- 웹에서 호출하기 위한 인터페이스 method를 하나의 Class로 만듭니다.
- 인터페이스 method에
@JavascriptInterface어노테이션을 붙여줍니다.
class GCJsInterface {
@JavascriptInterface
fun nativeFunction(param: String) {
// android native code
}
}
- 위 Class를 WebView에 연결합니다.
webView.addJavascriptInterface(GCJsInterface(), "Android") - 웹에서는 window.클래스명.메소드명 형식으로 Android native method를 호출할 수 있습니다.
window.Android.nativeFuntion("param")
지금까지 안드로이드 웹뷰에서의 연동 방식을 설명드렸습니다.
웹뷰와 네이티브 앱을 연결하려면 앱과 웹 간의 상호 협의된 규격이 꼭 필요합니다. 이 과정에서 앱 개발자와 웹 개발자의 협업은 필수적이죠. 그럼 이제, 기존 여기어때 앱에서 사용하던 파편화된 웹뷰를 어떻게 통합했는지 이야기해 보겠습니다!
통합 WebView
여기어때 앱은 다양한 서비스를 제공하며, 네이티브로 직접 구현된 페이지가 대부분입니다. 하지만 항공, 항공+숙소, 렌터카, 예약 내역, 주문서, 이벤트, 공지사항 등은 웹뷰를 통해 제공되고 있죠. 웹뷰는 빠르게 서비스를 확장할 수 있는 장점이 있지만, 그 과정에서 어려움도 있었습니다.
앱 출시후 초창기에는 웹뷰로 제공되는 서비스가 많지 않아서 비교적 간단했습니다. 새로운 Activity를 만들고, 해당 페이지에 맞는 브릿지 인터페이스를 정의해서 연동하면 됐죠. 그 당시만 해도 서비스 규모가 작았기 때문에 큰 어려움 없이 진행할 수 있었습니다.
하지만 서비스가 확장되면서 상황이 달라졌습니다. 웹뷰로 제공되는 페이지가 늘어나고, 페이지별로 연동해야 하는 인터페이스도 다양해지면서 관리가 복잡해지기 시작했습니다.
서비스별로 새로운 Activity가 계속 추가되다 보니, 관리해야 할 페이지가 점점 많아졌습니다. 당연히 코드도 복잡해지고, 유지보수에도 시간이 들기 시작했습니다. 새로운 기능을 추가할 때마다 겹치는 부분이 많아지고, 개발 속도도 점점 느려졌습니다. 페이지마다 사용하는 웹뷰 연동 규격이 다르다 보니, 연동할 때마다 어떤 규격을 써야 하는지 확인해야 했습니다. 특히, 웹페이지가 변경될 때마다 관련 부서와 일일이 협의해야 해서 번거로움이 많았습니다.
그래서 우리팀이 내린 결론은 “통합”이었습니다.

모든 웹뷰 페이지를 하나의 Activity에서 관리하고, 통합된 브릿지 인터페이스를 적용하기로 하였습니다. 이렇게 하면 이점이 더 많다고 생각했습니다.
우선, 하나의 통합 규격을 사용함으로써 코드의 일관성이 유지되고, 새로운 페이지를 추가할 때 기존 규격을 그대로 활용할 수 있어 개발 속도가 빨라집니다. 무엇보다, 웹페이지마다 규격을 일일이 확인할 필요가 없어져 부서 간 협업도 훨씬 원활해질 것으로 보았습니다.
그래서 팀 내부 프로젝트로 아래와 같은 목표를 잡고 진행하였습니다.
기존 파편화된 웹뷰를 하나의 공통된 웹뷰로 사용할 수 있도록 구조를 단순화하고 앱, 웹간 연동 규격을 통일화하여 하나의 인터페이스로 사용할 수 있도록 한다.
통합 웹뷰 연동 규격 통일화 : 브릿지 방식으로의 전환
통합 웹뷰 프로젝트의 첫 단계로 연동 규격 통일화 작업을 진행했습니다. 기존에는 웹뷰 연동 시 Scheme 방식과 브릿지 방식이 혼재되어 사용되고 있었는데, 이러한 이중 구조는 개발 복잡성을 높이고 유지보수를 어렵게 만들었습니다.
Scheme 방식을 대체하기 위해 새로운 브릿지 인터페이스 규격을 설계했습니다. 새로운 브릿지 인터페이스를 기반으로 통합 웹뷰 연동 규격서를 작성하였으며, 이는 웹페이지 개발 부서가 명확한 기준을 바탕으로 개발할 수 있도록 하는 데 중요한 역할을 했습니다. 각 부서에 규격서를 전달하고, 규격서에 기반한 개발이 원활히 진행될 수 있도록 가이드를 제공했습니다.

연동 규격서 샘플
웹뷰에서 앱 토스트 메시지를 띄우는 연동 규격입니다. 브릿지 인터페이스 메소드명과 각 파라미터에 대한 명세를 작성하고, 추가 안내가 필요한 사항은 비고란에 작성하였습니다. 또한 해당 기능이 적용된 앱버전과 플랫폼(iOS, Android)을 태그로 표시하였습니다.
이렇게 기존에 파편화된 규격들을 컨플루언스 문서에 정리하였습니다. 사용하지 않는 규격은 삭제하고 중복되거나 비슷한 인터페이스는 하나의 규격으로 사용하거나 신규로 규격을 만들어서 제공하기로 하였습니다.
정리된 연동 규격서를 바탕으로 앱개발팀에서는 기존 코드를 리펙토링하면서 하나의 페이지에 웹뷰와 브릿지 인터페이스를 구현해 관리하기 편한 구조로 변경을 하였습니다. 이러한 작업을 통해 혼란스러웠던 연동 환경을 단순화하고, 개발자들이 보다 명확한 기준을 가지고 작업할 수 있는 환경을 마련했습니다.
지금까지 통합웹뷰를 구축하기까지의 과정을 적어보았습니다.
지속적인 규격 관리와 개선을 통해 협업 효율성을 높였고, 이를 기반으로 서비스 확장에도 더욱 탄력적으로 대응할 수 있는 환경을 마련했습니다. 이러한 경험이 비슷한 고민을 하고 있는 개발자분들에게 작은 인사이트가 되길 바랍니다.
끝까지 읽어주셔서 감사합니다!