読者です 読者をやめる 読者になる 読者になる

酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

JenkinsでCocoaPodsを含んだiOSアプリプロジェクトのビルドで署名に失敗してしまう

iPhone Jenkins

(開発的な意味で)チームで働くことはほぼなくて1人でiOSアプリを開発していると、1件1件最新ビルドが欲しいという要望に応えるのが難しかったです。……というか、僕は限界だったのでJenkinsを導入してJenkinsおじさんを酷使していました。

それ以降、Xcodeプラグインを使ったり使わなかったりと試行錯誤の末、コマンドライン直叩きスタイルで落ち着きました。僕が使っているコマンドラインの一覧は一通り「Xcodeでのビルドを自動化するxcodebuildコマンドとIPAファイルを作成してiTunes Connect(Testflight)に投げる方法 - 酢ろぐ!」で書きました。

先日から着手した新しい案件で初めてCocoaPodsを使ってみました。CocoaPodsはVisual StudioでいうところのNuGetのようなものです。

今更かもしれませんが昔からのコードをメンテばかりしてきたので、CocoaPodsを導入できずにいたんですよね。導入してみると、これがかなり便利でPodfileに使いたいライブラリをペペーンって書くとインストールしてくれているという優れもので、 なんで今まで使ってなかったんだろうと思うレベルです。

CocoaPodsを使ったプロジェクトは、iPhoneシミュレータ上で実行している時には特に問題なく動いていました。Jenkinsでもアスタリスク(*)なAd-Hocプロビジョニングプロファイルでビルドしている時にもすんなりとビルドできていたため、今回の問題に気付きませんでした。

今日、In-houseなプロビジョニングプロファイルに差し替えたところJenkinsおじさんがアラートを吐き出すという現象が発生してしまいました。証明書のインストールでミスってるのかな?Build Settingsで諸々の設定を間違っているのか?と色々疑って無駄に時間を消耗してしまいました。

どんなエラーがでていたのか?

下記のようなエラーが発生していました。

CocoaPodsが生成したPod側のプロジェクトのBundle IDが'org.cocoapods.*'になっていたためにプロビジョニングプロファイルが持っているプリフィックスと相違しておりビルドに失敗しています。

=== BUILD TARGET Pods-Realm OF 
PROJECT Pods WITH CONFIGURATION Release ===

Check dependencies
Code Sign error: Provisioning profile does not 
match bundle identifier: The provisioning profile 
specified in your build settings 
(“XXXXXXX In-house Distribution”) 
has an AppID of “jp.ch3cooh.*” which does not match 
your bundle identifier “org.cocoapods.Realm”.
CodeSign error: code signing is required 
for product type 'Framework' in SDK 'iOS 8.3'

pod installを実行すると元々のプロジェクト(ここではhoge.xcodeprojとする)とライブラリ群を抱えたPodsプロジェクトを含むxcworkspaceが生成されます。

━hoge.xcworkspace
 ┃
 ┣━hoge.xcodeproj (アプリが入ってる側)
 ┗━Pods.xcodeproj (ライブラリが入ってる側)

Jenkinsのログに残っていたのは下記のようなエラーでした。アプリのBundle Identifierはjp.ch3cooh.hogeで、Pods側のBundle Identifierはorg.cocoapods.Realmになっていました。

Xcodeを使っていると自動的に解決してくれるのですが、コマンドラインからビルドした場合は自動では解決してくれないので2時間ほど悩んでしまいました。

どんなコマンドで失敗したのか?

Jenkinsでgit cloneしてpod installしてから以下のコマンドでビルドしています。

pod install

# schemeがないので一旦Xcodeを開いて初期化する
# てかここを自動化できていないの問題なのでは(
pgrep -f "/Applications/Xcode.app" | xargs kill
open hoge.xcworkspace
sleep 10
pgrep -f "/Applications/Xcode.app" | xargs kill

# ビルド開始する
xcodebuild -sdk iphoneos \
  -workspace hoge.xcworkspace -scheme hoge \
  -configuration Release clean build \
  CODE_SIGN_IDENTITY='iPhone Distribution: XXXXXXXXX.' \
  PROVISIONING_PROFILE='XXXX-XXXXX-XXXXX'

解決したけど強引かも……

プロビジョニングプロファイルのIDと相違があることが署名できない原因なので、Podfileでなんらかのパラメータを指定すればインストール時のBundle Identifierを指定できるのではないか?と考えましたが見つからず。

最終的に「A post install script for CocoaPods that changes the bundle identifier of all pods to the one specified. · GitHub」を参考に、pod installの完了後にPod側のプロジェクトのInfo.plistを書き換えるという手段に出ました。

post_install do |installer|
  
  installer.project.targets.each do |target|
    target.build_configurations.each do |config|
      if config.name == 'BREnterprise'
        config.build_settings['CODE_SIGN_IDENTITY[sdk=iphoneos*]'] = 'iPhone Distribution: XXXXXXXXX.'
        config.build_settings['PROVISIONING_PROFILE'] = 'XXXX-XXXXX-XXXXX'
      end
    end
  end
  
  # change bundle id of each pod to 'com.bottlerocketapps.*'
  bundle_id = 'jp.ch3cooh'

  directory = installer.config.project_pods_root + 'Target Support Files/'
  Dir.foreach(directory) do |path|

    full_path = directory + path
    if File.directory?(full_path)

      info_plist_path = full_path + 'Info.plist'
      if File.exist?(info_plist_path)

        text = File.read(info_plist_path)
        new_contents = text.gsub('org.cocoapods', bundle_id)
        File.open(info_plist_path, "w") {|file| file.puts new_contents }
      end
    end
  end
end

もっと良い手段があれば知りたいです……というかCocoaPodsを使っている人はみんなここでつまづくと思うんだけどどうやって解決してるんだろう。良い方法があれば教えて下さい。

(追記2016/6/1)CocoaPods 1.0を導入後、ビルド時の署名に失敗してしまう現象が再発しました

blog.ch3cooh.jp

関連記事

blog.ch3cooh.jp