xcrun simctl privacyは、写真・連絡先・位置情報などのプライバシー系権限を、確認ダイアログを表示せずに操作するサブコマンドである。

基本的な使い方

privacy <device> <action> <service> [<bundle identifier>]の形式で実行する。

<action>には次の3種類を指定できる。

action内容
grant確認なしでアクセスを許可する。<bundle identifier>が必須
revokeアクセスを拒否し、そのサービスの利用を全て禁止する。<bundle identifier>が必須
resetアクセス状態をリセットし、次回利用時に確認ダイアログを表示させる。<bundle identifier>は省略可能

<service>には次のいずれかを指定する。

service内容
all全てのサービスを対象にする
calendarカレンダーへのアクセス
contacts-limited連絡先の基本情報のみへのアクセス
contacts連絡先の詳細情報を含む全アクセス
locationアプリ使用中のみの位置情報アクセス
location-always常時の位置情報アクセス
photos-addフォトライブラリへの追加のみのアクセス
photosフォトライブラリへの全アクセス
media-libraryメディアライブラリへのアクセス
microphoneマイク(音声入力)へのアクセス
motionモーション・フィットネスデータへのアクセス
remindersリマインダーへのアクセス
siriSiriからのアプリ利用
$ xcrun simctl privacy "TIL Privacy Test" grant photos com.apple.mobilesafari

権限の反映状況は、シミュレータのTCC(プライバシー権限)データベースを直接確認すると分かりやすい。

$ sqlite3 ~/Library/Developer/CoreSimulator/Devices/<UUID>/data/Library/TCC/TCC.db \
    "SELECT service, client, auth_value FROM access;"
kTCCServicePhotos|com.apple.mobilesafari|2

auth_value2のとき許可、0のとき拒否を意味する。

grant/revokeはbundle identifierが必須

grantrevokeはアプリを一意に指定する必要があり、<bundle identifier>を省略するとエラーになる。

$ xcrun simctl privacy "TIL Privacy Test" grant photos
Bundle identifier is required for grant actions

revokeを実行すると、TCCデータベース上のauth_valueが拒否を示す0に変わる。

$ xcrun simctl privacy "TIL Privacy Test" revoke photos com.apple.mobilesafari
$ sqlite3 ~/Library/Developer/CoreSimulator/Devices/<UUID>/data/Library/TCC/TCC.db \
    "SELECT service, client, auth_value FROM access WHERE service='kTCCServicePhotos';"
kTCCServicePhotos|com.apple.mobilesafari|0

reset allはbundle identifierを省略すると既存の権限に影響しない

ヘルプのExamplesにはreset all(bundle identifier省略)で全ての権限をリセットできるという例が載っているが、実際に試したところ、既にTCCデータベースに記録済みのアプリの権限には一切変化がなかった。

$ sqlite3 ~/Library/Developer/CoreSimulator/Devices/<UUID>/data/Library/TCC/TCC.db \
    "SELECT service, client, auth_value FROM access WHERE client='com.apple.mobilesafari';"
kTCCServicePhotos|com.apple.mobilesafari|2
kTCCServiceAddressBook|com.apple.mobilesafari|2

$ xcrun simctl privacy "TIL Privacy Test" reset all

$ sqlite3 ~/Library/Developer/CoreSimulator/Devices/<UUID>/data/Library/TCC/TCC.db \
    "SELECT service, client, auth_value FROM access WHERE client='com.apple.mobilesafari';"
kTCCServicePhotos|com.apple.mobilesafari|2
kTCCServiceAddressBook|com.apple.mobilesafari|2

一方、<bundle identifier>を指定してreset all com.apple.mobilesafariのように実行すると、そのアプリの全サービスのTCCレコードが実際に削除された(対象アプリは次に該当機能を使うときに確認ダイアログが再表示される状態になる)。

$ xcrun simctl privacy "TIL Privacy Test" reset all com.apple.mobilesafari

$ sqlite3 ~/Library/Developer/CoreSimulator/Devices/<UUID>/data/Library/TCC/TCC.db \
    "SELECT count(*) FROM access WHERE client='com.apple.mobilesafari';"
0

個別のサービス・アプリを指定したreset <service> <bundle identifier>でも、該当するTCCレコードのみ削除されることを確認した。 特定のアプリの権限を確実にリセットしたい場合は、<bundle identifier>を省略せずに指定する必要がある。

活用例: UIテストで権限確認ダイアログを回避する

UIテストの実行前にあらかじめgrantで必要な権限を許可しておくと、実際のアプリ操作中に確認ダイアログが表示されず、テストが安定して進行する。

$ xcrun simctl privacy "TIL Privacy Test" grant photos com.example.app
$ xcrun simctl privacy "TIL Privacy Test" grant location com.example.app

ヘルプにも記載されているとおり、この方法はアプリ本来のInfo.plist設定やAPI呼び出しの不備を隠してしまう可能性があるため、権限リクエストの実装自体を検証したいテストでは使わない方がよい。