
【CI/CD】BitriseでDeployGateなiOSをFastlane matchでやってみる
2021.12.20
第2弾~はじめに~

(株)ライトコードの笹川(ささがわ)です!
CIシリーズ第2弾です!
引き続き、Bitriseの使い方を紹介します。
前回の記事の宣言通り、今回は「iOS」です。
iOSは、1ビルドあたり10分以内であれば、無料で利用できるのは魅力的ですね!
前回の記事:【CI/CD】BitriseでDeployGateをAndroidでやってみる
早速設定を始めてみましょう
iOSビルドの環境はこちら
- CLIは、fastlane
- 証明書の設定は、Manual
- ビルド時にfastlane matchを利用
- Configrationは、「Debug」「Stage」「Release」の3種類
- 証明書もそれぞれ「Development」「Adhoc」「Appstore」となります。
- Xcodeは、10.2.1
設定してみる
今回は、Fastlane matchを利用したSigningを利用しますので、公式ドキュメント通りには進めません。
とりあえず、fastlaneをworkflowsに設定し、実行したいlaneを設定します。
お察しの通りエラーが発生いたします…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [14:25:08]: Cloning remote git repo... [14:25:08]: If cloning the repo takes too long, you can use the `clone_branch_directly` option in match. Cloning into '/var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/d20190528-1491-1suoeby'... fatal: could not read Username for 'https://github.com': terminal prompts disabled [14:25:08]: Exit status: 128 [14:25:08]: Error cloning certificates repo, please make sure you have read access to the repository you want to use [14:25:08]: Run the following command manually to make sure you're properly authenticated: [14:25:08]: $ git clone https://github.com/[match用のリポジトリ].git /var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/d20190528-1491-1suoeby +------------------+--------------------+ | Lane Context | +------------------+--------------------+ | DEFAULT_PLATFORM | ios | | PLATFORM_NAME | ios | | LANE_NAME | ios deploy_develop | +------------------+--------------------+ [14:25:08]: Error cloning certificates git repo, please make sure you have access to the repository - see instructions above |
Fastlane match を利用したドキュメントについては、記載が…ない!
公式ドキュメントには下記のように書いてあります。
サードパーティツールをcode signingの管理に利用する場合、そのツールのドキュメントやissueトラッカーを利用してください。
Bitriseでは、こちらで用意したStep(Certificate and profile installer)やtools (codesigndoc)についてのカスタマーサポートは可能ですが、サードパーティツールについてのカスタマーサポートは行なっておりません。
Fastlane matchのエラーを解消する
ここからは、他のCIサービスなども含めて使い方を調査し試行錯誤することにしました。
Fastlane matchを利用する際のパスワードの設定が漏れていました。
こちらは Workflow Editer の Env Vars で MATCH_PASSWORD に対して matchを利用する際のパスワードを設定しておきます。
fastfile や Matchfileなどへの記載は不要です。
設定して、Rebuildします。
match(sync_code_signing)の設定は、これで問題なしです。
gymでのエラーを解消する
matchが成功したあとは、また別のエラーが発生しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | [15:00:36]: $ set -o pipefail && xcodebuild -workspace ./JENA_INTERVIEW.xcworkspace -scheme {ProjectFile} -destination 'generic/platform=iOS' -archivePath /Users/vagrant/Library/Developer/Xcode/Archives/2019-05-28/{ProjectFile}\ 2019-05-28\ 15.00.36.xcarchive archive | tee /var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/fastlane_logs916760609/gym/{ProjectFile}-{ProjectFile}.log | xcpretty [15:00:38]: ▸ --- xcodebuild: WARNING: Using the first of multiple matching destinations: [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } [15:00:42]: ▸ ❌ error: No profile for team '{TeamID}' matching '{Adhoc ProvisioningProfile}' found: Xcode couldn't find any provisioning profiles matching '{TeamID}/{Adhoc ProvisioningProfile}'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor. (in target '{ProjectFile}') [15:00:42]: ▸ ** ARCHIVE FAILED ** --- xcodebuild: WARNING: Using the first of multiple matching destinations: { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device } ❌ error: No profile for team '{TeamID}' matching '{Adhoc ProvisioningProfile}' found: Xcode couldn't find any provisioning profiles matching '{TeamID}/{Adhoc ProvisioningProfile}'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor. (in target '{ProjectFile}') ** ARCHIVE FAILED ** [15:00:42]: Exit status: 65 ~省略~ [15:00:42]: ▸ note: Using new build system [15:00:42]: ▸ note: Planning build [15:00:42]: ▸ note: Constructing build description [15:00:42]: ▸ Build system information [15:00:42]: ▸ error: No profile for team '{TeamID}' matching '{Adhoc ProvisioningProfile}' found: Xcode couldn't find any provisioning profiles matching '{TeamID}/{Adhoc ProvisioningProfile}'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor. (in target '{ProjectFile}') |
こちらのビルドですが、Developmentの証明書を利用したビルドをする予定で Configration も Debug となっております。
エラー文を見るとDevelopmentの証明書じゃなくて、Adhocの証明書を利用してビルドをしようと失敗しているようです。
指定した証明書を利用するようにlaneの内容を書き換えます。
(変数は、適宜置き換えてください。)
laneの内容を書き換え
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | lane :develop_deploy do get_provisioning_profiles(type: "development") settings_to_override = { :BUNDLE_IDENTIFIER => ENV["APP_ID"], :PROVISIONING_PROFILE_SPECIFIER => ENV["PROVISIONING_PROFILE_DEVELOPMENT"], :DEVELOPMENT_TEAM => ENV["FASTLANE_TEAM_ID"] } gym( scheme: "{schema}", configuration: "Debug", export_method: "development", export_options: { provisioningProfiles: { ENV["APP_ID"] => ENV["PROVISIONING_PROFILE_DEVELOPMENT"] }, } ) end |
設定してRebuildします。
これで、gymの設定は問題ないです。
Certificateのエラーを解消する
上記のgymの設定が完了したあとに別のエラーが発生しました。
1 2 3 | [13:57:34]: $ set -o pipefail && xcodebuild -workspace ./{ProjectFile}.xcworkspace -scheme {ProjectFile} -destination 'generic/platform=iOS' -archivePath /Users/vagrant/Library/Developer/Xcode/Archives/2019-06-01/{ProjectFile}\ 2019-06-01\ 13.57.34.xcarchive BUNDLE_IDENTIFIER={Application Id} PROVISIONING_PROFILE_SPECIFIER={Development ProvisioningProfile} DEVELOPMENT_TEAM={Team Id} archive | tee /var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/fastlane_logs410590617/gym/{ProjectFile}-JENA_INTERVIEW.log | xcpretty [13:57:40]: ▸ ❌ error: No signing certificate "iOS Development" found: No "iOS Development" signing certificate matching team ID "{Team id}" with a private key was found. (in target '{ProjectFile}') [13:57:40]: ▸ ** ARCHIVE FAILED ** |
どうやら、Certificateの署名そのものでエラーが発生しているようです。
certificate-and-profile-installer を Workflows に追加します。
「Code Signing タブ」をタップし、「Developer用のCertificate」から「exportしたp12ファイル」をアップロードします。
パスワードは、exportしたときに設定したものを入力してください。
設定してRebuildします。
cocoapodsのエラーを解消する
自動でcocoapodsのバージョンがアップグレードされていました。
そのため、Gemfileでcocoapodsのバージョンを指定するようにしたら、fastlaneでcocoapodsコマンドが失敗するようになってしまいました。
1 2 3 | [16:13:27]: Exit status of command 'bundle exec pod install' was 1 instead of 0. bundler: failed to load command: pod (/Users/vagrant/.rbenv/versions/2.5.3/bin/pod) Bundler::GemNotFound: Could not find gem 'cocoapods (~> 1.7.0)' in any of the gem sources listed in your Gemfile. |
Scriptを追加
こちらに関しては、下記のScriptを追加し対応しました。
1 2 3 4 5 6 7 | - script@1.1.5: title: Do anything with Script step inputs: - content: |- #!/usr/bin/env bash bundle install --path vendor/bundle --jobs=2 |
これで、cocoapodsのバージョン指定をしてもエラーが発生しなくなりました。
DeployGateにアップロードする
これでアプリケーションファイル出力のビルドは、問題なく実行できるようになりました。
次に、出力したappファイルをDeployGateで配信できるようにします。
こちらは、Bitriseのworkflowを利用せずにfastlaneで対応します。
laneでの書き方はこちら
1 2 3 4 5 6 7 8 | desc "Upload to Deploy Gate" lane :upload_deploy_gate do deploygate( api_token: ENV['DEPLOYGATE_API_KEY'], user: ENV['DEPLOYGATE_USER'], message: "{DeploGateの対象ファイルに対するメッセージ}", ) end |
gymコマンドのあとに、こちらを呼び出せばアップロードが行われます。
Deploy to Bitrise.ioで保存されるようにする
DeployGate には、アップロードできるようになりましたが、appファイルとdYSMファイルを別途保管していることが多いのでこちらも設定します。
fastlane で出力先を指定せずにgymを実行すると、プロジェクトルートにファイルが出力されます。
ですから、Artifacts として保存しておきたい場合は、以下のどちらかになります。
- fastlaneで出力したファイルを移動する
- Artifactsとして参照するパスを変更する
Bitriseの仕様としての正解はわかりませんが、Workflow側で細かい設定をすると後に影響しそうでしたので前者で対応することにしました。
Scriptを追加
具体的な方法としては、Workflowのfastlaneの次にScriptを追加します。
1 2 3 4 5 6 | - script@1.1.5: inputs: - content: |- #!/usr/bin/env bash cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa cp $BITRISE_SOURCE_DIR/{App Name}.app.dSYM.zip $BITRISE_DEPLOY_DIR/{App Name}.app.dSYM.zip |
デフォルトのDeployディレクトリに対してcpコマンドでファイルをコピーしています。
これで無事、Aritfactsにもファイルが保存されるようになりました。
さいごに
Androidの設定をした記事でも述べたように、BitriseではGUIでCI設定ができるのは利点の一つです。
今回のようにfastlane matchを利用した場合に、「どんなエラーが出て」「どんな対応をするか」は探しても見つかりませんでした。
iOSの証明書管理によく利用される fastlane match ですが、実際に採用している人も多いのではないでしょうか。
この記事が誰かの役に立ってくれたら幸いです!
オススメ本
こちらの記事もオススメ!
関連記事
最終的に出来上がったymlファイル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | --- format_version: '7' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: ios trigger_map: - push_branch: develop workflow: deploy_develop - push_branch: stage* workflow: deploy_stage - push_branch: release* workflow: deploy_appstore workflows: code_sign: steps: - activate-ssh-key@4.0.3: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone@4.0.14: {} - cache-pull@2.0.1: {} - certificate-and-profile-installer@1.10.1: {} - script@1.1.5: title: Do anything with Script step inputs: - content: |- #!/usr/bin/env bash bundle install --path vendor/bundle --jobs=2 after_run: [] deploy_develop: steps: - fastlane@2.4.0: inputs: - lane: develop_deploy - script@1.1.5: inputs: - content: |- #!/usr/bin/env bash cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa before_run: - code_sign after_run: - deploy_to_bitrise description: 'Upload to Deploygate of Development build ' deploy_appstore: steps: - fastlane@2.4.0: inputs: - lane: appstore_deploy - script@1.1.5: inputs: - content: |- #!/usr/bin/env bash cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa cp $BITRISE_SOURCE_DIR/{App Name}.app.dSYM.zip $BITRISE_DEPLOY_DIR/{App Name}.app.dSYM.zip before_run: - code_sign after_run: - deploy_to_bitrise deploy_stage: steps: - fastlane@2.4.0: inputs: - lane: stage_deploy - script@1.1.5: inputs: - content: |- #!/usr/bin/env bash ls $BITRISE_SOURCE_DIR cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa cp $BITRISE_SOURCE_DIR/{App Name}.app.dSYM.zip $BITRISE_DEPLOY_DIR/{App Name}.app.dSYM.zip before_run: - code_sign after_run: - deploy_to_bitrise deploy_to_bitrise: steps: - deploy-to-bitrise-io@1.4.2: {} - cache-push@2.2.0: {} before_run: [] app: envs: - opts: is_expand: false BITRISE_PROJECT_PATH: {App Name}.xcworkspace - opts: is_expand: false BITRISE_SCHEME: Debug - opts: is_expand: false BITRISE_EXPORT_METHOD: development - opts: is_expand: false MATCH_PASSWORD: "{MATCH_PASSWORD}" |
書いた人はこんな人

- 新潟生まれ新潟育ち本業はモバイルアプリエンジニア。
日々、猫(犬)エンジニアとして活躍中!
IT技術9月 20, 2023開発効率を少しだけ上げるGithubActionsの便利な使い方
IT技術4月 7, 2023【ISUCON部】ライトコードISUCON部 始動!
IT技術4月 18, 2022【Android】Webでよくみる入力Boxを手作り
IT技術1月 19, 2022【Android】SeekbarでスイッチなUIを作る