16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

BitriseでAppStoreConnectからdSYMを安定してダウンロードする

Last updated at Posted at 2020-12-16

Bitriseワークフローの中で
AppStoreConnectからdSYMをダウンロードするには
いくつかの課題があります。

この記事では、それら課題に対しての私なりのアプローチを書きます。
前提として、fastlaneを主に利用します。

fastlaneを利用したdSYMのダウンロード

このActionでdSYMのダウンロードが可能です。
download_dsyms

2ファクタ認証を解決する

Bitriseで2ファクタ認証を解決する方法が2つあります。

  • FASTLANE_SESSIONを利用するセッションベース
  • API Keyを利用したAppStoreConnect API

AppStoreConnect APIはdSYMダウンロードの機能を提供していません。
よって、fastlaneの download_dsyms を利用する際はセッションベースの方法で2ファクタ認証を解決するしかありません。

これら2つの方法の詳細はこちらの記事にまとめてあります。

bitcode再コンパイルを待たなければならない

ipaのアップロードと同時にアプリ審査をする場合

fastlaneのAction deliver を利用し、パラメータ submit_for_review をtrueにします。
こうすることで deliver Actionが bitcodeの再コンパイルを待機し、完了後にアプリ審査へサブミットされます。
deliver の直後にdownload_dsymsを呼び出せばdSYMをダウンロードすることが可能です。

ipaのアップロードと同時にアプリ審査をしない場合

このケースが最も事態が複雑です。

パラメータwait_for_dsym_processingは絶対ではない

download_dsyms Actionにも再コンパイルを待機する機能があります。
パラメータ wait_for_dsym_processing がそれにあたります。
下の画像のリストにアップロードしたバージョンが表示されると、このwait_for_dsym_processingは有効に作用します。
2020-12-16 20.59のイメージ.jpg

しかし、ipaをアップロードしてからこのリストに表示されるまで若干のラグがあるため
アップロード直後にdownload_dsyms Actionを実行しても、再コンパイルを待機してくれない場合があります。
しかも、この場合はfastlaneは正常終了と判断します。
(bitcodeなしビルドのケースを考慮してのこと。とfastlaneのコードにコメントが書かれています)

そのため、dSYMダウンロードの成否は dSYMファイル (zipファイル)の有無で判定する のが確実です。
この時、download_dsymsのパラメータ build_number version は必ず指定する必要があります。
download_dsymsは、build_numberversionを指定しなければ、すべてのバージョンのdSYMをダウンロードしてしまうからです。
また、事前にclean_build_artifactsを利用し、Bitriseでビルドした際に出力されるdSYMファイルを削除しておく必要もあるので注意が必要です。

再コンパイル待ちワークフローが長時間bitriseを占有してしまう。

再コンパイル完了まで、数十分かかることもあります。

  • Bitriseの契約プランのビルド時間の上限を迎える
  • 他のワークフローをブロックしてしまう

可能性があります。

そこで、dSYMファイルのダウンロードに失敗したら (ファイルがなかったら) Bitriseのワークフローを一旦終了し、新たにBitriseにビルドを要求させます。

download_dsyms
wait_timeout というパラメータがあります。デフォルトは5分です。
5分経過後、dSYMがダウンロードできなくともfastlaneは正常終了します。
終了後、dSYMファイル(zipファイル)の有無を判定し、ファイルがなければbitriseのRestful APIを利用して、再びdSYMをダウンロードするビルドを要求します。

こうすることで、長時間bitriseを占有する問題を回避できます。

この時、build_numberにBitriseの Set Xcode Project Build Number を利用していると注意が必要です。
アプリをビルドした時のbuild_numberと、dSYMダウンロード時のbuild_numberが異なってしまうからです。
これは、BitriseAPIをリクエストする際にbuild_numberをパラメータにすることで解決できます。

サンプル

    lane :deploy_store do
        match(type: "appstore", readonly: true)
        gym()
        deliver()
        clean_build_artifacts() # ⚠️これを入れないとCIビルド時のdSYMをアップロードしてしまう⚠️
        upload_dsym()
    end

    lane :upload_dsym do
        version = get_version_number(
            xcodeproj: "DeploySample.xcodeproj",
            target: "DeploySample"
        )
        # `Set Xcode Project Build Number`を使わない場合
        # build_number = get_build_number(
        #     xcodeproj: "DeploySample.xcodeproj"
        # )
        build_number = ENV["DSYM_BUILD_NUMBER"] || ENV["XCODE_BUNDLE_VERSION"]
        puts "build_number = #{build_number}"
        download_dsyms(
            app_identifier: "アプリのBundleID",
            wait_for_dsym_processing: true,
            wait_timeout: 180, # 再コンパイルを3分待つ
            version: version,
            build_number: build_number
        )

        # dSYMファイルの有無を判定
        if Dir.glob("#{ENV['PWD']}/*.dSYM.zip").empty?
            puts "No dsym files"
            trigger_upload_dsym_workflow()
            next
        end

        upload_symbols_to_crashlytics(
            gsp_path: "./DeploySample/GoogleService-Info.plist",
            binary_path: "./Pods/FirebaseCrashlytics/upload-symbols",
        )
    end

    lane :trigger_upload_dsym_workflow do
        uri = URI.parse("https://api.bitrise.io/v0.1/apps/#{ENV["BITRISE_APP_SLUG"]}/builds")
        params = { 
            build_params: {
                branch: ENV["BITRISE_GIT_BRANCH"],
                commit_hash: ENV["BITRISE_GIT_COMMIT"],
                workflow_id: "upload_dsym", # `fastlane upload_dsym` を呼ぶだけのworkflowを事前に用意する。このパラメータはそのworkflowの名前。
                environments: [
                    {
                      # `build_number`を環境変数に渡す
                      is_expand: true,
                      mapped_to: "DSYM_BUILD_NUMBER",
                      value: ENV["DSYM_BUILD_NUMBER"] || ENV["XCODE_BUNDLE_VERSION"]
                    }
                ],    
            },
            hook_info: {
                type: "bitrise"
            }
        }
        headers = { 
            "Content-Type" => "application/json",
            "Authorization" => ENV["BITRISE_API_ACCESS_TOKEN"]
        }
        uri.query = URI.encode_www_form(params)
    
        http = Net::HTTP.new(uri.host, uri.port)
        http.use_ssl = true
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
        
        request = Net::HTTP::Post.new(uri.request_uri)
        request["Content-Type"] = "application/json"
        request["Authorization"] = ENV["BITRISE_API_ACCESS_TOKEN"]
        request.body = params.to_json

        response = http.request(request)
        response.value
    end
16
8
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
16
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?