12. Build variants in Flutter
https://docs.flutter.dev/deployment/flavors
● 하나의 프로젝트 환경에서 빌드 결과물을 물리적으로 분리
● 개발용, QA용, 배포용 앱파일 분리
● 프리미엄 기능을 제공하는 유료, 무료버전 앱을 만들 수 있음.
● 코드는 같지만 리소스만 다른 앱을 만들 수 있음.
17. Create Build variants - Android
● Gradle 스크립트에 선언한 “appName” 매개변수를 manifest에 적용
● android / app / src / main / AndroidManifest.xml
https://developer.android.com/studio/build/manifest-build-variables?hl=ko
<application
android:label="${appName}"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
>
18. Create Build variants - iOS
https://docs.flutter.dev/deployment/flavors
● .xcconfig 파일 생성 후 scheme 을 설정함.
● iOS의 scheme 설정은 안드로이드의productFlavors 와 동일한 역할
● .xcconfig 파일은 productFlavors 에 정의된 빌드 구성정보와 동일.
24. ● Flutter의 빌드모드는 세가지
● Debug : 앱 개발 전용
● Release : 출시 전용
● Profile : 디버깅 전용
Create Build variants - iOS
https://docs.flutter.dev/testing/build-modes
37. What is Github Actions?
https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions
● 빌드, 테스트, 배포를 자동화할 수 있는 CI/CD 플랫폼.
● Github repo에 대한 push, pull request, tag 등 트리거로 만들 수 있음.
● 트리거가 동작하면YAML 기반 스크립트를 실행.
● fastlane과 마찬가지로 높은 수준으로 추상화된 액션을 제공함
● Docker build, cloud deploy, app build 등 다양한 작업 가능
42. What is self-hosted runners?
● 작업을 실행하는 서버인 러너를 자체 호스팅으로 사용 가능.
● 특정 운영체제가 필요하거나 특별화된 하드웨어 구성이 필요한 경우 추천
● 단일 Repo 구성 가능
● 조직(organization) 단위로 구성하여 여러 Repo에서 구성 가능
● 엔터프라이즈계정의 경우 여러 조직 단위 구성 가능
● Linux, Windows, macOS 지원
● x64, ARM64, ARM32 지원
43. What is self-hosted runners?
● Github Pro 기준 한달에 3,000분을 무료
제공
● 빌드할 때 마다 환경설정 + 빌드 + 업로드
● 기본 작업시간 6분 * 10 = 60분 소모 시
한달에 무료 빌드 50번
● 30일 기준 하루에 6분 작업을 5번 사용 시
$72 ≈ 96500원
https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners
45. What is fastlane?
https://docs.fastlane.tools/getting-started/ios/setup/
lane :beta do
increment_build_number
build_app
upload_to_testflight
end
lane :release do
capture_screenshots
build_app
upload_to_app_store # Upload the screenshots and the binary to iTunes
slack # Let your team-mates know the new version is live
end
$ fastlane release
48. Create Automation using fastlane
desc "Increase version number"
lane :increase_version_code do
version_code = number_of_commits(all: true)
yaml_file_path = "../../pubspec.yaml"
data = YAML.load_file(yaml_file_path)
version = data["version"]
version_name = data["version"].split("+")[0]
new_version_code = version_code + 1
new_version = "#{version_name}+#{new_build_number}"
data["version"] = new_version
File.open(yaml_file_path, 'w') { |f| YAML.dump(data, f) }
end
ios/fastlane/Fastfile && android/fastlane/Fastfile
49. fastlane actions : number_of_commits
https://docs.fastlane.tools/actions/number_of_commits/#number_of_commits
increment_build_number(build_number: number_of_commits)
build_number = number_of_commits(all: true)
increment_build_number(build_number: build_number)
● 현재 git 브랜치의 커밋 수를 반환.
● all 파라미터를 사용하여 현재 분기 대신 모든 커밋의 총 수를 반환.
50. Create Automation using fastlane
desc "Increase version number"
lane :increase_version_code do
version_code = number_of_commits(all: true)
yaml_file_path = "../../pubspec.yaml"
data = YAML.load_file(yaml_file_path)
version = data["version"]
version_name = data["version"].split("+")[0]
new_version_code = version_code + 1
new_version = "#{version_name}+#{new_build_number}"
data["version"] = new_version
File.open(yaml_file_path, 'w') { |f| YAML.dump(data, f) }
end
ios/fastlane/Fastfile && android/fastlane/Fastfile
52. Create Automation using fastlane
desc "build develop"
lane :build_dev do |options|
## build APP
sh('flutter build apk -t lib/main_dev.dart --flavor develop')
end
android/fastlane/Fastfile
53. Create Automation using fastlane
desc "build develop"
lane :build_dev do |options|
## pods Repo Update
sh('flutter pub get')
cocoapods(
repo_update: true,
)
## build APP
build_app(
scheme: "develop",
clean: true,
workspace: "Runner.xcworkspace",
)
end
ios/fastlane/Fastfile
54. fastlane actions : cocoapods
https://docs.fastlane.tools/actions/cocoapods/#cocoapods
cocoapods(
clean_install: true,
podfile: "./CustomPodfile"
)
● pod install명령어를 실행
● 매개변수에 따라 캐시를 지우고 설치하거나 podfile 경로를 바꿀 수 있음.
55. Create Automation using fastlane
desc "build develop"
lane :build_dev do |options|
## pods Repo Update
sh('flutter pub get')
cocoapods(
repo_update: true,
use_bundle_exec: false,
)
## build APP
build_app(
scheme: "develop",
clean: true,
workspace: "Runner.xcworkspace",
)
end
ios/fastlane/Fastfile
56. fastlane actions : build_app
https://docs.fastlane.tools/actions/build_app/#build_app
build_app(
workspace: "MyApp.xcworkspace",
configuration: "Debug",
scheme: "MyApp",
silent: true,
clean: true,
output_directory: "path/to/dir", # Destination directory. Defaults to current directory.
output_name: "my-app.ipa", # specify the name of the .ipa file to generate (including file extension)
sdk: "iOS 11.1" # use SDK as the name or path of the base SDK when building the project.
)
● iOS 앱을 빌드하여 패키지를 만듦.
● 매개변수에 따라 다양한 빌드 옵션을 적용할 수 있음.
61. fastlane actions : app_store_connect_api_key
desc "Do Signing for Deploy iOS App"
lane :do_signing do |options|
api_key = app_store_connect_api_key(
key_id: options[:key_id],
issuer_id: options[:issuer_id],
key_content: options[:key_content],
is_key_content_base64: true
)
match(
type: 'appstore',
app_identifier: options[:app_identifier],
api_key: api_key,
readonly: true
)
end
ios/fastlane/Fastfile
62. Create Automation using fastlane
desc "Do Signing for Deploy iOS App"
lane :do_signing do |options|
api_key = app_store_connect_api_key(
key_id: options[:key_id],
issuer_id: options[:issuer_id],
key_content: options[:key_content],
is_key_content_base64: true
)
match(
type: 'appstore',
app_identifier: options[:app_identifier],
api_key: api_key,
readonly: true
)
end
ios/fastlane/Fastfile
63. fastlane actions : match
https://docs.fastlane.tools/actions/match
match(type: "appstore")
match(type: "development")
● git, google cloud, aws s3에 인증 관련 파일을 업로드
● 업로드 된 인증 관련 파일은 암호화되어 저장됨
● 각 lane에서 빌드하기 전 인증서를 대조하여 개발 환경에 상관없이 개발 및
배포 가능
64. fastlane actions : match
$ fastlane match init
[✔] 🚀
[12:21:30]: fastlane match supports multiple storage modes, please select the one you want to use:
1. git
2. google_cloud
3. s3
65. fastlane actions : match
[12:21:31]: Please create a new, private git repository to store the certificates and profiles there
[12:21:31]: URL of the Git Repo: [깃허브 repo 입력]
[12:21:34]: Successfully created './Matchfile'. You can open the file using a code editor.
[12:21:34]: You can now run `fastlane match development`, `fastlane match adhoc`, `fastlane match
enterprise` and `fastlane match appstore`
[12:21:34]: On the first run for each environment it will create the provisioning profiles and
[12:21:34]: certificates for you. From then on, it will automatically import the existing profiles.
[12:21:34]: For more information visit https://docs.fastlane.tools/actions/match/
66. fastlane actions : match
git_url("[깃허브 repo]")
storage_mode("git")
type("appstore") # The default type, can be: appstore, adhoc, enterprise or development
app_identifier(["[앱 아이디 입력]", "[앱 아이디 입력]"])
# username("user@fastlane.tools") # Your Apple Developer Portal username
# For all available options run `fastlane match --help`
# Remove the # in the beginning of the line to enable the other options
# The docs are available on https://docs.fastlane.tools/actions/match
67. fastlane actions : match
fastlane match nuke development
fastlane match nuke distribution
68. fastlane actions : match
fastlane match appstore
[✔] 🚀
[12:26:45]: Get started using a Gemfile for fastlane
https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
+--------------+----------------------------------------------+
| Detected Values from './Matchfile' |
+--------------+----------------------------------------------+
| git_url | [깃허브 Repo] |
| storage_mode | git |
| type | appstore |
+--------------+----------------------------------------------+
...
74. fastlane actions : firebase_app_distribution
https://firebase.google.com/docs/app-distribution/ios/distribute-fastlane
firebase_app_distribution(
app: "1:123456789:ios:abcd1234",
testers: "tester1@company.com, tester2@company.com",
release_notes: "Lots of amazing new features to test out!"
)
● 신뢰할 수 있는 테스터에게 빠르게 배포
● 테스터 초대 및 관리 가능
76. fastlane actions : upload_to_testflight
https://docs.fastlane.tools/actions/upload_to_testflight
● 테스트 전용 앱인 testflight에 업로드
● 보통 testflight 업로드 이후 테스트 통과한 빌드파일을 appstore 출시에 올림
upload_to_testflight(skip_submission: true) # to only upload the build
upload_to_testflight(
beta_app_feedback_email: "email@email.com",
beta_app_description: "This is a description of my app",
demo_account_required: true,
notify_external_testers: false,
changelog: "This is my changelog of things that have changed in a log"
)
78. fastlane actions : upload_to_playstore
https://docs.fastlane.tools/actions/upload_to_play_store
● 스토어의 출시 단계를 나타내는 track
● flavor를 설정한 경우 app bundle 파일을 못찾아서 수동으로 잡아줘야함.
upload_to_playstore(
track: "internal",
abb: "../build/app/outputs/bundle/productRelease/app-product-release.aab",
skip_upload_metadata: true,
)
79. default_platform(:ios)
platform :ios do
lane :increase_version_code do
...
end
lane :do_signing do |options|
...
end
...
...
desc "Deploy develop ipa version to Firebase Distribution"
lane :build_deploy_dev do |options|
## signing
do_signing(
app_identifier: options[:app_identifier],
key_id: options[:key_id],
issuer_id: options[:issuer_id],
key_content: options[:key_content]
)
## pods Repo Update
sh('flutter pub get')
cocoapods(
repo_update: true,
use_bundle_exec: false,
)
## build APP
build_app(
scheme: "develop",
clean: true,
workspace: "Runner.xcworkspace",
)
## deploy APP
firebase_app_distribution(
app: "[firebase app id]",
firebase_cli_token: options[:firebase_token]
)
end
ios/fastlane/Fastfile
80. default_platform(:ios)
platform :ios do
lane :increase_version_code do
...
end
lane :do_signing do |options|
...
end
...
...
desc "Deploy a Product version to Apple App Store"
lane :build_deploy_prod do |options|
## signing
do_signing(
app_identifier: options[:app_identifier],
key_id: options[:key_id],
issuer_id: options[:issuer_id],
key_content: options[:key_content]
)
## pods Repo Update
sh('flutter pub get')
cocoapods(
repo_update: true,
use_bundle_exec: false,
)
## build APP
build_app(
scheme: "product",
clean: true,
workspace: "Runner.xcworkspace"
)
## deploy APP
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
ios/fastlane/Fastfile
81. default_platform(:android)
platform :android do
lane :increase_version_code do
...
end
...
...
desc "Deploy develop version apk to Firebase Distribution"
lane :build_deploy_dev do |options|
## build APP
sh('flutter build apk -t lib/src/config/env/env_develop.dart
--flavor develop')
## deploy APP
firebase_app_distribution(
app: "[firebase app id]",
apk_path:
"../build/app/outputs/flutter-apk/app-develop-release.apk",
firebase_cli_token: options[:firebase_token]
)
end
android/fastlane/Fastfile
82. default_platform(:android)
platform :android do
lane :increase_version_code do
...
end
...
...
desc "Deploy a Product version to Google Play Store"
lane :build_deploy_prod do
## build APP
sh("flutter build appbundle --release -t
lib/src/config/env/env_product.dart --flavor product")
## deploy APP
upload_to_play_store(
aab:
"../build/app/outputs/bundle/productRelease/app-product-release.
aab",
track: 'internal',
skip_upload_metadata: true,
)
end
android/fastlane/Fastfile