ETC

네이티브 앱에서 하이브리드 앱으로

partner_jun 2024. 9. 25. 22:09

모바일 기기의 성능이 압도적으로 좋아지면서 하이브리드 앱의 한계를 느끼기 어려워졌다. 웹 개발이라는 특성상 빠른 배포로 다양한 실험을 진행함으로써 지표를 확인할 수 있고, 특히 앱 심사라는 골치아픈 문제를 피해갈 수도 있다는 점도 큰 장점이다. 토스를 필두로 실제 서비스에 적용하는 사례가 많아지면서 다니고 있는 회사에서도 적용하겠다는 목표가 세워졌다. 실제 개발에 들어가는 것은 몇 달 뒤가 될 것 같지만 어떤 점을 고려해야 할지 미리 생각해두었다.

 

 

고려해야 할 것들

Android

뒤로가기(Back Key)

안드로이드는 물리적 버튼(요새는 제스처)으로 뒤로 가기가 가능하다는 점을 고려해야 한다. 브라우저인 웹뷰 자체에서 '뒤로 가기'를 해 버리므로 의도하지 않은 동작을 할 가능성이 높다. 특히 앱에 노출되는 화면이기 때문에 모달(팝업이나 바텀 시트 등)이 노출되었을 때 자연스럽게 '뒤로 가기' 버튼을 누르게 된다. 이 동작을 적절하게 핸들링하지 않았다면 페이지 자체가 이동되어 끔찍한 UX를 선사하게 된다. 이런 문제를 해결하기 위해 윈도우 객체에 이벤트 핸들러를 추가할 수 도 있겠지만, search param이나 hashbang 등 URL을 이용한 동작으로 페이지 이동을 시뮬레이팅하는 것이 이상적이다. Next.js에서는 이런 구현을 위해 Parallel Routes를 지원해주고 있으며, router 등을 이용해 직접 구현하는 것도 크게 어렵지 않다.

 

IOS

Swipe Back

IOS는 기본적으로 열려 있는 뷰를 스와이프하는 특별한 동작이 가능하다. 이 '스와이프 백'은 안드로이드의 '뒤로 가기' 버튼과 마찬가지로 이전 페이지로 이동할 수도 있고, 뷰 자체를 닫아 버릴 수도 있다. 먼저 '뒤로 가기' 동작을 허용했다고 생각하면 '캐시된' 이전 페이지가 스와이프하는 현재 뷰의 아래에 깔려 보이게 된다(BF 캐시를 이용한 이전 화면). 만약 이전 화면이 모달(팝업/바텀시트)이며 위에서 언급한 URL 이동으로 구현되어 있다면 모달이 없는 화면을 모달이 있는 화면이 덮고 있는 상황이 될 것이며, 이는 스와이프 할 때 매우 어색한 문제를 일으킨다. 두번째로 뷰 자체를 닫아 버리는 경우, 새 웹뷰를 통한 인증 등 이탈을 막아야 하는 흐름에서 추가적인 예외 처리를 해야 한다. 그렇기 때문에 앱 자체에서 웹뷰와 브릿지를 이용해 특정 상황에서 스와이프 백이 동작되지 않도록 설정하는 것이 무난하다. 이 작업은 22년 하반기 회고에서 작성하기도 했다.

요거.

 

페이지 이탈

IOS는 물리적으로 페이지를 이탈할 수 있는 방법이 없다(위에서 언급한 SwipeBack이 있긴 하지만). 그렇기 때문에 주로 페이지 왼쪽 상단의 '뒤로가기' 버튼을 사용하게 되는데, JS가 로드 되지 않는 경우 이 버튼이 동작하지 않을 수 있다. 주로 버튼에 클릭 핸들러를 추가하는데 이 클릭 핸들러 함수 자체가 번들링되기 때문이다. 매우 느린 인터넷 환경, 혹은 네트워크 오류로 인해 JS 파일이 제대로 실행되지 않고 있다면 페이지를 닫을 방법이 없어지고, 이 말은 곧 앱을 강제 종료해야 한다는 뜻이다. 그렇기 때문에 이런 최악의 경우에도 페이지를 이탈할 수 있는 방법을 강구해야 한다.

 

 

공통

브릿지 라이브러리 개발

앱과 기능을 통신하기 위한 브릿지 함수를 개발하고 관리해야 한다. 이 부분은 아주 기초적인 것으로 대부분의 회사, 도메인에서 이미 준비되어 있다. 특이한 것은 Jsonp과 유사하게 콜백 함수를 실행하도록 한다는 것인데, 이게 제대로 동작하지 않을 때 Sentry와 같은 클라이언트 로그 시스템에 오류가 남는다는 것이다. 가능한대로 Inbound Filter 처리해두긴 했지만 꽤나 신경쓰이는 문제다.

 

