スマホアプリのコマンドビルドまとめ（iOS編）


前回、『[XCTestCaseで作ったテストをxcodebuildで実行する方法](https://qiita.com/gremito/items/835f06511b80e4efafff)』についてまとめましたが、引き続きxcodebuildでシミュレータビルドと.ipaファイルのビルドをやったのでその試験のまとめです。


## 概要

目的は以下の２点です。

- iOSシミュレータにアプリを転送して実行させる
- .ipaファイルを作る

## 準備

以下の準備を済ませておくこと。

- 証明書登録諸々
  - [iOS 証明書 & Provisioning Profile & Apple Developer Program の更新をやったメモ（1年ぶりn回目）｜クラスメソッドブログ](https://dev.classmethod.jp/smartphone/iphone/update-ios-certificate-and-provisioning-profile)
- どのシミュレータを扱うか決めておく
    - `$ instruments -s devices`
    - `$ xcrun simctl list`

## シミュレータ

以下の各記事を参考に実機でのビルドよりも先にシミュレータビルドを行う。

- [Xcodeでのビルドを自動化するxcodebuildコマンドとIPAファイルを作成してiTunes Connect(Testflight)に投げる方法](https://blog.ch3cooh.jp/entry/20150210/1423573065)
- [xcodebuild: Deploy iOS app from Command Line](https://link.medium.com/TMZtXFd2W1)
- [simctl: Control iOS Simulators from Command Line](https://link.medium.com/PLhyOVrhW1)
- [Xcodeのカスタムビルドアクションで使える環境変数 - matsukaz's blog](http://matsukaz.hatenablog.com/entry/2015/07/06/090933)
- [xcodebuildでipa作成 -exportOptionsPlist対応版](https://qiita.com/roworks/items/7ef12acabf9679561d84)

`$ xcrun simctl`では、シミュレータの画面が表示されないため状況が分からないことから別の方法で対応することに。
まずは、シミュレータに転送できる.appファイルをビルドするところまで作業する。

```shell
$ cd ios_app

# .appファイルをビルド
xcodebuild \
  -workspace AppName.xcworkspace \
  -scheme AppName \
  -destination OS=13.2,name="iPhone 11" \
  -derivedDataPath ./build  \
  clean build

# `-derivedDataPath`がない時のビルド先
# /Users/gremito/Library/Developer/Xcode/DerivedData/AppName-xxxxxxxxxxxxxxxxxxxxxxx/Build/Products/Debug-iphonesimulator/AppName.app
```

上記の場合、`ios_app/build/Build/Products/Debug-iphonesimulator/AppName.app`


## 実機端末

.ipaファイルをビルドします。『[ipaファイルのエクスポートとdeploygateへのアップロードの自動化しました](https://blog.spacemarket.com/code/deploy-ipa/)』という記事を参考にさせていただきました🙏

```shell
$ cd ios_app

# アーカイブをビルド
$ xcodebuild   \
  -workspace AppName.xcworkspace \
  -scheme AppName \
  -configuration Release archive \
  -archivePath ./build/AppName.xcarchive

# アプリをビルド
$ xcodebuild  \
  -exportArchive  \
  -archivePath  ./build/AppName.xcarchive  \
  -exportPath ./build  \
  -exportOptionsPlist ./build/AppName.xcarchive/Info.plist
```

実機へのアプリ転送とアプリの実行は次のどれかのツールを使って試すことにしてまだ未対応。


### 申請用ビルド

次の記事が参考になりました。

- [Xcode8のxcodebuildでarchive時にsignining周りでエラーがでたときの対処法](https://yanamura.hatenablog.com/entry/2016/09/16/115743)
- [Bitriseで動作するFastlane/Gymでビルドが失敗する問題の解決方法](https://techblog.lclco.com/entry/2017/10/31/121516)

```shell
# アーカイブ時のみ
$ xcodebuild  \
  -workspace AppName.xcworkspace \
  -scheme AppName \
  -configuration Release archive \
  -archivePath ./build/AppName.xcarchive \
  CODE_SIGN_IDENTITY="${SIGN}" \
  PROVISIONING_PROFILE_SPECIFIER=${PROVISIONING}
```


## [fbsimctl](https://github.com/facebook/idb/tree/master/fbsimctl)と[idb](https://www.fbidb.io/)

Facebookが作ったiOSシミュレーターとデバイスを自動化するためのCLIツールとのこと。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">もうfbsimctlは使えないのかなぁ、全然ダメで何やっても`fbsimctl: command not found`って言われてしまう😇<br>代わりにidbがあるけどfbsimctlはidbのリポジトリ内にあって作り直した感じなのか？🤔<br>てか今頃気づいたけどiOS専用だからAndroidで同じことできんしAppium使うかw<a href="https://t.co/IM2HHJwivW">https://t.co/IM2HHJwivW</a></p>&mdash; gremito #ものラジ CSM® フリーランス (@grem_ito) <a href="https://twitter.com/grem_ito/status/1199977307290525697?ref_src=twsrc%5Etfw">November 28, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

`idb`を使うとシミュレータの起動→アプリ転送→アプリ起動→アプリ終了のコマンドを動作確認しました。

```shell
# シミュレータ起動
$ idb boot --udid XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX
# シミュレータ連携
$ idb connect XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX
# アプリ転送
$ idb install ~/ios_app/build/AppName.xcarchive/Products/Applications/AppName.app
# アプリ起動
$ idb launch net.gremito.ios.appname
# アプリ終了
$ idb terminate net.gremito.ios.appname
# アプリ削除
$ idb uninstall net.gremito.ios.appname
```


## [Appium](http://appium.io/)

`appium`は、デスクトップ版とCLI版があり、CI環境を作る場合は、[appium/appium](https://github.com/appium/appium)にある[getting-started.md](https://github.com/appium/appium/blob/master/docs/en/about-appium/getting-started.md)を参考にCLI版を入れる方が良い。

`appium`の最初の難関は、`$appium doctor`で❌が表示している内容を対応するところでしょう。
と言ってもすんなり終わる場合もあるのでappiumを使う前に問題は把握して対処しておく。


## [Airtest](https://github.com/AirtestProject/Airtest)

サクッと試したかったが、そもそもPythonの管理でガッツリハマる。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">MojaveはMissing the OpenSSL lib?の問題でCatalinaはRead-only file systemの問題でってどういうこっちゃねんwww</p>&mdash; gremito #ものラジ CSM® フリーランス (@grem_ito) <a href="https://twitter.com/grem_ito/status/1199882010681982977?ref_src=twsrc%5Etfw">November 28, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

次に[opencv-contrib-python](https://pypi.org/project/opencv-contrib-python/)のインストール時に指定した古いバージョンが取れなかった。
おそらく[opencv-python](https://pypi.org/project/opencv-python/)も同様だと思い、少し調査して対応していたもののサクッとできなかったため中断した。

```shell
$ python3 -m pip install -U airtest
Collecting airtest
  Using cached 

# 省略

Collecting opencv-contrib-python<=3.4.2.17 (from airtest)
  ERROR: Could not find a version that satisfies the requirement opencv-contrib-python<=3.4.2.17 (from airtest) (from versions: 3.4.8.29, 4.1.2.30)
ERROR: No matching distribution found for opencv-contrib-python<=3.4.2.17 (from airtest)
WARNING: You are using pip version 19.2.3, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
```

# おまけ

## `Debug-iphonesimulator`について

シミュレータビルドの際、`ios_app/build/Build/Products/Debug-iphonesimulator/AppName.app`に成果物ができています。
コマンドラインでも`iPhone 11`と指定しているので気づきにくいですが、iPadの場合は`Debug-iphonesimulator`ではなく、`Debug-ipadsimulator`と作られパスが変わってしまうのか、という疑問について。

```
$ xcodebuild -showsdks
iOS SDKs:
	iOS 13.2                      	-sdk iphoneos13.2

iOS Simulator SDKs:
	Simulator - iOS 13.2          	-sdk iphonesimulator13.2

macOS SDKs:
	DriverKit 19.0                	-sdk driverkit.macosx19.0
	macOS 10.15                   	-sdk macosx10.15

tvOS SDKs:
	tvOS 13.2                     	-sdk appletvos13.2

tvOS Simulator SDKs:
	Simulator - tvOS 13.2         	-sdk appletvsimulator13.2

watchOS SDKs:
	watchOS 6.1                   	-sdk watchos6.1

watchOS Simulator SDKs:
	Simulator - watchOS 6.1       	-sdk watchsimulator6.1
```

上記のように`iOS Simulator SDKs`は一律`iphonesimulator13.2`と括られています。
試しに`-destination OS=13.2,name="iPad (7th generation)"`とオプションの値を変えてビルドしてみたところパスは変わらずで`Debug-iphonesimulator`でした。