24/7 twenty-four seven

iOS/OS X application programing topics.

Travis CIでipaを作るときのCode Signが失敗するのを修正したメモ

一週間ほど前から(おそらくTravis CIの環境がXcode 5.1に変わってから)Travis CI上でipaファイルの作成に失敗するようになってしまって、TestFlightにベータ版を自動的にアップロードすることができなくなっていたのを昨日ようやく直したのでメモ。


↓ということで以前に書いた記事はちょっと古くなってしまいました。
本文はそのままですが、参照先のgistの内容はアップデートしてあります。
ユビレジのiPadアプリのCI環境をJenkinsからTravis CIに移行したときのまとめ - 24/7 twenty-four seven


失敗している箇所のエラーメッセージは下記の通り。ipaを作る前の、プロジェクトのビルドでコード署名をするところで失敗しているけど、これだけだと原因がよくわからないのでまず手元で同様のメッセージが出る状況を再現することを実行しました。

⌦ Code Sign error: No matching codesigning identity found: No codesigning identities (i.e. certificate and private key pairs) matching “iPhone Distribution: Ubiregi Inc. (Y7522692LT)” were found.
⌦ CodeSign error: code signing is required for product type 'Application' in SDK 'iOS 7.1'

** BUILD FAILED **
The following build commands failed:
Check dependencies
(1 failure)
rake aborted!

