본문 바로가기
CI/CD

GitLab을 활용한 자동 Capacitor Android 빌드

fastlane과 GitLab으로 Android Ionic 앱의 CI/CD 파이프라인을 5분 만에 설정하는 방법

GitLab Capgo 기반 Capacitor Android 자동 빌드 블로그 일러스트

GitLab CI를 활용한 자동 Android Build

Capacitor 앱의 CI/CD 설정은 복잡하고 시간이 많이 걸릴 수 있습니다. 다음 내용을 확인해 보세요:

사전 요구사항

시작하기 전에 다음을 설정해야 합니다:

  • 관리자 권한이 있는 GitLab 계정
  • 올바른 서명으로 Google Play Store에 이미 출시된 앱
  • Android 서명 키 및 keystore 파일
  • Play Store API가 활성화된 Google Cloud Console 프로젝트
  • 적절한 권한을 가진 서비스 계정
  • GitLab CI/CD 워크플로우에 대한 이해
  • Fastlane 설정에 대한 지식
  • 파이프라인 유지 관리 및 디버깅 시간

Capgo이 제공하는 CI/CD용 Capgo Build

Fastlane, Gradle runner, keystore, upload-script 유지 관리를 건너뛰세요. Capgo 빌드 기존 CI/CD 파이프라인에서 서명된 네이티브 Android 빌드를 실행합니다:

  • 기존 파이프라인과 호환: 웹 빌드 후 GitLab CI, GitHub Actions, Jenkins 또는 로컬 스크립트에서 Capgo 빌드를 트리거합니다 npx cap sync.
  • CI 시크릿 기반 서명: Android 키스토어, 키 별칭, 비밀번호 및 Play Console 서비스 계정 JSON을 자체 CI 시크릿에 안전하게 보관합니다.
  • 네이티브 러너 관리 불필요: Capgo 빌드는 유지보수된 Android 빌드 환경을 제공하므로, SDK 이미지, Gradle 캐시 문제 또는 Fastlane 레인을 직접 관리할 필요가 없습니다.
  • 아티팩트 및 제출: QA를 위해 서명된 아티팩트를 다운로드하거나 Capgo CLI을 통해 릴리스 빌드를 제출합니다.

요금제

  • Capgo 플랜은 월 $12부터 시작합니다
  • OTA 업데이트 및 월 약 15회 네이티브 빌드 포함
  • 추가 빌드 분은 크레딧으로 분당 과금됩니다

CI/CD에서 Capgo 빌드 설정하기

수동 설정 가이드

다음과 같이 진행하세요:

포스트에서 따를 단계

  1. Fastlane 파일 복사
  2. GitLab 암호화 시크릿에 시크릿 저장
  3. Google Play 서비스 계정 키 생성 및 저장
  4. Android 서명 키 저장
  5. GitLab 워크플로 .yml 파일 설정

1. Fastlane 파일 복사

Fastlane은 일반적인 모바일 개발 작업을 자동화하기 위해 만들어진 Ruby 라이브러리입니다. Fastlane을 사용하면 보통 Android Studio에서 수행하던 작업을 실행하는 일련의 “actions”를 묶은 커스텀 “lanes”를 구성할 수 있습니다. Fastlane으로 많은 것을 할 수 있지만, 이 튜토리얼에서는 몇 가지 핵심 action만 사용하겠습니다.

프로젝트 루트에 Fastlane 폴더를 만들고 다음 파일들을 복사하세요: Fastlane

default_platform(:android)

KEYSTORE_KEY_ALIAS = ENV["KEYSTORE_KEY_ALIAS"]
KEYSTORE_KEY_PASSWORD = ENV["KEYSTORE_KEY_PASSWORD"]
KEYSTORE_STORE_PASSWORD = ENV["KEYSTORE_STORE_PASSWORD"]

