Ionic Appflow - Ionic CI/CD 구축하기

Appflow 란?

- Appflow를 통해, 웹 및 기본 빌드를 효과적으로 생성하고, 라이브 앱 업데이트를 푸시하고, 앱 스토어에 앱을 게시하고, 전체 프로세스를 자동화할 수 있습니다.

- React Native의 Code Push 기능처럼 심사없이 앱을 지속적으로 업데이트할 수 있다.(무료 버전은 웹 관련 수정 내용만)

- 시작하기 : https://ionic.io/docs/appflow/quickstart

- 연 100만달러 미만의 수익을 얻는 앱이면 무료로 적용 가능

- Appflow는 Git 버전 제어와 직접 작동하며 기존 코드 베이스를 배포 및 패키지 빌드의 정보 소스로 사용함

- Appflow에 직접 푸시할 수도 있으나, Github를 통합하면 Appflow가 코드에 액세스할 수 있음

 

Appflow 기본 설정

- Ionic Appflow 대시보드 링크 :  https://dashboard.ionicframework.com

- 대충 가입하고, Github 연동하고, 커밋에서 빌드 생성(IOS, Android, Web 중 Web)하면 된다.

 

Appflow Ionic Capacitor 프로젝트에 적용하기 (SDK 활용)

- https://ionic.io/docs/appflow/deploy/setup/capacitor-sdk

# bugfix : capacitor 5.x 버전을 사용하는 경우 1.3.0으로 설치해야 했음
$ npm install @capacitor/live-updates@1.3.0
$ npx cap sync

의존성 sdk 패키지 설치

// ./capacitor.config.ts
import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.company.appname',
  appName: 'My Capacitor App',
  webDir: 'www',
  plugins: {
    LiveUpdates: {
      appId: '042a1261', // Appflow 대시보드에서 확인한 AppId
      channel: 'Production', // Appflow 대시보드에서 확인한 Channel명
      autoUpdateMethod: 'background', // 기본값(알게 모르게 업데이트되는 방식 편함)
      maxVersions: 2 // 기본값(업데이트 버전 최근 몇개까지 로컬에 저장해둘지 정의),
      // enabled: true // 로컬 개발 시 live update를 비활성화 해야하는데, V0.1.3은 해당 변수가 없음...
    }
  }
};

export default config;

LiveUpdates 관련 capacitor 설정 진행 (Appflow 상에서 관리하는 AppId와 Channel명 등 입력하여 SDK 기본 설정 진행)

  • appId는 Appflow 대시보드에서 앱 업데이트 정보를 받기위해 필요합니다.
  • channel은 Appflow 대시보드에서 앱 업데이트 정보를 받기위해 필요하며, 스마트폰이 업데이트를 수신할 채널을 나타냅니다.(channel별로 다르게 빌드를 구성할 수 있는 듯?)
  • autoUpdateMethod : 'background' -> 자동 업데이트의 권장 방식으로써, 업데이트가 Appflow 상에 있으면 사용자가 이전 버전을 사용하는 동안 업데이트가 다운로드되어 설치됩니다. 다음에 앱을 실행하면 새 버전이 로드되는 식으로 동작합니다.(별도의 코딩이 필요 없이 SDK에서 로직을 자동으로 처리하므로 권장합니다.)
  • maxVersions : 기기에 캐시된 상태로 유지할 앱의 최대 버전의 개수입니다.
    사용자 기기에 캐시된 라이브 업데이트를 롤백하는 경우 Appflow 서버에서 검색할 필요가 없으므로 즉시 로드된다는 장점이 있습니다.
  • enabled : Live Updates 활성화 여부(로컬 개발 시에는 false로 지정, autoUpdateMethod를 'none'으로 지정하여 동일한 효과를 낼 수 있지 않을까 싶음)

 

로그인한 사용자에 따라서, 다른 버전(staging or production)으로 자동업데이트 수행하기

 

이를 위해서는 먼저, autoUpdateMethod : 'none'(수동)으로 진행해야 한다.

import * as LiveUpdates from '@capacitor/live-updates';

// App 초기화 함수 내에서 아래 로직 호출
async initializeApp() {

// 현재 로그인한 사용자의 정보를 불러와서, staging 계정이면 staging, production 계정이면 production 버전 업데이트
const loggedInUser = myApi.login(); // myApi.login()은 예시 함수임

// Dynamically set the channel and max versions
await LiveUpdates.setConfig({
  channel: loggedInUser.channel,  // could be beta, production, etc.
  maxVersions: loggedInUser.maxVersions
});

// Retrieve the latest Live Update based on the user-specific configuration
await LiveUpdates.sync();

}

 