성능

브라우저라는 샌드박스에서 기동되는 웹 페이지는 당연히 네이티브 앱보다 느리다. 모바일 기기의 성능이 좋아졌지만 네이티브 앱과 비교하면 상대적으로 느린데, FE 특성상 철저히 관리하지 않으면 더 느려질 가능성이 높다. 느려진 페이지는 앱의 품질 자체를 떨어뜨리므로 항상 신경써야 한다. 특히 IOS는 위에 적은 것처럼 페이지 이탈 자체가 불가능해지는 이슈도 발생할 수 있다는 점을 주의해야 한다. 번들 분석 같은 기본적인 작업을 모두 끝냈는데도 느리다면, 성능을 끌어올리기 위해 도메인을 분리하는 방법도 있다. 마이크로 프론트엔드에 입각해 기능별로 도메인을 분리하여 번들의 물리적인 크기 자체를 줄여버리는 것이다. h2 이후로 다운로드 시간은 신경 쓰이지도 않는 문제가 되었기에 번들 파일의 크기가 줄어들면 페이지의 실행 속도는 눈에 띄게 빨라진다. 하지만 도메인을 분리하면 각 도메인별로 권한(GPS나 알람 등)을 허용해주어야 하고, local(session) storage 공유가 불가능한 문제가 있다. 그래서 최근 gateway proxy를 이용해 하나의 도메인으로 사용자에게 서비스를 제공하는 곳이 많아졌다.

 

 

Sleep-wake, onPageShow update

앱이라는 특성상 최소화-활성화를 핸들링해야 한다. 간단하게는 페이지를 새로고침 할 수 도 있고, API에 데이터를 재요청하는 방법도 있다. 특히 웹뷰를 여러개 띄웠을 때, 다른 웹뷰에서 갱신된 데이터를 새로 가져와 보여주어야 하는 경우가 많다. 이 내용은 BF캐시와 관련된 문서에 작성했었다.

 

Long touch Selection

텍스트나 이미지를 길게 눌렀을 때 동작을 제어할지 판단해야 한다. 텍스트를 선택할 수 있거나(파란 색 셀렉션) 이미지를 저장하거나 하는 기능 비활성화를 고려해야 한다는 뜻이다. 이전 회사에서 함께 일했던 앱 개발자는 이것이 완성도의 차이라고 했다. 그때까지는 별 생각이 없었지만 그 이야기를 듣고부턴 계속 신경쓰인다...

 

File Selection

웹뷰에서 파일을 선택할 수 있다면 앱에서 어떤 식으로 허용해줄지 핸들러를 설정해야 한다. 특히 안드로이드의 경우 확장자나 다중 파일 선택 등을 앱에서 제어하므로, 관련된 문제가 발생했을 때 HTML과 안드로이드 양 쪽 확인이 필요하다.

 

Client Version, Client log

앱의 버전을 체크하고 로깅하거나 분기 처리할 수 있는 방법을 강구해야 한다. 경우에 따라서는 API까지 앱의 버전을 전달해야 하는데, 웹뷰를 열 때 요청되는 헤더나 쿠키 등을 이용하는 방법이 일반적이다. 한번 잘 정해두면 크롤러 등 귀찮은 문제를 걸러내는 데에도 도움이 된다.

 

웹뷰 이동 방식 결정

웹뷰 내에서 페이지를 이동해야 할 때 웹 페이지의 리다이렉션을 이동할지 새로운 웹뷰를 띄울지 판단해야 한다. 새로운 웹뷰로 이동하는 경우 기본적으로 더 느리지만, 사용자의 '뒤로 가기'에 무조건 창을 닫는 식의 일관된 동작을 구현할 수 있어 UX 측면에서는 더 좋은 선택일 수 있다. 또 약관을 확인하거나 로그인을 하는 등 이전 동작의 흐름으로 되돌아와야 하는 경우는 이동보다 새로운 웹뷰를 띄우는 것이 더 낫다.

 

 

마치며

비즈니스 측면에서의 문제를 제외하고 생각나는대로 적어두었다. 성능 문제를 제외한다면 크게 이슈가 될 것은 보이지 않는다. 다만 이 성능이라는 것이 네이티브와 상대적으로 비교하게 되니 곤란하다. 잘 될때는 아무 말 없지만 어쩌다 한번 잘 되지 않을 때(특히 네트워크 문제가 있을 때) 하이브리드 웹으로 전환된 것을 느끼게 되고, "왜 전환했냐"는 비난의 대상이 되기 때문이다. 나야 이미 몇 번 경험해서 또 욕하는구나 하고 넘어가지만 함께 작업할 동료들은 부담스러울지도 모르겠다.