platform :android do
    desc "Deploy a beta version to the Google Play"
    private_lane :verify_changelog_exists do |version_code: |
      changelog_path = "android/metadata/en-US/changelogs/#{version_code}.txt"
      UI.user_error!("Missing changelog file at #{changelog_path}") unless File.exist?(changelog_path)
      UI.message("Changelog exists for version code #{version_code}")
    end

    private_lane :verify_upload_to_staging do |version_name: |
      UI.message "Skipping staging verification step"
    end
    lane :beta do
				keystore_path = "#{Dir.tmpdir}/build_keystore.keystore"
				File.write(keystore_path, Base64.decode64(ENV['ANDROID_KEYSTORE_FILE']))
				json_key_data = Base64.decode64(ENV['PLAY_CONFIG_JSON'])
				previous_build_number = google_play_track_version_codes(
					package_name: ENV['DEVELOPER_PACKAGE_NAME'],
					track: "internal",
					json_key_data: json_key_data,
				)[0]

				current_build_number = previous_build_number + 1
				sh("export NEW_BUILD_NUMBER=#{current_build_number}")
        gradle(
          task: "clean bundleRelease",
          project_dir: 'android/',
          print_command: false,
          properties: {
            "android.injected.signing.store.file" => "#{keystore_path}",
            "android.injected.signing.store.password" => "#{KEYSTORE_STORE_PASSWORD}",
            "android.injected.signing.key.alias" => "#{KEYSTORE_KEY_ALIAS}",
            "android.injected.signing.key.password" => "#{KEYSTORE_KEY_PASSWORD}",
						'versionCode' => current_build_number
          })
        upload_to_play_store(
					package_name: ENV['DEVELOPER_PACKAGE_NAME'],
					json_key_data: json_key_data,
          track: 'internal',
          release_status: 'completed',
          skip_upload_metadata: true,
          skip_upload_changelogs: true,
          skip_upload_images: true,
          skip_upload_screenshots: true,
        )
    end
    lane :build do
      gradle(
        task: "clean bundleRelease",
        project_dir: 'android/',
        print_command: false,
        properties: {
          "android.injected.signing.store.file" => "#{keystore_path}",
          "android.injected.signing.store.password" => "#{KEYSTORE_STORE_PASSWORD}",
          "android.injected.signing.key.alias" => "#{KEYSTORE_KEY_ALIAS}",
          "android.injected.signing.key.password" => "#{KEYSTORE_KEY_PASSWORD}",
        })
    end
    lane :prod_release do
      build_gradle = File.read("../android/app/build.gradle")

      verify_changelog_exists(version_code: build_gradle.match(/versionCode (\d+)/)[1])
      verify_upload_to_staging(version_name: build_gradle.match(/versionName '([\d\.]+)'/)[1])

      supply(
        track_promote_to: 'beta',
        skip_upload_apk: true,
        skip_upload_aab: true,
        skip_upload_metadata: false,
        skip_upload_changelogs: false,
        skip_upload_images: false,
        skip_upload_screenshots: false
      )
    end
end

GitLab CI/CD 변수에 Secret 저장하기

GitLab은 GitHub의 리포지토리 시크릿과 유사하게 암호화된 CI/CD 변수를 저장할 수 있는 방법을 제공합니다. 민감한 정보를 안전하게 저장하세요.

  1. GitLab 프로젝트의 설정으로 이동하세요.
  2. CI/CD > Variables로 이동하세요
  3. 다음 변수를 추가하세요:
  • ANDROID_KEYSTORE_FILE: base64로 인코딩된 .jks 또는 .keystore Android 빌드를 서명하는 데 사용되는 파일입니다. Play App Signing을 사용하는 경우 업로드 키와 연결된 keystore 파일이거나, 앱 서명 키일 수 있습니다.
  • KEYSTORE_KEY_PASSWORD: keystore 파일과 연결된 비밀번호
  • KEYSTORE_KEY_ALIAS: 키 스토어 별칭
  • KEYSTORE_STORE_PASSWORD: 개인 키 비밀번호
  • DEVELOPER_PACKAGE_NAME: com.example.app과 같은 Android 앱 ID
  • PLAY_CONFIG_JSON: base64로 인코딩된 서비스 계정 키 JSON입니다.

Google Play 서비스 계정 키 생성하기