Live Updates 빌드 (Appflow 대시보드 상에서 수동 빌드, 무료 버전..)

Native Updates(유료)가 아닌, Live Update 배포는 사용자에게 웹 자산(JavaScript, HTML, CSS, 글꼴 및 이미지)만 포함한 업데이트 버전을 제공합니다.

Appflow 대시보드 "Build"란에서 수동으로 Commit을 선택하여, Build를 진행(Web)합니다.

Live Updates 빌드는 내부적으로 아래와 같은 작업을 수행합니다.

  • npm install : 모든 웹 프로젝트 종속성을 설치
  • npm run build : 빌드된 애플리케이션이 포함된 디렉터리 (기본 www 폴더)가 저장되고 실시간 업데이트에 사용할 수 있습니다.
  • 라이브 업데이트 매니페스트 파일을 생성 : 여기에는 구축된 웹 디렉토리에 있는 모든 파일의 해시가 포함됩니다. Live Update가 배포된 후 기본 앱에 포함된 매니페스트 파일이 Live Update의 매니페스트와 비교됩니다. 수정된 파일만 다운로드되므로( 차등 라이브 업데이트 라고도 함 ) 라이브 업데이트가 작고 성능이 좋습니다.

Channel 설정하기 (Appflow 대시보드 상에서 관리)

라이브 업데이트 채널은 업데이트를 위해 해당 채널을 수신하도록 구성된 모든 Device와 공유될 앱의 특정 웹 빌드를 가리킵니다.

앱에 Live Updates SDK(@capacitor/live-updates)를 설치 하면 해당 채널에 구성된 기본 바이너리는 앱이 처음 열릴 때마다 채널에서 사용 가능한 업데이트를 확인합니다. 원할 때마다 Appflow 대시보드에서 Channel에 매핑된 Build를 변경할 수 있으며 변경 사항을 롤백할 수도 있습니다.

 

기본 채널이 존재하므로, 예를 들어 로컬 장치나 에뮬레이터에서 라이브 업데이트를 시도하는 경우 "Development", QA 팀을 위한 "QA", 사용자가 상호 작용할 앱 스토어 바이너리를 위한 "Production" 등으로 지정할 수 있다.

여러개 설정하는 것은 유료네..

 

빌드 목록에서, 채널을 매핑함으로써 여러 버전에 대해 실시간으로 롤백할 수도 있다.

 

Git 연동 배포 자동화

무료 버전에서는 배포 자동화가 불가능하다.

 

Live Update 빌드하기 (웹 빌드)

 

 

Web Build 버전 관리하기

"Build" 탭에서, 완료된 빌드 상세 화면으로 진입 시, "Versioning" 탭에서 버전관련 설정을 해준다.

업데이트가 호환되는지 여부를 지정하는 최소 및 최대 해당 빌드 버전 번호가 지정됩니다.

이렇게 하면 앱 스토어 내에 배포되는 새로운 기본 빌드가 Appflow에서 현재 사용 가능한 업데이트와 충돌하지 않습니다.

  • 최소:  이 라이브 업데이트를 다운로드하려면  기본 바이너리가  이 버전 이상 이어야 합니다.
  • 최대:  이 라이브 업데이트를 다운로드하려면 기본 바이너리가 이 버전 이하  여야 합니다  .
  • 동등:  네이티브 바이너리가 이 버전인 경우 이 라이브 업데이트를 다운로드 하지 마십시오 . 왜냐하면 동일하기 때문입니다.

https://ionic.zendesk.com/hc/en-us/articles/360003567694-How-to-restrict-Live-Update-by-native-version

  • 버전 1.0.0을 실행하는 사용자는 버전이 최소 버전 요구 사항보다 낮기 때문에 업데이트를 받을 수 없습니다 .
  • 버전 1.0.1을 실행하는 사용자는 해당 버전이 최소 버전 요구 사항을 충족하므로 업데이트를 받게 됩니다 .
  • 버전 1.0.2를 실행하는 사용자는 해당 버전이 해당 버전과 일치하므로 업데이트를 받을 수 없습니다 .
  • 버전 1.0.3~2.0.0을 실행하는 사용자는 해당 버전이 최대 버전 요구 사항을 충족하므로 업데이트를 받게 됩니다 .
  • 버전 2.0.1 이상을 실행하는 사용자는 버전이 최대 버전 요구 사항보다 높기 때문에 업데이트를 받을 수 없습니다 .

