개요
Flutter로 앱을 개발하였다면, 이렇게 개발한 앱을 사용자가 사용할 수 있게 배포해야 합니다. Flutter의 공식 문서에는 Flutter로 개발한 앱을 배포하는 방법에 대해서 설명하고 있습니다. 이를 참고하면 Flutter로 개발한 앱을 배포할 수 있습니다.
- 안드로이드 배포: https://docs.flutter.dev/deployment/android
- iOS 배포: https://docs.flutter.dev/deployment/ios
Fastlane
은 네이티브로 개발한 앱뿐만아니라 하이브리드 앱(Flutter, React Native 등)도 쉽게 배포할 수 있게 도와주는 툴입니다.
- Fastlane: https://fastlane.tools/
이번 블로그 포스트에서는 Fastlane
을 사용하여 Flutter로 개발한 앱을 배포하는 방법에 대해서 알아보겠습니다.
Fastlane
fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.
Fastlane
은 iOS와 안드로이드의 테스트용 배포 또는 릴리스용 배포를 간단하게 자동화해주는 툴입니다. 배포뿐만 아니라, 스크린샷 생성, 코드 사이닝, 앱 스토어 등록 정보 등을 생성, 관리할 수 있습니다.
이번 블로그 포스트에서는 스크린샷, 앱 스토어 등록 정보 등은 등록이 되어있다고 가정하고, 테스트용/릴리스용 배포를 자동화하는 부분만을 다룰 예정입니다.
스크린샷, 앱 스토어 등록 정보 생성 등, 다른 기능도 사용하고 싶은 분들은 공식 사이트를 참고하시기 바랍니다.
- 공식 사이트: Fastlane
Flutter 공식 홈페이지에서도 CI/CD
를 위해 Fastlane
을 사용하는 방법에 대해서 안내하고 있으므로, 공식 문서도 참고해 보시기 바랍니다.
Fastlane 설치
Fastlane
을 사용하여 Flutter로 개발한 앱을 배포하기 위해서는 Fastlane
을 설치할 필요가 있습니다. 다음 명령어를 사용해서 Fastlane
을 설치합니다.
# Using RubyGems
sudo gem install fastlane -NV
# Alternatively using Homebrew
brew cask install fastlane
공식 사이트에서는 Homebrew
를 사용해서 설치하는 방법과 RubyGems
을 사용해서 설치하는 방법을 안내하고 있습니다.
저는 처음에 Homebrew를 사용해서 설치하고, 테스트해봤지만 제대로 동작하지 않는 부분이 있었습니다. 따라서 RubyGems을 사용해서 설치하는 것을 권장합니다. 혹시 Homebrew로 제대로 동작하지 않는다면 RubyGems으로 다시 설치하신 후 시도해 보시기 바랍니다.
iOS
Flutter로 개발한 iOS 앱을 Fastlane을 사용해서 배포하는 방법에 대해서 알아봅시다.
iOS를 위한 Fastlane 초기화
아래에 명령어를 사용하여 iOS를 위한 Fastlane을 초기화 합니다.
cd ios
fastlane init
위에 명령어를 실행하면 아래와 같은 화면을 확인할 수 있습니다.
이번 블로그 포스트에서는 Testflight용과 앱 스토어에 배포를 위한 설정에 대해서 알아볼 예정입니다. 따라서 2
번이나 3
번을 선택하여 진행하면 됩니다.
2. Automate beta distribution to TestFlight
3. Automate App Store distribution
여기에서는 Testflight용 배포를 위한 설정인 2
번을 선택하여 진행합니다.
2번을 선택하고 진행하면 위와 같이 iOS의 프로젝트를 선택하는 화면을 확인할 수 있습니다. Flutter로 개발한 앱을 배포할 예정이므로 2
번을 선택하여 진행합니다.
2번을 선택하여 진행하였다면, 위와 같이 Apple 로그인을 위한 화면을 확인할 수 있습니다. iOS의 앱 배포를 위해 사용하는 Apple store connect
의 로그인 아이디를 입력합니다.
저는 이미 Fastlane을 사용하여 로그인한 적이 있기 때문에 위와 같은 화면을 확인할 수 있었습니다. 처음 Fastlane을 설정하시는 분들은 이중 인증을 위한 절차를 진행하셔야 됩니다.
위와 같은 화면 이외에도 여러차례 Continue by pressing Enter
를 입력하는 화면이 나옵니다. Enter
키를 눌러 진행하여 설정을 완료합니다.
iOS용 Fastlane 폴더 및 파일
iOS의 설정을 완료하면 Flutter의 ios 폴더 밑에 아래에 폴더 및 파일이 생성되는 것을 확인할 수 있습니다.
|- fastlane
| |- Appfile
| |- Fastfile
|- Gemfile
|- Gemfile.lock
각 폴더 및 파일을 자세히 살펴보도록 하겠습니다.
- fastlane 폴더: Fastlane의 설정 및 실행 파일들이 들어 있는 폴더입니다.
- Gemfile, Gemfile.lock: Fastlane은 Ruby로 개발되었습니다. 이 파일들은 Ruby에서 라이브러리 관리하기 위한 파일들입니다.
Fastlane을 실행하기 위한 설정 내용이 들어 있는 fastlane/Appfile
파일에서 주석을 제거하면 아래와 같습니다.
app_identifier("io.github.dev-yakuza.kumoncho")
apple_id("[email protected]")
itc_team_id("119423059")
team_id("WFDJCJXQZ6")
Appfile
파일은 iOS의 자동 배포를 위한 Fastlane 설정 파일입니다. 간단한 파일이므로 자세한 설명은 생략하도록 하겠습니다.
그 다음은 실제로 앱을 배포하기 위한 실행 파일인 fastlane/Fastfile
파일에서 주석을 제거하면 아래와 같습니다.
default_platform(:ios)
platform :ios do
desc "Push a new beta build to TestFlight"
lane :beta do
increment_build_number(xcodeproj: "kumoncho.xcodeproj")
build_app(workspace: "kumoncho.xcworkspace", scheme: "kumoncho")
upload_to_testflight
end
end
여기에 표시된 Fastlane을 실행하기 위해서는 다음과 같은 명령어를 사용할 수 있습니다.
# cd ios
fastlane beta
이와 같이 Fastlane을 실행하면 iOS의 build number를 올리고(increment_build_number
), 앱을 빌드한 다음(build_app
), Testflight용으로 업로드 합니다.(upload_to_testflight
)
iOS용 실행 파일 수정
기본적으로 제공하는 fastlane 파일로는 완벽하게 배포 자동화를 할 수 없습니다. 따라서 iOS용 배포를 자동화하기 위해 fastlane/Fastfile
파일을 아래와 같이 수정합니다.
# frozen_string_literal: true
default_platform(:ios)
platform :ios do
def updateVersion(options)
if options[:version]
version = options[:version]
else
version = prompt(text: "Enter the version type or specific version\n(major, minor, patch or 1.0.0): ")
end
re = /\d+.\d+.\d+/
versionNum = version[re, 0]
if versionNum
increment_version_number(
version_number: versionNum
)
elsif version == 'major' || version == 'minor' || version == 'patch'
increment_version_number(
bump_type: version
)
else
UI.user_error!('[ERROR] Wrong version!!!!!!')
end
end
def certificate(options)
if options[:type] == 'github'
create_keychain(
name: 'ios_app_keychain',
password: '****************',
timeout: 1800,
default_keychain: true,
unlock: true,
lock_when_sleeps: false
)
import_certificate(
certificate_path: 'distribution.p12',
certificate_password: '****************',
keychain_name: 'ios_app_keychain',
keychain_password: '****************'
)
end
install_provisioning_profile(path: 'distribution.mobileprovision')
update_project_provisioning(
xcodeproj: 'Runner.xcodeproj',
target_filter: 'github',
profile: 'distribution.mobileprovision',
build_configuration: 'Release'
)
api_key = app_store_connect_api_key(
key_id: '**************',
issuer_id: '***********************',
key_filepath: 'distribution.p8'
)
api_key
end
desc 'Update version'
lane :version do |options|
updateVersion(options)
increment_build_number(xcodeproj: 'Runner.xcodeproj')
end
desc 'Submit review only'
lane :submit_review do |_options|
upload_to_app_store(
submit_for_review: true,
automatic_release: true,
force: true,
skip_metadata: true,
skip_screenshots: true,
skip_binary_upload: true
)
end
desc 'Push a new beta build to TestFlight'
lane :beta do |options|
api_key = certificate(options)
build_app(
workspace: 'Runner.xcworkspace',
scheme: 'Runner',
)
upload_to_testflight(api_key: api_key)
end
desc 'Push a new release build to the App Store'
lane :release do |options|
api_key = certificate(options)
build_app(
workspace: 'Runner.xcworkspace',
scheme: 'Runner',
)
upload_to_app_store(
force: true,
reject_if_possible: true,
skip_metadata: false,
skip_screenshots: true,
languages: ['en-US', 'ja','ko'],
release_notes: {
"default" => "bug fixed",
"en-US" => "bug fixed",
"ja" => "バグ修正",
"ko" => "버그 수정"
},
submit_for_review: true,
precheck_include_in_app_purchases: false,
automatic_release: true,
submission_information: {
add_id_info_uses_idfa: false,
export_compliance_encryption_updated: false,
export_compliance_uses_encryption: false
},
api_key: api_key
)
end
end
사용자가 입력한 버전 상황에 맞게, 버전을 수정하도록 하는 함수를 정의하였습니다.
platform :ios do
def updateVersion(options)
...
end
...
desc 'Update version'
lane :version do |options|
updateVersion(options)
increment_build_number(xcodeproj: 'Runner.xcodeproj')
end
...
end
Fastlane 명령어를 사용하여 배포할 앱의 버전을 업데이트할 수 있는 version
이라는 명령어를 만들었습니다. 이 명령어는 다음과 같이 실행하여 앱의 버전을 업데이트 할 수 있습니다.
# fastlane version version:1.0.0
# fastlane version version:major
# fastlane version version:minor
fastlane version version:patch
만약 파라메터를 입력하지 않으면, 사용자 입력을 기다리도록 처리하였습니다.
def updateVersion(options)
if options[:version]
version = options[:version]
else
version = prompt(text: "Enter the version type or specific version\n(major, minor, patch or 1.0.0): ")
end
...
Fastlane을 사용하여 배포하기 위해서는 인증서(Certification)과 프로비저닝 파일(Provisioning) 그리고 앱 스토어 커넥션 API 키(App store connect API key)가 필요합니다.
이 파일들을 준비하였다면 다음과 같이 certificate
함수를 통해 파일들을 등록하고, API
키를 반환하여 필요한 곳에서 사용할 수 있도록 만들었습니다.
# frozen_string_literal: true
default_platform(:ios)
platform :ios do
...
def certificate(options)
if options[:type] == 'github'
create_keychain(
name: 'ios_app_keychain',
password: '****************',
timeout: 1800,
default_keychain: true,
unlock: true,
lock_when_sleeps: false
)
import_certificate(
certificate_path: 'distribution.p12',
certificate_password: '****************',
keychain_name: 'ios_app_keychain',
keychain_password: '****************'
)
end
install_provisioning_profile(path: 'distribution.mobileprovision')
update_project_provisioning(
xcodeproj: 'Runner.xcodeproj',
target_filter: 'github',
profile: 'distribution.mobileprovision',
build_configuration: 'Release'
)
api_key = app_store_connect_api_key(
key_id: '**************',
issuer_id: '***********************',
key_filepath: 'distribution.p8'
)
api_key
end
...
end
이렇게 만든 API
키는 다음과 같이 Testflight나 앱 스토어에 배포할 때 활용됩니다.
# frozen_string_literal: true
default_platform(:ios)
platform :ios do
...
desc 'Push a new beta build to TestFlight'
lane :beta do |options|
api_key = certificate(options)
build_app(
workspace: 'Runner.xcworkspace',
scheme: 'Runner',
)
upload_to_testflight(api_key: api_key)
end
desc 'Push a new release build to the App Store'
lane :release do |options|
api_key = certificate(options)
build_app(
workspace: 'Runner.xcworkspace',
scheme: 'Runner',
)
upload_to_app_store(
force: true,
reject_if_possible: true,
skip_metadata: false,
skip_screenshots: true,
languages: ['en-US', 'ja','ko'],
release_notes: {
"default" => "bug fixed",
"en-US" => "bug fixed",
"ja" => "バグ修正",
"ko" => "버그 수정"
},
submit_for_review: true,
precheck_include_in_app_purchases: false,
automatic_release: true,
submission_information: {
add_id_info_uses_idfa: false,
export_compliance_encryption_updated: false,
export_compliance_uses_encryption: false
},
api_key: api_key
)
end
end
Testflight용으로 배포하는 스크립트를 보면, 인증서를 등록한 후, 앱을 빌드하고, Fastlane가 제공하는 upload_to_testflight
함수를 사용하여 배포하는 것을 확인할 수 있습니다.
...
platform :ios do
...
desc 'Push a new beta build to TestFlight'
lane :beta do |options|
api_key = certificate(options)
build_app(
workspace: 'Runner.xcworkspace',
scheme: 'Runner',
)
upload_to_testflight(api_key: api_key)
end
...
end
앱 스토어 용으로 배포하는 코드도 Testflight용과 동일하게 인증서를 등록한 후, 앱을 빌드합니다. 이후 upload_to_app_store
함수를 사용하여 앱을 배포하게 됩니다.
...
platform :ios do
...
desc 'Push a new release build to the App Store'
lane :release do |options|
api_key = certificate(options)
build_app(
workspace: 'Runner.xcworkspace',
scheme: 'Runner',
)
upload_to_app_store(
force: true,
reject_if_possible: true,
skip_metadata: false,
skip_screenshots: true,
languages: ['en-US', 'ja','ko'],
release_notes: {
"default" => "bug fixed",
"en-US" => "bug fixed",
"ja" => "バグ修正",
"ko" => "버그 수정"
},
submit_for_review: true,
precheck_include_in_app_purchases: false,
automatic_release: true,
submission_information: {
add_id_info_uses_idfa: false,
export_compliance_encryption_updated: false,
export_compliance_uses_encryption: false
},
api_key: api_key
)
end
end
upload_to_app_store
함수에서 사용한 옵션은 다음과 같습니다.
- force: Fastlane가 생성하는 HTML report를 생성하지 않도록 합니다.
- reject_if_possible: 심사 대기중인 버전이 있다면 취소합니다
- skip_metadata: 앱 스토어의 정보를 등록할지 결정합니다. 자동 배포를 할 때, 버전의 수정 내용을 작성해야하므로 이 정보를 등록하도록 설정해야합니다.
- skip_screenshots: 저는 이미 배포한 앱에 대해서 자동 배포를 적용하고 있습니다. 따라서 스크린 샷을 다시 업로드할 필요가 없습니다
- languages: 현재 스토어에 등록된 앱의 지역화를 설정합니다. 사용 가능한 언어는
ar-SA, ca, cs, da, de-DE, el, en-AU, en-CA, en-GB, en-US, es-ES, es-MX, fi, fr-CA, fr-FR, he, hi, hr, hu, id, it, ja, ko, ms, nl-NL, no, pl, pt-BR, pt-PT, ro, ru, sk, sv, th, tr, uk, vi, zh-Hans, zh-Hant
이며 자세한 내용은 공식 홈페이지를 참고하시기 바랍니다(공식 홈페이지) - release_notes: iOS는 앱을 재배포할 때, Release notes를 꼭 작성해야합니다. 제가 사용하는 스크립트는 3개국어를 지원하는 앱이므로 default와 3개국어에 해당하는 Release notes를 작성하였습니다.
- submit_for_review: 앱 심사에 제출하도록 합니다.
- automatic_release: 심사후 앱을 자동으로 배포하도록 설정합니다. 이 값이 설정되지 않으면, 앱 심사를 통과한 후 개발자가 수동으로 배포해야 합니다.
- submission_information: 배포전에 암호화, 광고 포함 여부등을 물어보는 옵션을 설정합니다.
이 밖에도 많은 옵션들이 있습니다. 자세한 내용은 공식 홈페이지를 참고하시기 바랍니다.
iOS용 Fastlane을 실행하여 Testflight에 배포하기
iOS용 Fastlane을 사용하여 자동으로 배포할 준비가 끝났습니다. 이제 Fastlane을 사용하여 앱을 자동 배포해 봅시다.
아래에 명령어를 사용하여 Flutter로 제작한 앱을 Testflight에 배포해 봅니다.
# cd ios
fastlane beta version:patch
배포가 완료될 때까지, 상단한 시간이 걸립니다. 배포가 완료되면 아래와 같은 화면을 확인할 수 있습니다.
물론 App store connect의 Testflight에도 잘 배포된 것을 확인할 수 있습니다.
iOS용 Fastlane을 실행하여 앱 스토어에 배포하기
그럼 이제 아래에 Fastlane 명령어를 실행하여 Flutter로 개발한 앱을 앱 스토어에 배포해 봅시다.
# cd ios
fastlane release version:patch
배포가 완료되면 아래와 같은 화면을 확인할 수 있습니다.
또한 App store connect에도 잘 배포된 것을 확인할 수 있습니다.
안드로이드
이제 Flutter로 개발한 안드로이드 앱을 Fastlane을 사용해서 배포를 자동화 해보도록 하겠습니다.
API access를 위한 Service Account 생성
Fastlane을 통해 안드로이드를 배포할 때, 구글 API를 사용하기 때문에 Google Developer Service Account
를 생성할 필요가 있습니다.
Google Developer Service Account를 생성하기 위해, 아래의 링크를 통해 구글 플레이 콘솔(Google Play Console)로 이동합니다.
- 구글 플레이 콘솔: https://play.google.com/apps/publish/
구글 플레이 콘솔로 이동하면 아래와 같은 화면을 확인할 수 있습니다.
왼쪽 메뉴의 Settings
를 선택합니다. 그리고 Developer account
하위에 있는 API access
메뉴를 선택합니다.
위와 같은 화면이 보인다면, CREATE NEW PROJECT
버튼을 눌러, 새로운 프로젝트를 생성합니다.
새로운 프로젝트가 생성되면, 위와 같은 화면을 볼 수 있습니다. 하단에 있는 CREATE SERVICE ACCOUNT
버튼을 선택하면, 아래와 같은 화면을 확인할 수 있습니다.
위와 같은 화면에서 Google API Console
링크를 선택합니다. 선택하고 나면, 아래와 같은 화면을 볼 수 있습니다.
상단에 있는 CREATE SERVICE ACCOUNT
버튼을 선택합니다. 선택하고 나면 아래와 같이 새로운 Service account를 생성하는 화면을 확인할 수 있습니다.
위와 같은 화면에서, Service account name
에 이름을 입력하고, CREATE
버튼을 눌러 Service account를 생성합니다.(저는 Service account name에 google-play-fastlane-deployment을 입력하였습니다.)
위와 같은 화면이 보이면, Role
을 선택하고 Service Account User
를 검색하여 선택합니다. Role에 Service Account User를 설정하였다면, 하단에 있는 CONTINUE
버튼을 눌러 다음으로 진행합니다.
위와 같은 화면이 보이면, 하단에 있는 CREATE KEY
를 선택하고 JSON
이 선택된 상태에서 CREATE
버튼을 눌러 키를 생성합니다.
CREATE 버튼을 눌러 키를 생성하면 JSON 형식에 파일이 자동으로 다운로드 됩니다. 이 파일을 Flutter 프로젝트의 android
폴더 하위에 복사합니다. 마지막으로 DONE
버튼을 눌러 Service Account를 생성합니다.
그리고 원래 화면으로 돌아와서 오른쪽 하단에 있는 DONE
버튼을 눌러 Service Account 생성을 종료합니다.
그러면 이전과는 다르게 아래와 같은 화면을 확인할 수 있습니다.
이제 권한을 부여하기 위해 오른쪽 하단의 GRANT ACCESS
버튼을 선택합니다.
위와 같은 화면이 나오면 하단으로 스크롤하여 ADD USER
를 선택하여 사용자를 등록합니다.
안드로이드를 위한 Fastlane 초기화
이제 안드로이드용 Fastlane을 생성해 봅시다. 아래에 명령어를 사용하여 안드로이드용 Fastlane을 생성합니다.
cd android
fastlane init
위에 명령어를 실행하면 아래와 같은 화면을 확인할 수 있습니다.
안드로이드 프로젝트의 Package Name
을 입력합니다.(ex> io.github.dev.yakuza.kumoncho) 그러면 다음과 같이 JSON 파일의 경로를 입력하라는 화면을 확인할 수 있습니다.
Service Account를 생성했을 때, 다운로드한 JSON 파일을 android
폴더에 복사하였습니다. 이 파일의 경로를 지정합니다. (ex> app-xxx.json
)
다음으로 안드로이드를 배포할 때, 등록한 스토어 정보(metadata)를 다운로드할 것인지 물어봅니다. 저는 이미 배포한 앱을 자동화하기 때문에 스토어 정보를 갱신할 필요가 없었습니다. 따라서 n
입력을 입력하여 스토어 정보를 다운로드하지 않았습니다.
위와 같은 화면 이외에도 여러차례 Continue by pressing Enter
를 입력하는 화면이 나옵니다. Enter 키를 눌러 진행하여 설정을 완료합니다.
안드로이드용 Fastlane 폴더 및 파일
안드로이드의 설정을 완료하면 Flutter의 android 폴더 밑에 아래에 폴더 및 파일이 생성되는 것을 확인할 수 있습니다.
|- fastlane
| |- Appfile
| |- Fastfile
|- Gemfile
|- Gemfile.lock
각 폴더 및 파일을 자세히 살펴보도록 하겠습니다.
- fastlane 폴더: Fastlane의 설정 및 실행 파일들이 들어 있는 폴더입니다.
- Gemfile, Gemfile.lock: Fastlane은 Ruby로 개발되었습니다. 이 파일들을 Ruby에서 라이브러리 관리하기 위한 파일들입니다.
Fastlane을 실행하기 위한 설정 내용이 들어 있는 fastlane/Appfile
파일에서 주석을 제거하고 확인하면 아래와 같습니다.
json_key_file("api-xxx.json")
package_name("io.github.dev.yakuza.kumoncho")
우리가 설정한 Pacakge Name과 JSON 파일 위치가 설정된 것을 확인할 수 있습니다. 그 다음은 실제로 앱을 배포하기 위한 실행 파일인 fastlane/Fastfile
파일을 주석을 제거하면 아래와 같습니다.
default_platform(:android)
platform :android do
desc "Runs all the tests"
lane :test do
gradle(task: "test")
end
desc "Submit a new Beta"
lane :beta do
gradle(task: "clean assembleRelease")
crashlytics
end
desc "Deploy a new version to the Google Play"
lane :deploy do
gradle(task: "clean assembleRelease")
upload_to_play_store
end
end
iOS와는 다르게 beta
와 deploy
, 두개의 lane이 생성된 것을 확인할 수 있습니다. 위에 Fastlane도 역시 아래와 같은 명령어로 실행할 수 있습니다.
# cd android
fastlane beta
fastlane deploy
하지만 역시 완벽한 자동화를 위해서는 Fastfile을 수정할 필요가 있습니다.
안드로이드용 실행 파일 수정
기본적으로 제공하는 fastlane 파일로는 완벽하게 자동화를 할 수 없습니다. 따라서 안드로이용 배포를 자동화하기 위해 fastlane/Fastfile
파일을 아래와 같이 수정합니다.
# frozen_string_literal: true
default_platform(:android)
platform :android do
def increment_version_code
path = '../app/build.gradle'
re = /versionCode\s+(\d+)/
s = File.read(path)
versionCode = s[re, 1].to_i
s[re, 1] = (versionCode + 1).to_s
f = File.new(path, 'w')
f.write(s)
f.close
end
def increment_version_number(bump_type: nil, version_number: nil)
path = '../app/build.gradle'
re = /versionName\s+("\d+.\d+.\d+")/
s = File.read(path)
versionName = s[re, 1].gsub!('"', '').split('.')
major = versionName[0].to_i
minor = versionName[1].to_i
patch = versionName[2].to_i
if bump_type == 'major'
major += 1
minor = 0
patch = 0
elsif bump_type == 'minor'
minor += 1
patch = 0
elsif bump_type == 'patch'
patch += 1
end
s[re, 1] = if version_number
"\"#{version_number}\""
else
"\"#{major}.#{minor}.#{patch}\""
end
f = File.new(path, 'w')
f.write(s)
f.close
increment_version_code
end
def updateVersion(options)
version = options[:version] || prompt(text: "Enter the version type or specific version\n(major, minor, patch or 1.0.0): ")
re = /\d+.\d+.\d+/
versionNum = version[re, 0]
if versionNum
increment_version_number(
version_number: versionNum
)
elsif %w[major minor patch].include?(version)
increment_version_number(
bump_type: version
)
else
UI.user_error!('[ERROR] Wrong version!!!!!!')
end
end
desc 'Update version'
lane :version do |options|
updateVersion(options)
end
desc 'Submit a new Beta'
lane :beta do |_options|
gradle(task: 'clean bundleRelease')
upload_to_play_store(
skip_upload_metadata: true,
skip_upload_screenshots: true,
skip_upload_images: true,
skip_upload_apk: true,
track: 'internal',
aab: '../build/app/outputs/bundle/release/app-release.aab'
)
end
desc 'Deploy a new version to the Google Play'
lane :release do |_options|
gradle(task: 'clean bundleRelease')
upload_to_play_store(
skip_upload_metadata: true,
skip_upload_screenshots: true,
skip_upload_images: true,
skip_upload_apk: true,
aab: '../build/app/outputs/bundle/release/app-release.aab'
)
end
end
추가한 내용을 자세히 살펴보도록 하겠습니다. 안드로이드는 iOS와 다르게 앱 버전을 업데이트하는 기능을 제공하지 않습니다.(제가 못찾은 걸 수 도 있습니다. 혹시 아시는 분은 피드백 주세요.) 따라서 안드로이드의 versionCode와 versionName을 업데이트하는 기능을 구현하였습니다.
platform :android do
def increment_version_code
...
end
def increment_version_number(bump_type: nil, version_number: nil)
...
end
def updateVersion(options)
...
end
...
end
버전을 업데이트하는 updateVersion
함수는 iOS
에서 설명하였으므로 자세한 설명은 생략하도록 하겠습니다.
안드로이드의 테스트용 Fastlane
테스트용으로 앱을 배포하기 위한 Fastlane을 살펴보도록 하겠습니다.
platform :android do
...
desc 'Submit a new Beta'
lane :beta do |_options|
gradle(task: 'clean bundleRelease')
upload_to_play_store(
skip_upload_metadata: true,
skip_upload_screenshots: true,
skip_upload_images: true,
skip_upload_apk: true,
track: 'internal',
aab: '../build/app/outputs/bundle/release/app-release.aab'
)
end
...
end
안드로이드는 Gradle의 clean
과 bundleRelease
로 앱을 빌드하도록 하였습니다.(assembleRelease
이 아님) 또한, upload_to_play_store
함수의 track: 'internal'
을 사용하여 internal test용으로 배포하도록 하였습니다.
안드로이드는 iOS와 다르게 Release notes(change log)를 작성할 필요가 없기 때문에 스토어와 관련된 모든 기능은 skip 하도록 설정하였습니다.
마지막으로 bundleRelease
를 통해 aab 파일을 생성하고 업로드할 예정이므로 skip_upload_apk
를 true
로 설정하였습니다.
안드로이드의 구글 플레이 스토어용 Fastlane
다음으로 구글 플레이 스토어에 배포하기 위한 Fastlane 코드를 살펴보도록 하겠습니다.
...
platform :android do
...
desc 'Deploy a new version to the Google Play'
lane :release do |_options|
gradle(task: 'clean bundleRelease')
upload_to_play_store(
skip_upload_metadata: true,
skip_upload_screenshots: true,
skip_upload_images: true,
skip_upload_apk: true,
aab: '../build/app/outputs/bundle/release/app-release.aab'
)
end
end
iOS와 동일하게 하기 위해 lane :deploy
를 lane :release
로 이름을 변경하였습니다. upload_to_play_store
함수의 track
파라메터가 없는 것외에는 beta용과 동일하기 때문에 자세한 설명은 생략하도록 하겠습니다.
안드로이드용 Fastlane 실행
이제 Fastlane을 사용하여 안드로이드에서 자동으로 배포할 준비가 끝났습니다. 이제 Fastlane을 사용하여 앱을 자동 배포해 봅시다.
아래에 명령어를 사용하여 Flutter로 제작한 앱을 internal test에 배포해 봅니다.
# cd android
fastlane beta version:patch
배포가 완료될 때까지, 조금 시간이 걸립니다. 배포가 완료되면 아래와 같은 화면을 확인할 수 있습니다.
물론 Play store console에서도 internal test에 잘 배포된 것을 확인할 수 있습니다.
그럼 이제 아래에 명령어를 실행하여 실제로 배포를 진행해 봅니다.
# cd android
fastlane release version:patch
배포가 완료되면 아래와 같은 화면을 확인할 수 있습니다.
또한 Google Play store에도 잘 배포된 것을 확인할 수 있습니다.
gitignore
Fastlane을 통해 배포를 하면, 그에 따른 파일들이 생성됩니다. 이 파일들 중 Git에서 관리할 필요가 없는 파일들을 .gitignore
파일을 열고 다음과 같이 추가합니다.
...
# fastlane
ios/*.mobileprovision
ios/*.cer
ios/*.dSYM.zip
android/fastlane/README.md
ios/fastlane/README.md
완료
이것으로 Fastlane을 사용해서 Flutter로 제작한 앱을 자동으로 배포하는 방법에 대해서 알아보았습니다. 이번 블로그에서 설명한 내용은 물론 Native로 개발된 앱에서도 활용할 수 있으므로 많은 분들께 도움이 되었으면 좋겠습니다.
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku
가 개발한 앱을 한번 사용해보세요.Deku
가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.