# CodePush 또는 EAS Update에서 Mocco 호스팅 OTA로 옮기기

Mocco는 Expo Updates 프로토콜을 제공하므로 앱은 기본 `expo-updates` 클라이언트를 그대로 씁니다. 옮기려면 새 업데이트 URL이 들어간 새 바이너리를 배포해야 합니다. 다른 곳을 가리키는 채로 이미 설치된 바이너리로는 업데이트를 옮길 수 없습니다. 대부분의 사용자가 새 바이너리로 바꿀 때까지 두 서비스를 함께 운영하세요.

## EAS Update에서 옮기기

EAS Update도 `expo-updates`를 쓰므로 코드는 그대로입니다.

| EAS Update | Mocco |
|---|---|
| `updates.url` `https://u.expo.dev/<project>` | **OTA updates** → **Hosted by Mocco**의 매니페스트 URL (`mocco ota init`이 기록합니다) |
| `eas update --channel` | `mocco ota publish --channel` (또는 `ota-publish` 액션) |
| 채널과 브랜치 | 채널. 릴리스는 채널 사이에서 승격되며 다시 업로드하지 않습니다 |
| 코드 서명(선택) | 필수: `mocco ota init`이 키와 인증서를 만듭니다 |
| `eas update:rollback` | **Roll back**(미리 서명되어 즉시 적용) 또는 **Roll back to embedded** |
| 롤아웃 | `--rollout <percent>`와 채널 컨트롤 |

`runtimeVersion`은 그대로 두세요. Mocco도 EAS처럼 플랫폼과 런타임 버전별로 업데이트를 제공합니다.

## App Center CodePush에서 옮기기

CodePush는 다른 클라이언트가 필요합니다. `react-native-code-push`를 `expo-updates`로 바꿉니다. 네이티브 React Native 앱에는 `npx install-expo-modules`로 Expo 모듈을 추가한 뒤 `npx expo install expo-updates`를 실행합니다.

| CodePush | Mocco |
|---|---|
| 배포 키(`Staging`, `Production`) | `expo-channel-name`의 채널. `production`을 보호합니다 |
| `appcenter codepush release-react` | `mocco ota publish --channel staging` |
| `promote Staging Production` | **Promote**(보호된 채널에서는 승인이 필요합니다) |
| `--rollout 20` | `--rollout 20` |
| `--mandatory`와 `installMode` | `--mandatory`. 앱이 다음 안전한 시점에 적용합니다 |
| `rollback` | **Roll back**(즉시 적용, 미리 서명됨) |
| 대상 바이너리 버전(`--targetBinaryVersion`) | `runtimeVersion`(`app.json`에 설정합니다. 예: `appVersion` 정책) |

`codePush()` 래퍼와 `checkFrequency`를 제거하세요. `expo-updates`는 기본적으로 실행할 때 확인합니다.

## 전환 순서

1. 호스팅을 설정합니다([Mocco에서 OTA 업데이트 호스팅하기](https://www.mocco.club/docs/ko/articles/em6rkw-hosted-updates)). 앱, 인증서, 채널, CI를 준비합니다.
2. Mocco 설정으로 빌드한 바이너리를 배포합니다. 이전 바이너리를 위해 기존 서비스에도 계속 배포합니다.
3. 이전 바이너리가 아직 쓰이는 동안에는 모든 OTA 릴리스를 두 곳에 함께 배포합니다. Mocco의 도입 현황 수치로 새 바이너리의 릴리스를 실행하는 기기가 얼마나 되는지 확인할 수 있습니다.
4. 이전 바이너리의 비중이 무시할 만큼 줄어들면 기존 서비스 배포를 중단합니다.
