1
1

More than 1 year has passed since last update.

Jenkins Pipeline iOSプロジェクトの自動配信化をする

Last updated at Posted at 2022-12-13

この記事の内容

jenkinsのpipelineで

  • 開始と終了のSlackの通知
  • Gitでのソースの取得
  • CocoaPodsの更新
  • ipaの作成
  • ipaの成果物の保存
  • AppleStore(TestFlight) or FireBaseDistributionでの配信

を自動化してやってしまおうという内容です。

前提条件

  • Xcodeコマンドラインツールをインストール済み
  • WORKSPACE直下にXcodeProjectファイルがある状態
  • XcodeBuildでipa書き出し用にExportOptions.plistが必要
    • 他の方の記事になりますが、こちらを参考にして作成するとわかりやすいです。
    • Organizerから一度DistributionAppをすればExportOptions.plistがExportされるのでそれを使うのも可
  • 使用するXcodeでAppleDeveloperアカウントのログイン済み
  • AppleDeveloperアカウントにてAppPWを発行しておく※「AppleStore」に送信する場合のみ
  • FireBaseCLIを導入し、配信を行うのID,PWにてログイン済み※「Firebase Distribution」をする場合のみ

PipeLine

各変数を修正すれば環境を整えれるようにしております。
まずはPipeLineの文をすべて載せ、下記にて一つづつ解説を載せていきます。

node("NodeName") {
    // Slack Settings
    def strSlackChannel = "#sample_channel"
    def strSlackMessageJob = "Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
    def strSlackCredentialId = "" 

    // Git Settings
    def strGitRepo = "https://hoge.com/git/fugo.git"
    def strBranch = "*/branch"
    def strCredentialsId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  
    // Xcode Settings
    def strXcodeVersion = "13.4.1"
    def strXcodePath = "/Applications/xcode/Xcode_${xcodeVersion}.app/Contents/Developer"

    // Project Settings
    def strConfiguration = "Release"
    def strScheme = "Scheme"
    def strWorkSpacePath = "${WORKSPACE}/WorkSpace.xcworkspace"
    def strExportPath = "${WORKSPACE}/build"
    def strArchivePath = "${WORKSPACE}/build/${strScheme}.xcarchive"
    def strIpaPath = "${strExportPath}/${strScheme}.ipa"
    def strExportOptionsPath = "${WORKSPACE}/build_plist/ExportOptions.plist"

    // TestFlight Settings
    def strAppleID = "sample@sample.co.jp"
    def strAppleAppPW = "XXXX-XXXX-XXXX-XXXX"

    // Firebase Settings
    def strFirebaseAppID = "1:1234567890:ios:1234567890"
    def strFirebaseDistributionGroup = "GroupName"
            
    try {
        // Slackへの開始通知
        slackSend channel: "${strSlackChannel}", color: 'FFFF00', message: "START JOB : ${strSlackMessageJob}", tokenCredentialId: "${strSlackCredentialId}"
        
        stage ("Checkout") {
            def scm = checkout(
                [$class: 'GitSCM', branches: [[name: strBranch]],
                  doGenerateSubmoduleConfigurations: false, 
                  extensions: [[$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: false, timeout: 60]],
                  submoduleCfg: [],
                  userRemoteConfigs: [[credentialsId: strCredentialsId, url: strGitRepo]]])
        }
        
        stage("Pod Install"){
            sh "cd ${WORKSPACE} &&" +
            "LANG=en_US.UTF-8 pod install"
        }


        stage ("Build iOS") {
            sh "export DEVELOPER_DIR=${strXcodePath} &&" +
            "cd ${WORKSPACE} &&" +
            "agvtool new-version -all ${env.BUILD_NUMBER} &&" +
            "xcodebuild -sdk iphoneos -workspace ${strWorkSpacePath} -scheme ${strScheme} -configuration ${strConfiguration} -archivePath ${strArchivePath} clean archive &&"+
            "xcodebuild -exportArchive -archivePath ${strArchivePath} -exportPath ${strExportPath} -exportOptionsPlist ${strExportOptionsPath}"
        }
        
        stage ("Archive Artifacts") {
            archiveArtifacts allowEmptyArchive: true, artifacts: '**/*.ipa'
        }
        
        stage ("Upload Apple Store") {
            sh "xcrun altool --upload-app -f ${strIpaPath} -t ios -u ${strAppleID} -p ${strAppleAppPW}"
        }
    
        stage ("Firebase Distribution") {
            sh "firebase appdistribution:distribute ${strIpaPath} --app ${strFirebaseAppID} --groups ${strFirebaseDistributionGroup} --debug"
        }
        
        // Slackへの成功通知など
        slackSend channel: "${strSlackChannel}", color: '0000FF', message: "SUCCESS JOB : ${strSlackMessageJob}", tokenCredentialId: "${strSlackCredentialId}"

    }catch (e) {
        // Slackへの失敗通知など
        slackSend channel: "${strSlackChannel}", color: 'FF0000', message: "FAILED JOB : ${strSlackMessageJob}", tokenCredentialId: "${strSlackCredentialId}"
        throw e
    }
}

