React Native Code Push로 배포하기

정슬아
None
Published in
6 min readApr 4, 2021

안녕하세요. 휴먼스케이프 Software Engineer Dia입니다. 😀

모바일 앱은 웹 앱과는 다르게 업데이트 버전을 바로 배포할 수 없고 앱스토어와 구글 플레이 스토어 각 플랫폼의 심사를 거쳐 사용자에게 배포 되는데요, 앱 심사 기간은 짧게는 24시간 이내, 길게는 7일이 소요될 수 있으며, 다양한 이유로 심사 기간이 지연되거나 업데이트가 거부될 수 있습니다. 하지만 서비스 운영을 하다 보면 업데이트 내용에 따라 번거로운 심사 과정 없이 바로 배포가 이루어질 필요가 있는 경우가 있습니다.

휴먼스케이프의 레어노트앱은 React Native로 만들어지고 있는데요, React Native에서는 CodePush를 이용해 스토어 플랫폼 심사 없이 업데이트 버전을 바로 배포할 수 있습니다. 코드푸시는 리액트 네이티브의 큰 장점 중 하나라고 할 수 있습니다.

오늘은 레어노트 서비스에서 CodePush를 어떻게 사용하고 있는지 소개해 드리겠습니다.

CodePush란?!

CodePush는 MS에서 만든 오픈소스로 React Native나 Apache Cordova로 개발한 앱을 심사과정 없이 바로 업데이트 할 수 있도록 해주는 서비스입니다.

특정 업데이트를 중앙 저장소 역할을 하는 App Center에 JS Bundle과 assets을 업로드하면 모바일 클라이언트는 앱 시작 시 마다 업데이트 버전이 있는지 확인하여 동기화 합니다.

눈치채셨겠지만, 코드 푸시는 js 단에서의 변경 사항만 관리할 수 있으며, 네이티브 코드와 관련된 모든 변경사항(AppDelegate.m/MainActivity.java 파일의 수정, 라이브러리 추가 등)은 스토어 플랫폼을 통해 배포되어야 합니다.

CodePush 적용

본 포스팅 에서는 코드 푸시 라이브러리를 설치하고, 앱을 등록하는 세팅 과정은 생략합니다.

코드 푸시 업데이트 유형

코드 푸시는 mandatoryoptional 두 가지 유형의 업데이트를 제공할 수 있으며, 업데이트 유형에 따라 다른 업데이트 전략을 정의할 수 있습니다.

CodePush HOC 적용

코드 푸시는 코드에 대한 새로운 업데이트가 있는지 확인하고 새로운 변경 사항으로 앱을 다시 로드하는 CodePush의 HOC (고차 컴포넌트)에 Root Component를 래핑하는 것으로 간단하게 적용할 수 있습니다.

이 때 업데이트 유형에 따라 다양한 옵션을 정의할 수 있습니다.

// Wrapper function
codePush(rootComponent: React.Component): React.Component;
codePush(options: CodePushOptions)(rootComponent: React.Component): React.Component;

기본 옵션은 아래와 같이 적용됩니다.

  • 앱이 재시작(codePush.CheckFrequency.ON_APP_START) 될 때마다 코드 푸시 업데이트 체크
  • mandatory 업데이트는 즉시 다운로드 & 설치(codePush.InstallMode.IMMEDIATE)
  • optional 업데이트는 업데이트 파일은 다운로드 해 두었다가 다음번 앱이 재 시작 될 때 설치(codePush.InstallMode.ON_NEXT_RESTART)

추가적으로, updateDialog 옵션을 정의하여 업데이트가 있을 때 유저에게 업데이트를 즉각적으로 설치 할지에 대한 Alert를 띄울 수 있는데 이 경우 앱스토어 정책에 위반되어 리젝사유가 될 수 있으니 주의해야 합니다.

런타임 단계의 업데이트 방지

위와 같이 코드 푸시를 구성하게 되면 사용자가 앱의 첫 화면에 진입하여 사용하기 시작하던 중 갑자기 업데이트가 설치되어 앱이 재실행되는 경험을 하게 됩니다.

이는 코드 푸시의 비동기성 때문인데요, 불편한 사용자 경험을 개선하기 위해 코드 푸시 동기화가 완료된 후 앱에 진입할 수 있도록 useCodePush 커스텀 훅을 구성하여 코드 푸시 동기화 상태를 체크하도록 했습니다.

그리고 App.js에서는 코드 푸시 동기화 작업이 진행 중이면 동기화 진행 상태를 보여주는 뷰(SyncProgressView)를 렌더하고, 작업이 끝나면 앱의 첫 화면에 진입할 수 있도록 구성했습니다.

이 때, 동기화 진행 상황을 표시하지 않고 스플래시 스크린 아래에서 동기화 작업을 모두 진행할 수 있지만, 네트워크 상황 등에 따라 코드 푸시 동기화에 소요되는 시간이 오래 걸릴 수 있기 때문에 진행 상황을 알 수 있도록 SyncProgressView를 구성하여 더 나은 사용자 경험을 제공하도록 했습니다.

버저닝 규칙

코드 푸시를 활용할 때 유의해야할 점 중 하나는 버저닝 관리 입니다. 코드 푸시를 활용하면 업데이트를 두 가지 방법(스토어를 통해, 코드 푸시를 통해)으로 할 수 있기 때문에 각 버전이 혼동 되어선 안되며, 버전 분기도 사용자가 최종적으로 사용하고 있는 버전에서 진행되어야 합니다.

레어노트 에서는 major.minor.patch 버저닝 규칙을 사용하고 있는데, 코드 푸시 릴리즈는 binary version에는 영향을 미치지 않기 때문에 코드 푸시로 업데이트 되는 hotfix에 대해서는 major.minor.patch-hotfix로 표기하기로 하였습니다.

만약, 바이너리 버전 v1.0.0에 대해 업데이트 버전을 코드 푸시를 통해 릴리즈 한다면 그 버전은 v1.0.0–1가 됩니다. 여기서 또 한 번의 업데이트가 코드 푸시를 통해 릴리즈 된다면 그 버전은 v1.0.0–2가 되며, 이는 사용자가 최종적으로 사용하고 있는 버전인 v1.0.0–1에서 분기 및 테스트 되어져야 합니다.

추가적으로, 앱 센터에서 관리되는 코드 푸시 버전 넘버는 v20 과 같이 표기 되는데, 이는 코드 푸시만을 위한 버전 넘버로, 커스텀이 불가합니다. 이로인한 혼선을 피하기 위해 코드 푸시 릴리즈 시 --description옵션에 major.minor.patch-hotfix 버전을 표기하여 관리하고 있습니다.

정리

오늘은 리액트 네이티브 환경에서 코드 업데이트를 하는데 뛰어난 유연성을 제공하는 코드 푸시 도입에 대해 공유 드렸는데요, 코드 푸시 도입을 고려하고 계신 분들께 조금이나마 도움이 되었으면 하는 바람입니다. 감사합니다.

--

--