xcrun simctl locationは、iOSシミュレータの位置情報をシミュレートするサブコマンドである。 setオプションを使うと、緯度・経度を指定した固定値にシミュレータの位置情報を設定できる。

基本的な使い方

緯度と経度をカンマ区切りで指定するだけで、シミュレータの位置情報を設定できる。 デバイスはUDIDで指定するほか、起動中のデバイスであればbootedが使える。

$ xcrun simctl location booted set 35.681236,139.767125

コマンドはすぐに終了し、成功しても標準出力には何も表示されない。

位置情報の反映をログで確認する

設定した座標が実際に反映されているかは、位置情報アプリを開かなくてもlog streamlocationdのログを見れば確認できる。

$ xcrun simctl spawn booted log stream --level debug \
    --predicate 'eventMessage contains "raw coordinate"'

このログストリームを表示した状態で別ターミナルからlocation setを実行すると、指定した座標が即座に流れてくる。

$ xcrun simctl location booted set 35.681236,139.767125
locationd: [com.apple.locationd.Position:Position] ... raw coordinate, at location (<+35.68123600,+139.76712500>) of type 1

続けて別の座標をsetすると、ログに流れる座標もすぐに切り替わる。 位置情報を利用する機能を自動テストする際、Mapsなどの位置情報アプリを開かなくてもsetの効果を確認できる。

緯度・経度のフォーマット

緯度・経度は<緯度>,<経度>の形式で、小数点には.、区切りには,を使う。 カンマがないとエラーになる。

$ xcrun simctl location booted set 35.681236
Invalid latitude,longitude pair: 35.681236

カンマの前後に空白が入っていてもパース自体は成功し、指定した座標が問題なく反映される。

$ xcrun simctl location booted set "35.681236, 139.767125"

範囲外の値は反映されない

緯度・経度として無効な範囲の値(例えば緯度に200)を指定した場合の挙動はヘルプに記載がない。 実際に試したところ、xcrun simctl location booted set 200,300はエラーメッセージを出さず終了コード0で終わる。 しかしlog streamで確認すると、この場合locationdには座標の更新が伝わっておらず、直前に設定していた座標のままだった。 つまり今回試した200,300のようなケースでは、コマンド自体は成功したように見えても値は無視され、シミュレータの位置情報には反映されなかった。 スクリプトから動的に座標を組み立てる場合、終了コードだけで成功を判断せず、値の妥当性を呼び出し側で検証した方がよい。

活用例: 位置情報に依存する機能のテスト

地域によって表示内容が変わる機能や、ジオフェンシングを使った機能をテストする際、実機を移動させずに任意の座標へ切り替えられる。

$ xcrun simctl location booted set 35.681236,139.767125  # 東京駅
$ xcrun simctl location booted set 34.702485,135.495951  # 大阪駅

CIに組み込めば、複数の地域を想定した動作確認を実機を持ち歩かずに機械的に実行できる。

setは単発の座標を切り替えるだけである。 時間経過に伴う連続的な移動をシミュレートしたい場合は、xcrun simctl location runでiOSシミュレータにプリセットの移動シナリオを再生するrunを使うとよい。 用意されたシナリオではなく任意の経路を再生したい場合は、xcrun simctl location startでiOSシミュレータに複数地点を経由する移動をシミュレートするstartが使える。