各種解説

Node

コマンドを実行するNode名を設定する

node("NodeName")

定数の解説

Slack Settings

Slack通知を行う場合のみ、不要なら消してください。
またjenkinsにSlack通知用のプラグイン(Slack Notification)を追加する必要があります。

    // Slack Settings
    def strSlackChannel = "#sample_channel"
    def strSlackMessageJob = "Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})"
    def strSlackCredentialId = "" 
  • strSlackChannel : 通知を行うチャンネル
  • strSlackMessageJob : Slackに送るJobについての情報メッセージ
  • strSlackCredentialId : Jenkinsの設定画面より登録をしたJenkinsのSlackの送信用ID

Git Settings

Gitの設定
strCredentialsIdのみJenkinsにて事前に登録をしておく必要あり

   // Git Settings
    def strGitRepo = "https://hoge.com/git/fugo.git"
    def strBranch = "*/branch"
    def strCredentialsId = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  • strGitRepo : GitのURL
  • strBranch : ビルドを行うGitのBranch名
  • strCredentialsId : Jenkinsの設定画面より登録をしたJenkinsのGitの接続用ID

Xcode Settings

Xcodeの設定
Xcodeバージョンを指定する場合のみ必要
下記のPathをそのまま使う場合は「/Applications/xcode」のフォルダ内にXcode14.1の場合は「Xcode_14.1.app」に名前を変更してインストールする必要あり

    // Xcode Settings
    def strXcodeVersion = "13.4.1"
    def strXcodePath = "/Applications/xcode/Xcode_${strXcodeVersion}.app/Contents/Developer"
  • strXcodeVersion : 指定のXcodeのバージョン
  • strXcodePath : 使用する「Xcode.app」の「/Contents/Developer」を設定する

Project Settings

XcodeProjectの設定
今回はWorkSpaceでの設定で説明をしていく。
必用があれば「.xcodeproj」に書き換え、「xcodebuild -workspace」の部分を書き換えると良い 

    // Project Settings
    def strConfiguration = "Release"
    def strScheme = "Scheme"
    def strWorkSpacePath = "${WORKSPACE}/WorkSpace.xcworkspace"
    def strExportPath = "${WORKSPACE}/build"
    def strArchivePath = "${WORKSPACE}/build/${strScheme}.xcarchive"
    def strIpaPath = "${strExportPath}/${strScheme}.ipa"
    def strExportOptionsPath = "${WORKSPACE}/build_plist/ExportOptions.plist"
  • strConfiguration : XcodeProjectのConfiguration、初期であれば Debug or Release
  • strScheme : ManageSchemesにて指定のtargetに指定したScheme名。Show+Shardをしておく必要あり
  • strWorkSpacePath : XcodeProjectのxcworkspaceのパスを設定する。
  • strExportPath : ipaファイルがExportされる用のフォルダパスを設定する。
  • strArchivePath : xcarchiveファイルがExportされるパスを設定する。
  • strIpaPath : ipaファイルのExportされた先のパスを設定する。
  • strExportOptionsPath : 「xcodebuild -exportArchive」用に設定するPlistファイル

配信関連の設定

TestFlightの設定とFirebaseDistributionの設定
必要があればお使いください。

    // TestFlight Settings
    def strAppleID = "sample@sample.co.jp"
    def strAppleAppPW = "XXXX-XXXX-XXXX-XXXX"

    // Firebase Settings
    def strFirebaseAppID = "1:1234567890:ios:1234567890"
    def strFirebaseDistributionGroup = "GroupName"
  • strAppleID : 配信を行うAppleアカウントのIDを設定する。

  • strAppleAppPW : 配信を行うAppleアカウントのAppパスワードを設定する。 ※通常ログインで使用するPWではない

    • こちらを参考に「App用パスワード」を作成する。
  • strFirebaseAppID : FirebaseプロジェクトのAppIDを設定する。

  • strFirebaseDistributionGroup : Firebaseプロジェクト内に作成をした配信グループIDを設定する。

