GitHubActionsでUnityのiOSビルドを走らせてXcodeビルドをしてApp Centerに配信するまで
pushしたら自動でUnityビルドが走る人権環境を手に入れるの続編です。
はじめに
詳細を書くのが面倒なので、GitHub ActionsやFastlaneを分かってる人向け記事です。
ポイント
match不使用
今回はmatchを使用せず、証明書(.p12)とmobileprovisionを手動で生成して使用するフローです。
これは好みが分かれるところだと思いますが、自分の趣味です。
すぐLinuxに切り替える
わざわざubuntuでUnityビルド、macOSでXcodeビルド、またubuntuに戻してAppCenterにアップロードと面倒なことをしています。
理由は簡単で、XcodeビルドにはmacOSを利用する必要がありますが、Linuxに比べて値段が10倍もします。
(GitHub Actionsの支払いについて)
ArtifactのUpload/Downloadは結構早いので、Linuxで出来ることはLinuxでやる方針にしています。
Artifactは忘れず消す
Job間を跨いでファイルを共有するためにArtifactを利用していますが、Artifactも課金対象です。
(自動で課金されることはなく、上限を超えると古いものから消えていきます。)
そのため、job間のファイル共有に使ったArtifactは忘れず消えるようなコードにしましょう。
Jobの途中でエラーになったときも正しく削除されるよう気をつけましょう。
development-build.yml
ここからは直接コードにコメントを入れながら解説していきます。
name: Development build
on:
push:
branches:
- main
jobs:
build_unity:
name: Build ${{ matrix.targetPlatform }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
targetPlatform:
- iOS
steps:
- name: Checkout repository
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: Unity/Library
key: Library-${{ matrix.targetPlatform }}
restore-keys: |
Library-
- name: Build
uses: game-ci/unity-builder@v2
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
projectPath: Unity
targetPlatform: ${{ matrix.targetPlatform }}
versioning: Custom
version: 0.1.${{ github.run_number }} # ここでバージョンを入れておくと出来たROMとGitHubActionsの対応付けが出来て便利
- uses: actions/upload-artifact@v2
with:
name: Build-${{ matrix.targetPlatform }}
path: build/${{ matrix.targetPlatform }}
build_xcode:
name: Build xcode project
runs-on: macos-latest
needs: build_unity
env:
IOS_APP_ID: dev.kyubuns.test
IOS_BUILD_PATH: ${{ format('{0}/build/iOS', github.workspace) }}
CERTIFICATES_PATH: ${{ format('{0}/Certificates.p12', github.workspace) }}
MOBILEPROVISION_PATH: ${{ format('{0}/Target.mobileprovision', github.workspace) }}
IPA_OUTPUT_PATH: ${{ format('{0}/Build.ipa', github.workspace) }}
CODESIGNING_IDENTITY: ${{ secrets.CODESIGNING_IDENTITY }}
CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Download Artifact
uses: actions/download-artifact@v2
with:
name: Build-iOS
path: build/iOS
- name: Fix File Permissions
run: |
find $IOS_BUILD_PATH -type f -name "**.sh" -exec chmod +x {} \;
- uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-${{ hashFiles('**/Gemfile.lock') }}
- name: Write Key Files
env:
CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
MOBILEPROVISION: ${{ secrets.MOBILEPROVISION }}
run: |
echo "$CERTIFICATES_P12" | base64 --decode > $CERTIFICATES_PATH
echo "$MOBILEPROVISION" | base64 --decode > $MOBILEPROVISION_PATH
- name: Build Xcode
uses: maierj/fastlane-action@v2.0.0
with:
lane: 'ios development'
- uses: actions/upload-artifact@v2
with:
name: Build-iOS-ipa
path: ${{ env.IPA_OUTPUT_PATH }}
- name: Cleanup
if: always()
uses: geekyeggo/delete-artifact@v1
with:
name: Build-iOS
# FastlaneでAppCenterにアップロードするところまで行っても良かったものの、macOSの稼働時間を減らすためにlinuxで行っている
upload_appcenter:
name: Upload ipa to AppCenter
runs-on: ubuntu-latest
needs: build_xcode
steps:
- name: Download Artifact
uses: actions/download-artifact@v2
with:
name: Build-iOS-ipa
- name: Upload to App Center
uses: wzieba/AppCenter-Github-Action@v1
with:
appName: kyubuns/Test
token: ${{ secrets.APPCENTER_API_TOKEN }}
file: Build.ipa
group: Internal
- name: Cleanup
if: always()
uses: geekyeggo/delete-artifact@v1
with:
name: Build-iOS-ipafastlane/Fastfile
fastlane init してGemfileとかは作ってください。
keychain_name = "temporary_keychain"
keychain_password = SecureRandom.base64
platform :ios do
lane :development do
certificates
provisining_uuid = sh("grep UUID -A1 -a #{ENV["MOBILEPROVISION_PATH"]} | grep -io \"[-A-Z0-9]\\{36\\}\"").strip
build_options = {}
build_options[:scheme] = "Unity-iPhone"
build_options[:output_name] = File.basename(ENV['IPA_OUTPUT_PATH'])
build_options[:output_directory] = File.dirname(ENV['IPA_OUTPUT_PATH'])
build_options[:configuration] = "Debug"
build_options[:project] = "#{ENV['IOS_BUILD_PATH']}/iOS/Unity-iPhone.xcodeproj"
build_options[:export_method] = "ad-hoc"
build_options[:codesigning_identity] = ENV['CODESIGNING_IDENTITY']
build_options[:export_options] = {
signingStyle: "manual",
compileBitcode: false,
provisioningProfiles: {
"#{ENV["IOS_APP_ID"]}": "#{provisining_uuid}"
},
}
build_options[:skip_profile_detection] = true
update_app_identifier(
xcodeproj: build_options[:project],
plist_path: "Info.plist",
app_identifier: ENV["IOS_APP_ID"],
)
update_project_provisioning(
xcodeproj: build_options[:project],
target_filter: build_options[:scheme],
profile: ENV["MOBILEPROVISION_PATH"],
code_signing_identity: build_options[:codesigning_identity]
)
build_ios_app(build_options)
end
lane :certificates do
cleanup_keychain
create_keychain(
name: keychain_name,
password: keychain_password,
default_keychain: true,
lock_when_sleeps: true,
timeout: 3600,
unlock: true
)
import_certificate(
certificate_path: ENV["CERTIFICATES_PATH"],
certificate_password: ENV["CERTIFICATES_PASSWORD"],
keychain_name: keychain_name,
keychain_password: keychain_password
)
install_provisioning_profile(path: ENV["MOBILEPROVISION_PATH"])
end
lane :cleanup_keychain do
if File.exist?(File.expand_path("~/Library/Keychains/#{keychain_name}-db"))
delete_keychain(name: keychain_name)
end
end
after_all do
if File.exist?(File.expand_path("~/Library/Keychains/#{keychain_name}-db"))
delete_keychain(name: keychain_name)
end
end
end参考
GAME.CI - Deploy to the App Store
https://game.ci/docs/github/deployment/ios