React Native 앱 배포 자동화 여정(feat. EAS, Expo)

EAS(Expo Application Services)는 Expo 팀에서 제공하는 클라우드 서비스로, React Native 앱의 빌드, 제출, 배포를 쉽게 만들어주는 서비스입니다.

문제 상황

React Native로 앱을 개발하면서 다음과 같은 어려움이 있었습니다

  • 빌드 설정: iOS와 Android 각각의 빌드 환경을 설정하고 관리하는 것이 번거로웠습니다.

  • 수동 배포: 앱스토어 배포를 위해 수동으로 빌드하고 업로드하는 과정이 필요했습니다.

  • 심사 과정: 간단한 버그 수정이나 기능 개선시에도 스토어 심사를 거쳐야 했습니다.

  • 휴먼 에러: 배포 과정에서 실수가 발생할 위험이 있었습니다.


기존 방식

기존의 배포 프로세스를 작성해보겠습니다.

Step1: 로컬에서 iOS/Android 개발 환경 설정(expo prebuild)

Step2: Xcode/Android Studio에서 수동으로 빌드

Step3: 각 스토어 콘솔에 접속하여 수동으로 업로드

Step4: 스토어 심사 제출 및 대기

Step5: 심사 완료 후 배포

이 과정은 많은 시간이 소요되고 휴먼 에러가 발생할 수 있었습니다.


들어가기 전에

EAS CLI

EAS CLI는 Expo 앱의 빌드, 배포, 업데이트를 관리하는 명령줄 도구입니다.

(로컬에서 테스트하실 때 다운로드 받아주세요!)

# <https://github.com/expo/eas-cli>
$ npm install -g eas-cli

EAS Project 생성

EXPO_TOKEN

Login한 계정이름을 {account_name}에 넣어주세요!

https://expo.dev/accounts/{account_name}/settings/access-tokens

EAS_PROJECT_ID

생성한 {project_name}에 넣어주세요

https://expo.dev/accounts/{account_name}/projects/{project_name}

app.config.js

생성한 프로젝트의 name, slug, project_id, ios.bundleIdentifier, android.package, owner 이름을 파일에 추가해주세요

export default {
  expo: {
    name: {name},
    slug: {slug},
    updates: {
      url: "<https://u.expo.dev/{project_id}>"
    },
    ios: {
      bundleIdentifier: "com.kr.moeum",
    },
    android: {
      package: "co.kr.moeum",
    },
    extra: {
      eas: {
        projectId: {project_id}
      }
    },
    owner: {owner}
  }
};

eas credentials

첫 Build시에는 credentials로 인증정보를 등록해주셔야 합니다.


EAS 도입

문제 해결을 위해 Expo의 EAS(Expo Application Services)를 도입하고 Github Action을 연동하여 워크플로우를 구축했습니다

Update Service

Javascript 코드 변경사항을 스토어 심사 없이 즉시 배포할 수 있는 Over-the-Air(OTA) 업데이트 지원하고 있는데요.

Update Service: EAS Update 동작 방식

Step1: 업데이트할 JS 번들을 EAS 서버에 업로드

Step2: 앱이 실행될 때 새로운 업데이트가 있는지 확인

Step3: 새 업데이트가 있다면 백그라운드에서 다운로드

Step4: 다음 앱 실행 시 새 버전 적용

Update Service: Github Action 연동

[샘플코드]

name: EAS Update

env:
  EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}         # https://expo.dev/accounts/{account_name}/settings/access-tokens
  EAS_PROJECT_ID: ${{ secrets.EAS_PROJECT_ID }} # https://expo.dev/accounts/{account_name}/projects/{project_name}

on:
   pull_request:
     types: [opened, synchronize]
  workflow_dispatch:

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - name: 🏗 Setup repo
        uses: actions/checkout@v3
     
      - name: 🏗 Setup EAS
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          token: ${{ env.EXPO_TOKEN }}
	    
	    - name: 🔧 Initialize EAS Project
        run: yes | eas init --id ${{ env.EAS_PROJECT_ID }}

      - name: 🚀 Create Preview
        id: preview
        uses: expo/expo-github-action/preview@v8
        with:
          command: eas update --auto --branch ${{ github.event.pull_request.head.ref || inputs.branch }} --platform all --message "App Update (#${{ github.event.pull_request.number || github.run_number }})"
          comment: true

Build Service

iOS와 Android 앱을 클라우드에서 빌드하는 서비스인데요.

Build Service: EAS Build 동작 방식

Step1: 소스코드와 빌드 설정을 EAS 빌드 서버로 전송

Step2: 클라우드 환경에서 네이티브 빌드 실행

Step3: 빌드된 바이너리 파일(.ipa/.aab) 생성

Step4: 생성된 파일을 EAS 서버에 저장

Build Service: Github Action 연동

[샘플코드]

name: EAS Build