各ステージの解説

Slack関連

SCMをポーリングなど、ビルドトリガを設定している場合に
jenkinsが走っているのかの確認が取りづらいためSlackで通知をするようにしている。
開始時は黄色、成功時は緑、失敗時は赤と見た目でもわかりやすいようにしている。
slackSendの設定で指定のメッセージにスタンプを付けるような動作もできるため、開始のメッセージに成功か失敗かでスタンプを付けるような仕様にするのも良いとは思います。

slackSend channel: "${strSlackChannel}", color: 'FFFF00', message: "START JOB : ${strSlackMessageJob}", tokenCredentialId: "${strSlackCredentialId}"

slackSend channel: "${strSlackChannel}", color: '0000FF', message: "SUCCESS JOB : ${strSlackMessageJob}", tokenCredentialId: "${strSlackCredentialId}"

slackSend channel: "${strSlackChannel}", color: 'FF0000', message: "FAILED JOB : ${strSlackMessageJob}", tokenCredentialId: "${strSlackCredentialId}"

Checkout

GitのCheckoutを行う
「SCMをポーリング」などを使うことが出来るのでこちらの方法でGitのCheckOutをすると、Gitのコミットをキャッチしてビルドをするなどが楽に実行できます。

    stage ("Checkout") {
        def scm = checkout(
            [$class: 'GitSCM', branches: [[name: strBranch]],
              doGenerateSubmoduleConfigurations: false, 
              extensions: [[$class: 'CloneOption', depth: 0, noTags: false, reference: '', shallow: false, timeout: 60]],
              submoduleCfg: [],
              userRemoteConfigs: [[credentialsId: strCredentialsId, url: strGitRepo]]])
    }

Pipeline Syntaxのcheckoutで設定できる項目を一部変数化してカスタムしたもの

Pod Install

cocoaPodsプロジェクトのためpod installを使っていますが、carthageやxcodeproj単体の場合は基本不要

    stage("Pod Install"){
        sh "cd ${WORKSPACE} &&" +
        "LANG=en_US.UTF-8 pod install"
    }

Build iOS

    stage ("Build iOS") {
        sh "export DEVELOPER_DIR=${strXcodePath} &&" +
        "cd ${WORKSPACE} &&" +
        "agvtool new-version -all ${env.BUILD_NUMBER} &&" +
        "xcodebuild -sdk iphoneos -workspace ${strWorkSpacePath} -scheme ${strScheme} -configuration ${strConfiguration} -archivePath ${strArchivePath} clean archive &&"+
        "xcodebuild -exportArchive -archivePath ${strArchivePath} -exportPath ${strExportPath} -exportOptionsPlist ${strExportOptionsPath}"
    }
  • 「export DEVELOPER_DIR=${strXcodePath}」 : ビルドを実行をするXcodeの指定
    • xcode-select --switchでも可能だが、一時の使用のためexportを使用している。
    • Xcodeのバージョンの指定をする必要がない場合には省略可
  • agvtool new-version -all ${env.BUILD_NUMBER} : XcodeのBuildNumberをjenkinsで使用しているBuildNumberに設定する。
  • xcodebuild -sdk iphoneos -workspace ${strWorkSpacePath} -scheme ${strScheme} -configuration ${strConfiguration} -archivePath ${strArchivePath} clean archive: xcarchiveを作成する。
  • xcodebuild -exportArchive -archivePath ${strArchivePath} -exportPath ${strExportPath} -exportOptionsPlist ${strExportOptionsPath} : xcarchiveからipaを作成する。Distortion Appの設定などはExportOptions.plistに記載をする必要が有る。

Archive Artifacts

成果物の保存用
主にipaファイルを保存しておく用として使用している。

    stage ("Archive Artifacts") {
        archiveArtifacts allowEmptyArchive: true, artifacts: '**/*.ipa'
    }

Apple Store

作成をしたipaファイルをAppStoreにuploadをする。

    stage ("Upload Apple Store") {
        sh "xcrun altool --upload-app -f ${strIpaPath} -t ios -u ${strAppleID} -p ${strAppleAppPW}"
    }

FireBase

FireBaseのdistributionにuploadをする。

    stage ("Firebase Distribution") {
        sh "firebase appdistribution:distribute ${strIpaPath} --app ${strFirebaseAppID} --groups ${strFirebaseDistributionGroup} --debug"
    }

FirebaseCLIの導入についてはこちらを参考に導入をしてください。

参考URL

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1