Command failed with status (65): [xcodebuild -sdk "iphoneos" -workspace "/Us...]


で、手元で新しくプロジェクトを作って状況を変えながら(Provisioning Profileを無くしてみる、秘密鍵をキーチェーンから消してみる、など)コマンドラインでビルドするのを何回かして、キーチェーンに秘密鍵が存在しないときに同様のエラーになることがわかりました。


↓そうすると、下記のキーチェーンに秘密鍵をインポートしてる部分がちゃんとできていないのだろうというところまではすぐにわかったのですが、直すのはよくわからなくて、けっこう時間がかかってしまいました。
というのも手元だと成功してしまうので、ちょっと修正してPushして結果を見て、というのを繰り返す必要がありました。

def add_certificates
  sh "security create-keychain -p travis #{KEYCHAIN_NAME}"
  sh "security import ./certificates/apple.cer -k ~/Library/Keychains/#{KEYCHAIN_NAME} -T /usr/bin/codesign"
  sh "security import ./certificates/dist.cer -k ~/Library/Keychains/#{KEYCHAIN_NAME} -T /usr/bin/codesign"
  sh "security import ./certificates/dist.p12 -k ~/Library/Keychains/#{KEYCHAIN_NAME} -P #{KEY_PASSWORD} -T /usr/bin/codesign"
  sh "mkdir -p \"#{PROFILE_DIR}\""
  sh "cp \"./profiles/#{PROFILE_NAME}.mobileprovision\" \"#{PROFILE_DIR}\""
end


↓結局、下記のように`security list-keychains -s #{KEYCHAIN_NAME}`の1行を追加すると成功するようになりました。

def add_certificates
  sh "security create-keychain -p travis #{KEYCHAIN_NAME}"
  sh "security import ./certificates/apple.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
  sh "security import ./certificates/dist.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
  sh "security import ./certificates/dist.p12 -k #{KEYCHAIN_NAME} -P #{KEY_PASSWORD} -T /usr/bin/codesign"
  sh "security list-keychains -s #{KEYCHAIN_NAME}"
end


`list-keychains`はキーチェーンのサーチリストを表示するコマンドですが、`-s`オプションでサーチリストに指定のキーチェーンを追加することができるので、それが有効なのかなと思いました。
これでしばらく運用していましたが、前の記事のコメントid:gin0606さんに以下の情報を教えていただきました。


XCode code signing issue with OS X Mavericks images


↑ のあさりさんの情報によると次の2行を追加して、作成したキーチェーンをデフォルトに指定することと、アンロックすれば直るとのことでした。

security default-keychain -s ios-build.keychain
security unlock-keychain -p travis ios-build.keychain 


アンロックは試してたのですが、デフォルトにするのは試してなかったのでやってみました。
結果は、デフォルトにするのは効果があり、アンロックは特に必要ありませんでした(あってもなくてもよい)。


どちらでも良さそうですが、デフォルトに指定するほうがなんとなく気に入ったので、それを採用しました。
↓ ということで、今は下のようなコードで正常に動いています。

def add_certificates
  sh "security create-keychain -p travis #{KEYCHAIN_NAME}"
  sh "security import ./certificates/apple.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
  sh "security import ./certificates/dist.cer -k #{KEYCHAIN_NAME} -T /usr/bin/codesign"
  sh "security import ./certificates/dist.p12 -k #{KEYCHAIN_NAME} -P #{KEY_PASSWORD} -T /usr/bin/codesign"
  sh "security default-keychain -s #{KEYCHAIN_NAME}"
end


↓ これらの変更を加えたRakefileの全体はこちら
Rakefile for testing, building and uploading to Testflight/Crittercism


↓ .travis.ymlの全体はこちら
.travis.yml for Ubiregi iPad App

Travis CIでiOSアプリのテスト&ベータ版の配信に使っているRakefileを改善したメモ

↓ コード署名に失敗する問題を直すついでに、今まで運用していく中でいくつか改善したい点があったので少し手を加えました。
Travis CIでipaを作るときのCode Signが失敗するのを修正したメモ - 24/7 twenty-four seven

Provisioning Profileのダウンロードにnomad/cupertinoを使う

これまではapple-devというRubyのスクリプトを使用していたのですが、それをやめて、cupertinoというGemを使うようにしました。


もともとcupertinoの存在は知っていたのですが、READMEを見て対話的な使い方しかできないものだと思ってしまっていたので、CIでは使えないと勘違いしていました。


実はコードを読んでみると、次のように`-u`と`-p`オプションでユーザ名とパスワードを渡すことがどのコマンドについてもサポートされているようだったので試してみるとあっさり成功したのでこれを使うように置き換えました。

global_option('-u', '--username USER', 'Username') { |arg| agent.username = arg unless arg.nil? }
global_option('-p', '--password PASSWORD', 'Password') { |arg| agent.password = arg unless arg.nil? }
global_option('--team TEAM', 'Team') { |arg| agent.team = arg if arg }


apple-devはBundlerでインストールできるようになっていなかったので、リポジトリにスクリプトを含めていましたが、それが不要になったので少しリポジトリがスッキリしました。

Pull Requestに対するビルドについてもTestFlightでベータ版を配信する

これまではmasterブランチにマージしたときだけTestFlightでベータ版を配信していたのですが、Pull Requestを簡単に動かして確認したいという声があったので、試しにPull RequestについてもTestFlightにアップロードするようにしてみました。


↓ この対応についてはTravis CIの実行時に設定される環境変数を見て処理を判断していたところを消しただけです。

task :testflight => ["version:set_build_version", IPA_FILE, :crittercism] do |t|
  iff ENV['TRAVIS_PULL_REQUEST'] != "false"
    puts "This is a pull request. No deployment will be done."
    next
  end
  if ENV['TRAVIS_BRANCH'] != "master"
    puts "Testing on a branch other than master. No deployment will be done."
    next
  end


また、Travis CIにはPull Requestの場合`TRAVIS_PULL_REQUEST`という環境変数にPull Requestの番号を入れてくれてるということなので、ビルド番号にPull Requestの番号を加えて配信することにしました。

task :set_build_version do
  rev = `git rev-parse --short HEAD`.strip

  pr_number = ENV["TRAVIS_PULL_REQUEST"];
  rev << " ##{pr_number}" if pr_number != "false"

  puts "Setting build version to: #{rev}"

  InfoPlist.build_version = rev
end

↑ これで、Pull Requestから作られたビルドについては、"Ubiregi2 2.67 (5bf4bc9 #590)"のような形でPull Requestの番号が表示されます。

Travis CI Pro(有料版の環境)のRubyが2.0.0でもCocoaPodsの実行に失敗しなくなった

今まではTravis CI Proの環境だとRuby 2.0.0を使うと`pod install`に失敗していたので、わざわざRuby 1.9.3の環境を指定していたのですが、それが直ったのでRuby 2.0.0を使うことができるようになりました。

↓ それで何が良くなったかというと、Rakefileでキーワード引数が使えるようになったので少しシンプルに書けるようになりました。

def join_option(options: {}, prefix: "", seperator: "")
  _options = options.map { |k, v| %(#{prefix}#{k}#{seperator}"#{v}") }
  _options = _options.join(" ")
end


↓ これらの変更を加えたRakefileの全体はこちら
Rakefile for testing, building and uploading to Testflight/Crittercism