env:
  EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}         # https://expo.dev/accounts/{account_name}/settings/access-tokens
  EAS_PROJECT_ID: ${{ secrets.EAS_PROJECT_ID }} # https://expo.dev/accounts/{account_name}/projects/{project_name}

on:
  workflow_dispatch:
      inputs:
      platform:
        type: choice
        description: "Build Platform"
        required: true
        options:
          - ios
          - android
          - both

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - name: 🏗 Setup repo
        uses: actions/checkout@v3
     
      - name: 🏗 Setup EAS
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          token: ${{ env.EXPO_TOKEN }}
	    
	    - name: 🔧 Initialize EAS Project
        run: yes | eas init --id ${{ env.EAS_PROJECT_ID }}

      - name: 🚀 Create Build - iOS
        if: ${{ github.event.inputs.platform == 'ios' || github.event.inputs.platform == 'both' }}
        id: ios-build
        uses: expo/expo-github-action/preview@v8
        with:
          command: eas build --profile preview --platform ios --clear-cache --non-interactive --no-wait
          comment: false
      
      - name: 🚀 Create Build - Android
        if: ${{ github.event.inputs.platform == 'android' || github.event.inputs.platform == 'both' }}
        id: android-build
        uses: expo/expo-github-action/preview@v8
        with:
          command: eas build --profile preview --platform android --clear-cache --non-interactive --no-wait
          comment: false

Submit Service

App Store와 Play Store에 자동 제출을 도와주는 서비스인데요.

Build Service: EAS Submit 동작 방식

Step1: 빌드된 바이너리 파일 검증

Step2: 스토어별 메타데이터 준비

Step3: 각 스토어의 API를 통한 자동 제출

Step4: 제출 상태 모니터링

Submit Service: Github Action 연동

[샘플코드]

name: EAS Submit

env:
  EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}          # https://expo.dev/accounts/{account_name}/settings/access-tokens
  EAS_PROJECT_ID: ${{ secrets.EAS_PROJECT_ID }}  # https://expo.dev/accounts/{account_name}/projects/{project_nam

on:
  workflow_dispatch:
      inputs:
      platform:
        type: choice
        description: "Submit Platform"
        required: true
        options:
          - ios
          - android
          - both

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - name: 🏗 Setup repo
        uses: actions/checkout@v3
     
      - name: 🏗 Setup EAS
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          token: ${{ env.EXPO_TOKEN }}
	    
	    - name: 🔧 Initialize EAS Project
        run: yes | eas init --id ${{ env.EAS_PROJECT_ID }}

      - name: 🚀 Create Submit - iOS
        if: ${{ github.event.inputs.platform == 'ios' || github.event.inputs.platform == 'both' }}
        id: ios-build
        uses: expo/expo-github-action/preview@v8
        with:
          command: eas submit --profile production --platform ios --clear-cache --non-interactive --no-wait
          comment: false
      
      - name: 🚀 Create Submit - Android
        if: ${{ github.event.inputs.platform == 'android' || github.event.inputs.platform == 'both' }}
        id: android-build
        uses: expo/expo-github-action/preview@v8
        with:
          command: eas submit --profile production --platform android --clear-cache --non-interactive --no-wait
          comment: false

도입결과

JS 업데이트 (코드 푸시)

  1. 개발자가 코드 변경사항을 브랜치에 푸시

  2. GitHub Actions 자동 트리거

  3. EAS Update로 JS 번들 빌드

  4. OTA 업데이트 배포

  5. 사용자 앱에 즉시 반영

네이티브 업데이트: 알파/베타 (수동 트리거)

  1. GitHub Actions의 워크플로우를 수동으로 트리거

  2. EAS Build로 iOS/Android 빌드

네이티브 업데이트: 스토어 (수동 트리거)

  1. GitHub Actions의 워크플로우를 수동으로 트리거

  2. EAS Build로 iOS/Android 동시 빌드

  3. 빌드 완료 후 자동으로 EAS Submit 실행

  4. 각 스토어에 자동 제출

  5. 스토어 심사 후 배포

여러분의 프로젝트에도 도움이 되길 바랍니다 🙏


문제 해결 가이드

의존성 검사

프로젝트의 의존성과 EAS를 사용하기 위한 검사로 다음 명령어를 실행해보세요

# 문제 확인
npx -y expo-doctor
# 의존성 체크 및 설치
npx expo install --check

버전 관리

자동으로 빌드 버전과 번호를 증가시키기 위해 eas.json에 다음과 같이 설정해보세요

(app.config.js는 초기 설정값입니다)

{
  "cli": {
    "appVersionSource": "remote" // 버전관리를 EAS 서버에서 해요.
  },
  "build": {
      "production": {
	      "channel": "production",
	      "autoIncrement": true // EAS가 자동으로 버전을 증가시켜요.
	    }
  }
}

Package Manager

pnpm의 의존성 설치방식에서 발생하는 문제를 해결하기 위해 .npmrc 파일을 생성하고 다음과 같이 설정해보세요

node-linker=hoisted

참고문서

Last updated