2014年にAppleがTestflightを買収してから数年経ちました。Androidのサポートが打ち切られたりして対応に追われたこともありましたが、数年経ち公式にiTunes Connectのアプリ申請プロセスに組み込まれるようになりました。
iOS 8を公開した時期から1つのバージョンに対してバイナリを複数投げることができるようになりました。
Jenkinsを使ってビルドしたiOSアプリのバイナリを自動でアップロードできるように、xcodebuildと延々戦っていたので、Xcode 6.1で実行した結果をメモしておきたいと思います。僕がJenkinsビルドマンをやっている限りこの記事は随時更新されていきます。
環境について
僕の環境での結果なので、他の環境で適用できなかったらごめんなさい。プロジェクトの構成によっては、xcodebuildがエラーを吐くと思うので適時良い感じに読みかえてください。
下記のメモには「Example.xcodeproj」というプロジェクトファイルの名前が沢山登場します。
プロジェクトが格納されている{Project directory}
には、「Example.xcodeproj」と「Example2.xcodeproj」の2つが格納されており、exampleスキーマにexampleターゲットが存在していることを前提としています。これはうちのアプリのプロジェクトの都合ですので良い感じに読みかえてください。
基本的に、-project
でプロジェクトファイルを指定する必要はありません。xcodebuildは、同一ディレクトリにxcodeprojが2つあるとどちらを使えば良いのかわからなくてエラーを吐くので、下記のメモでは.xcodeprojファイルを明示的に指定しています。
目次
- 環境について
- 目次
- xcodebuildを使ってビルド作業をコマンドラインでおこなう
- 再署名する
- IPAファイルを作成してiTunes Connectに投げる
- App Extension(Widget)を含むiOSアプリをビルドする
- 追記:Xcode 6.3でiTunes Connectにアップロードできなくなってしまった(2015/4/9)
- 追記:Xcode 6.4でビルドしていたプロジェクトをXcode 7.2にするとビルドが通らなくなってしまった(2016/3/11)
- 追記:Xcode 7でビルドしたApp Store向けバイナリを申請に出すとAppleからInvalid Swift Supportメールが送られてくる(2016/4/5)
- 追記:Xcode 8.3でビルドするとPackageApplicationが見つからないとエラーが発生する (2017/4/7)
- 参考
- 関連記事
xcodebuildを使ってビルド作業をコマンドラインでおこなう
ビルドに使うXcodeのバージョンを使い分ける
プロジェクトの関係上、 1台のPCに複数のXcodeがインストールされている場合があります。そういった場合には適切なバージョンのXcodeを使い分ける必要があります。
どのバージョンのxcodebuildが使われているか調べる
$ xcodebuild -version
Xcode 7.0.1
Build version 7A1001
Xcode 6.4のxcodebuildに切り替える
Applicationsに「Xcode」と「Xcode 6.4」があった場合を想定しています。「Xcode 6.4」の方はXcodeを共存させるためにリネームしていますので、自分の環境にあった名前に読み替えてください。
$ export DEVELOPER_DIR=/Applications/Xcode\ 6.4.app $ xcodebuild -version Xcode 6.4 Build version 6E35b
クリーン
ビルドをクリーンします。中間ファイルや出力ファイルが削除されます。中間ファイルを削除してしまうため、次回ビルドした際にはすべてのファイルをコンパイルしなおす必要がありコンパイル時間がかかってしまいます。
しかし、ビルドをクリーンすることで、例えば画像の差し替えなどの変更がビルド結果に反映されないことを防ぐことができます。何故かうちのプロジェクトではこの現象が頻発するのでビルドをクリーンしています。
# 全部のビルドをクリーンする xcodebuild clean -project Example.xcodeproj # exampleスキームのビルドをクリーンする xcodebuild clean -project Example.xcodeproj -scheme example
ビルド
指定されたプロジェクトのターゲットをビルドします。
# シミュレータ向けにビルドする xcodebuild -project Example.xcodeproj -target example \ -sdk iphonesimulator -configuration Debug build # 実機向けにビルドする xcodebuild -project Example.xcodeproj -target example \ -sdk iphoneos -configuration Release build # 実機向けにビルドする(-sdkを指定していないと実機ビルドになる) xcodebuild -project Example.xcodeproj -target example \ -configuration Release build # CocoaPodsを使っていてxcworkspaceを指定してビルドする xcodebuild -workspace Example.xcworkspace \ -scheme example -sdk iphonesimulator
プロジェクトに指定されているものと異なるCode sign(証明書)とプロビジョニングを指定したい場合には以下のように指定することが可能です。
# 実機向けにビルドする(証明書をEnterpriseに変更) xcodebuild -sdk iphoneos \ -project Example.xcodeproj -target example \ -configuration Release build \ CODE_SIGN_IDENTITY='iPhone Distribution: Sakusan CO.,LTD.' \ PROVISIONING_PROFILE='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
スキームを調べる/ターゲットを調べる
ビルドのためには-target
または-scheme
を指定する必要があります。.xcodeprojを使ってビルドするためにはターゲット(-target)を指定する必要があります。.xcworkspaceを使ってビルドするためにはスキーム(-scheme)を指定する必要があります。
それぞれ-target
または-scheme
を取得します。
.xcodeprojからターゲットの一覧を取得する
$ xcodebuild -project Example.xcodeproj -list Information about project "Example": Targets: Example Staging Example Production Build Configurations: Debug Release If no build configuration is specified and -scheme is not passed then "Release" is used. Schemes: Example Production Example Staging
.xcworkspaceからスキームの一覧を取得する
$ xcodebuild -workspace Example.xcworkspace -list Information about workspace "Example": Schemes: Pods-Example Production Pods-Example Staging Example Production Example Staging
テスト
指定されたプロジェクトのターゲットをテストします。
# iPhone 5s シミュレータでテストする xcodebuild -project Example.xcodeproj -scheme example \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 5s' clean test # iOS 8.1のiPhone 6シミュレータでテストする xcodebuild -project Example.xcodeproj -scheme example \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,OS=8.1,name=iPhone 6' clean test
使用しているxcodebuildで利用可能なSDKを調べる
$ xcodebuild -showsdks OS X SDKs: OS X 10.9 -sdk macosx10.9 OS X 10.10 -sdk macosx10.10 iOS SDKs: iOS 8.1 -sdk iphoneos8.1 iOS Simulator SDKs: Simulator - iOS 7.1 -sdk iphonesimulator7.1 Simulator - iOS 8.1 -sdk iphonesimulator8.1
インストールされている証明書を調べる
$ security find-identity -v -p codesigning 1) XXXXXXXXXX "iPhone Distribution: CH3COOH INC." 2) XXXXXXXXXX "iPhone Distribution: Sakusan,INC." 2 valid identities found
再署名する
現在出力しているipaファイルを新しいProvisioning Profileを使って再署名することができます。利用用途としては、新しいIPAファイルは作成したくないがProvisioning Profileが失効してしまったり対応するUDIDが増えた時に、Provisioning Profileのみを入れ替えたいという時によく使います。
詳しい方法については下記の記事にまとめました。
IPAファイルを作成してiTunes Connectに投げる
実機向けにビルドした.appファイルを署名して、.ipaファイルを作成してからiTunes Connectにぶん投げます。
注意しておかないといけないのは、必須項目であるアイコン画像やビルドバージョンの更新*1をしておかないといけないということです。
# 実機ビルド xcodebuild -project Example.xcodeproj -target example \ -configuration Release build
appファイルが、{Project directory}/build/Release-iphoneos/example.app にできていると思います。example.appは既にAppStoreで署名済みとします。
# .appをパッケージして.ipaファイルを作る xcrun -sdk iphoneos PackageApplication \ build/Release-iphoneos/example.app \ -o /Users/ch3cooh/Documents/example.ipa
作成したIPAの検証をおこなう
作成したexample.ipaファイルの検証を行います。-u
で指定しているMAILADDRESSと-pで指定しているPASSWORD
は、それぞれApple IDのものを指します。検証するためには「altool」を利用します。altoolのパスが思った以上に長くて表示されていません……
'/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool' \ --validate-app -f /Users/ch3cooh/Documents/example.ipa \ -u MAILADDRESS -p PASSWORD
以下のようにエラーが出なかったよと教えてくれます(そこそこ時間はかかる模様)。
2015-02-10 22:12:49.661 altool[29899:706733] No errors validating archive at /Users/ch3cooh/Documents/example.ipa
作成したIPAをiTunes Connectへアップロードする
問題がなかったので、iTunes Connectへ--validate-app
を--upload-app
に変えてアップロードします。
'/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool' \ --upload-app -f /Users/ch3cooh/Documents/example.ipa \ -u MAILADDRESS -p PASSWORD
iTunes Connect(Testflight)へのアップロードには検証とは比にならないくらい時間がかかります。辛抱強く待ちましょう。アップロードができました!!
2015-02-10 22:26:18.567 altool[32637:810145] No errors uploading /Users/ch3cooh/Documents/example.ipa
iTunes Connectのプレリリース上でも先ほどアップロードしたバイナリを確認することができます。
繰り返しになりますが、アップロードにはものすごい時間とネットワークリソースを使用しますので、開発マシンではなく専用のビルドマシンでJenkinsなどのCIツールを使う方が良いでしょう*2。
App Extension(Widget)を含むiOSアプリをビルドする
App Extension(Widget)と本体側のiOSアプリはプロビジョニングプロファイルが異なります。コマンドラインから異なるプロビジョニングプロファイルを指定します。
追記:Xcode 6.3でiTunes Connectにアップロードできなくなってしまった(2015/4/9)
altoolの--validate-app
オプションをつけてバイナリの検証をするのは問題がないのですが、Xcode 6.3をインストールした影響か、--upload-app
オプションでiTunes ConnectへのSubmitに失敗するようになってしまいました。
2015-04-09 15:10:27.019 altool[19173:77108] *** Error: Errors uploading '/Users/ch3cooh/Documents/example.ipa': ( "Error Domain=WorkerErrorDomain Code=-10001 \"Transporter not found at path: /usr/local/itms/bin/iTMSTransporter. You should reinstall the application.\" UserInfo=0x7fc522511550 {MZUnderlyingException=Transporter not found at path: /usr/local/itms/bin/iTMSTransporter. You should reinstall the application., NSLocalizedDescription=Transporter not found at path: /usr/local/itms/bin/iTMSTransporter. You should reinstall the application., NSLocalizedFailureReason=Transporter not found at path: /usr/local/itms/bin/iTMSTransporter. You should reinstall the application.}" )
重要な文章は、Transporter not found at path: /usr/local/itms/bin/iTMSTransporter.の部分です。
altoolさん曰く、/usr/local/itms/bin/iTMSTransporter
が見つからないと言っています。確かに「/usr/local」自体が存在していませんでした。
iTMSTransporterが実際に存在するのは以下のフォルダ(?)になります。
- /Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/itms/bin/
/usr/local/itms/bin/iTMSTransporter
を参照してしまうaltoolのためにシンボリックリンクを貼ってパスを通してあげましょう。ひょっとすると /usr/local
は権限の関係で作れないかもしれないので適切な方法に読み替えてください。
mkdir /usr/local ln -s "/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/itms" /usr/local/
今まで通りatoolコマンドでipaファイルをアップロードしてみます。数分後、以下のようなメッセージが表示されました。
2015-04-09 16:04:37.073 altool[19527:89225] No errors uploading '/Users/ch3cooh/Documents/example.ipa'
WatchKitアプリが含まれていないバイナリであれば問題なくTestFlightの配信まで確認できたが、WatchKitアプリが含まれているプロダクトはバイナリが無効と言われてしまった。
追記:Xcode 6.4でビルドしていたプロジェクトをXcode 7.2にするとビルドが通らなくなってしまった(2016/3/11)
Xcode 6.4でビルドしていたプロジェクトをXcode 7.2(Xcode 7.2.1)にした途端ビルドが通らなくなってしまった。ビルドスクリプトは以下の通りです。
xcodebuild -sdk iphoneos \ -workspace ${XCWORKSPACE_NAME} -scheme "${SCHEME_NAME}" \ -configuration Release build \ CODE_SIGN_IDENTITY=${CODE_SIGN_ID} \ PROVISIONING_PROFILE=${PROVISIONING_ID} \ SYMROOT=${BUILD_NUMBER_PATH} xcrun -sdk iphoneos PackageApplication "${SOURCE_PATH}" -o ${APP_PATH} \ --embed ~/Library/MobileDevice/Provisioning\ Profiles/${PROVISIONING_FILENAME}
原因を探ってみるとSYMROOTの位置に中間ファイルや.appファイルが生成されていないのが原因で、後続のアプリパッケージで失敗しているのがわかりました。
xcodebuildのCODE_SIGN_IDENTITYに今までは証明書のハッシュ値を指定していましたが、CODE_SIGN_IDENTITY
を"iPhone Distribution: SAKUSAN,INC. (XXXXXXXXX)"
のような名前で指定することでビルドが通るのを確認しました。
xcodebuild -sdk iphoneos \ -workspace ${XCWORKSPACE_NAME} -scheme "${SCHEME_NAME}" \ -configuration Release build \ SYMROOT=${BUILD_NUMBER_PATH} \ CODE_SIGN_IDENTITY="${CODE_SIGN_NAME}"
追記:Xcode 7でビルドしたApp Store向けバイナリを申請に出すとAppleからInvalid Swift Supportメールが送られてくる(2016/4/5)
Xcode 7でビルドしたApp Store向けバイナリをiTunes Connectにアップロードすると機械的にリジェクトされてしまい、AppleからInvalid Swift Supportと書かれたメールが送られてきます。
追記:Xcode 8.3でビルドするとPackageApplicationが見つからないとエラーが発生する (2017/4/7)
Xcode 8.2.1まではビルドエラーにならなかったのですが、Xcode 8.3にアップグレードすると下記のようにPackageApplicationが見つからないエラーが発生してしまいます。
xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH Build step 'シェルの実行' marked build as failure
解決方法の詳細については以下の記事に書きました。
参考
関連記事
この他にもiOSアプリ開発で見つけたネタや悩んだ内容など紹介しています。Tipsをまとめておりますのでこちらのページをご参照ください。