React Native 앱을 위한 셀프 호스팅 OTA(Over-The-Air) 업데이트 솔루션이다. 앱스토어 심사 없이 JS 로직과 에셋(이미지, 폰트 등)을 실시간으로 유저에게 배포할 수 있다. 과거에는 Microsoft App Center의 한 기능이었던 'CodePush'가 업계 표준이었으나, 2024년 종료가 공지되면서 RN 진영에 대안이 필요해졌고 그 대표주자로 등장한 것이 hot-updater다.
HotUpdater.wrap이 이를 담당).hot-updater deploy 실행 시)# CLI와 RN 모듈 설치
npm install -D hot-updater
npm install @hot-updater/react-native
# 초기화
npx hot-updater init
프롬프트 질문:
완료되면 루트에 .env.hotupdater와 hot-updater.config.ts가 생성되고,
Supabase에는 필요한 Storage 버킷과 메타데이터 테이블이 자동 세팅된다.
HotUpdater.wrap 적용 (필수)⚠️ wrap은 선택이 아니라 필수다. wrap이 없으면
checkForUpdate,reload등
모든 HotUpdater 메서드가 에러를 던지며, 크래시 자동 롤백 기능도 동작하지 않는다.
기본형 (자동 모드):
import { HotUpdater } from '@hot-updater/react-native';
function App() {
return <YourRootComponent />;
}
export default HotUpdater.wrap({
source: 'https://your-update-server-url', // 또는 baseURL
updateStrategy: 'appVersion', // 'appVersion' | 'fingerprint'
updateMode: 'auto',
reloadOnForceUpdate: true, // force update 시 다운로드 후 자동 reload
fallbackComponent: ({ progress, status, message }) => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>{status === 'UPDATING' ? `Updating... ${Math.round(progress * 100)}%`
: 'Checking for Update...'}</Text>
</View>
),
})(App);
동작:
1. 앱 진입 시 서버에 업데이트 확인
2. 업데이트 존재 시 새 번들 다운로드
3. force update면 다운로드 후 자동 reload, 그동안 fallbackComponent 표시
4. 일반 업데이트면 백그라운드 다운로드 후 다음 실행 시 적용
iOS(AppDelegate)와 Android(MainApplication)에서 jsBundleURL을
HotUpdater.bundleURL()로 바꿔준다. 이렇게 해야 앱 시작 시 로컬에 다운로드된
최신 번들이 있으면 그걸 로드하고, 없으면 기본 번들을 로드한다.
# 일반 배포
npx hot-updater deploy
# 인터랙티브 + 강제 업데이트
npx hot-updater deploy -i -f
-i (--interactive): 채널·플랫폼 등을 대화형으로 선택-f (--force-update): 이번 배포를 force update로 표시hot-updater의 기본 동작은 Silent Update다.
1차 실행에서 백그라운드 다운로드 → 2차 실행에서 적용. UX를 해치지 않기 위한 업계 표준 방식이다.
치명적 버그 픽스 등 즉시 적용이 필요하면 두 가지 방법이 있다:
방법 A — wrap의 force update 활용 (권장)
배포할 때 -f 플래그로 force update로 마킹하고, wrap의 reloadOnForceUpdate: true를 켜둔다.
서버가 forceUpdate를 내려주면 wrap이 자동으로 다운로드 → 즉시 reload까지 처리하며,
그동안 fallbackComponent가 화면을 가린다.
방법 B — 수동(manual) 모드
유저에게 알림을 띄우는 등 커스텀 UX가 필요할 때:
import React, { useEffect } from 'react';
import { Alert, View, Text } from 'react-native';
import { HotUpdater } from '@hot-updater/react-native';
function App() {
useEffect(() => {
(async () => {
try {
const updateInfo = await HotUpdater.checkForUpdate({
updateStrategy: 'appVersion',
});
if (!updateInfo) return;
Alert.alert(
'업데이트 안내',
'새로운 버전이 있습니다. 지금 업데이트할까요?',
[{
text: '확인',
onPress: async () => {
// 1) 번들 다운로드 (이게 빠지면 reload해도 적용될 게 없음)
await updateInfo.updateBundle();
// 2) 강제 새로고침
await HotUpdater.reload();
},
}],
{ cancelable: false },
);
} catch (e) {
console.log('업데이트 확인 실패:', e);
}
})();
}, []);
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>현재 앱 화면 (버전 1.0.0)</Text>
</View>
);
}
// wrap은 manual 모드에서도 필수다.
export default HotUpdater.wrap({
source: 'https://your-update-server-url',
updateStrategy: 'appVersion',
updateMode: 'manual',
})(App);
핵심 포인트:
checkForUpdate()는 확인만, 실제 다운로드는
updateInfo.updateBundle()을 호출해야 일어난다. 그 후HotUpdater.reload()로 즉시 반영.