secret을 생성하려면 PLAY_CONFIG_JSON 다음 단계를 따르세요:

  1. 다음으로 이동하세요: Google Cloud Console
  2. 새 프로젝트를 생성하거나 기존 프로젝트를 선택하세요
  3. Google Play Android Developer API를 활성화하세요
  4. 서비스 계정을 생성하세요:
    • “IAM & Admin” > “Service Accounts”로 이동하세요
    • “Create Service Account”를 클릭하세요
    • 이름과 설명을 입력하세요
    • “Create and Continue” 클릭
    • 역할 할당을 건너뛰고 “Done” 클릭
  5. JSON 키 생성:
    • 목록에서 서비스 계정을 찾으세요
    • 점 3개 메뉴 > “Manage keys” 클릭
    • “Add Key” > “Create new key” 클릭
    • JSON 형식 선택
    • “Create” 클릭
  6. Play Console에서 서비스 계정에 앱 접근 권한을 부여하세요:
    • 다음으로 이동: Play Console
    • “사용자 및 권한”으로 이동
    • “Invite new users” 클릭
    • 서비스 계정 이메일 입력 (@*.iam.gserviceaccount.com으로 끝남)
    • “Release to production” 권한 부여
    • “Invite user” 클릭
  7. JSON 키를 base64로 변환:
    base64 -i path/to/your/service-account-key.json | pbcopy
  8. base64로 인코딩된 문자열을 PLAY_CONFIG_JSON GitLab 변수로 추가

GitLab CI/CD 파이프라인 설정하기

CI/CD 파이프라인 정의를 위해 프로젝트 루트에 .gitlab-ci.yml 파일을 생성합니다. 아래는 파이프라인 구성 예시입니다:


image: mingc/android-build-box:latest

stages:
  - build
  - upload_to_capgo
  - build_and_upload_android

build:
  stage: build
  tags:
    - saas-linux-xlarge-amd64
  cache:
    - key:
        files:
          - bun.lockb
      paths:
        - .node_modules/
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - node_modules/
      - dist/
  only:
    - master

upload_to_capgo:
  stage: upload_to_capgo
  tags:
    - saas-linux-xlarge-amd64
  script:
    - npx @capgo/cli@latest bundle upload -a $CAPGO_TOKEN -c dev
  dependencies:
    - build
  when: manual
  only:
    - master

build_and_upload_android:
  tags:
    - saas-linux-xlarge-amd64
  stage:    build_and_upload_android
  cache:
    - key:
        files:
          - android/gradle/wrapper/gradle-wrapper.properties
      paths:
        - ~/.gradle/caches/
  script:
    - npx cap sync android
    - npx cap copy android
    - bundle exec fastlane android beta # We do create a tag for the build to trigger XCode cloud builds
  dependencies:
    - build
  when: manual
  only:
    - master

파이프라인 트리거

GitLab 저장소에 새 태그를 push하면, GitLab CI/CD가 정의된 파이프라인을 자동으로 트리거하여 Fastlane을 통해 Android 앱을 빌드하고 배포합니다.

프로젝트 구조와 요구 사항에 맞춰 경로와 의존성을 조정하세요. 이 설정을 통해 GitLab CI/CD에서 Android 앱 배포를 자동화할 수 있습니다.

마치며

mingc/android-build-box Docker 이미지를 사용해 GitLab CI/CD를 구성하면 Android 앱 빌드 프로세스를 자동화해 개발 워크플로를 더 효율적이고 안정적으로 만들 수 있습니다. 이 자동화로 시간을 확보해 앱 개발의 핵심에 집중할 수 있고, 결국 고품질 Android 앱을 더 효율적으로 제공하는 데 도움이 됩니다.

GitLab을 활용한 자동 Capacitor Android 빌드 이어서 진행하기

사용 중이라면 GitLab을 활용한 자동 Capacitor Android 빌드 CI/CD 자동화를 계획하려면, 다음을 연결하세요 Capgo CI/CD 설정하기 Capgo CI/CD의 제품 워크플로우용, Capgo Native Build Capgo Native Builds의 제품 워크플로우용, Capgo 연동 서비스 Capgo Integrations의 제품 워크플로우용, CI/CD 통합 CI/CD Integration의 구현 세부 사항은, 그리고 GitHub Actions 연동 GitHub Actions Integration의 구현 세부 사항을 참고하세요.

Capacitor 앱용 Live updates

웹 레이어 버그가 라이브 상태라면, 앱 스토어 승인을 며칠씩 기다리지 말고 Capgo를 통해 수정 사항을 배포하세요. 네이티브 변경 사항은 정상 리뷰 절차를 그대로 따르는 반면, 사용자는 백그라운드에서 업데이트를 받습니다.

블로그 최신 글

Capgo는 정말 프로페셔널한 모바일 앱을 만드는 데 필요한 최고의 인사이트를 제공합니다.