현재 Live Update 버전을 1.0.2로 설정해 놓았는데, Native Plugin을 1.0.1부터 추가했다면,,
1.0.0인 버전은 현재 Live Update 버전과 호환이 안되므로, "현재 Live Update 버전"에 대한 "최소 버전"을 1.0.1로 설정하여 1.0.0 사용자는 최신 Live Update 버전을 다운로드할 수 없게 해야 한다.

새로운 AppStore 배포가 필요한 경우 (주의하기)

  • 애플리케이션에서 사용하는 Capacitor Version 업그레이드
  • 프로젝트에서 사용되는 Capacitor 또는 Cordova 플러그인 업그레이드
  • capacitor.config.json파일의 값 수정
  • 애플리케이션 아이콘 또는 스플래시 화면 수정
  • Info.plist또는 AndroidManifest.xml 파일 의 변경을 포함하되 이에 국한되지 않고 Xcode 또는 Android Studio 프로젝트에 적용된 기타 모든 수정 사항

환경변수 설정하기

Appflow 대시보드 "Build" 탭에서 "Environment"을 선택하면, build할 때 환경 변수를 지정해줄 수 있다.

 

프로젝트 package.json 상에서, build 명령어 시 환경변수를 조회해옴

// package.json
...
"scripts": {
  ...
  "build": "BUILD_ENV=${BUILD_ENV:-local} ng build --configuration=$BUILD_ENV"
  ...
}
...

 

// angular.json
...
"configurations": {
  ... // other environment configurations
  "development": {
    "fileReplacements": [ // replace default environment.ts file with the environment.development.ts file
      {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.development.ts"
      }
    ],
  },
  "local": {}, // leave this blank to use the default src/environments/environment.ts file
  ...
}

 

Native(IOS, Android) 구성 설정

- Native Updates 를 하려면 인증서를 업로드 해야함.(마켓 심사 시, Sign 했던 인증서)

- 결국 인증서와 번들 ID(예시. app.xxxxxxx.com)가 필수적

- 그러나 Native Updates는 유료니까 패스

 

로컬 개발 시, Live Updates 끄기

로컬 앱 코드베이스가 배포된 Live Update 빌드와 동일한 채널을 가리키는 경우 코드를 덮어쓰게 됩니다

이러한 상황을 방지하려면 로컬 개발에 대한 실시간 업데이트를 끄면 됩니다. (중요) 앱 스토어에 제출하기 전에 다시 켜십시오.

const config: CapacitorConfig = {
  plugins: {
    LiveUpdates: {
      enabled: false, // 0.1.3 버전은 없으니, autoUpdate: 'none'으로 테스트해야할 듯..
    }
  }
};

 

실시간 업데이트 더 빠르게 하는 방법 (선택 사항, 너무 오래 걸리면 적용)

live-update-manifest.json 파일에는 구축된 웹 디렉터리( 예: www)의 모든 파일에 대한 해시가 포함되어 있습니다. Appflow에서 기본 iOS 또는 Android 빌드가 생성되면 앱의 웹 부분에 대한 매니페스트 파일이 자동으로 생성됩니다. 최종 사용자 장치에 새 라이브 업데이트를 보내면 기본 앱에 포함된 live-update-manifest.json이 라이브 업데이트의 live-update-manifest.json와 비교됩니다. 변경된 파일만 다운로드됩니다.

번들 웹 앱에 매니페스트 파일이 없으면 모든 파일이 다운로드되어 업데이트가 불필요하게 느려집니다.

Capacitor 기반 SDK는 live-update-manifest.json.

 

로컬에서 build할 경우, 자동으로 생성되지 않기 때문에 아래와 같이 조치를 취해주면 나중에 Live Updates 시 성능 향상 효과가 있다.

# Install Appflow CLI (1회 실행으로 global 하게 설치)
curl -fsSL https://ionic.io/get-appflow-cli | bash

# Generate manifest. WEB DIR = www, dist, etc.
appflow live-update generate-manifest --dir=[WEB DIR]`

# 위의 명령어를 반드시 두개의 명령어 사이에 호출해야, 의도한대로 동작한다.
npm run build # 웹 Build
appflow live-update generate-manifest # live-update.manifest.json 생성
npx cap sync # Capacitor 동기화

 

 

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기