Wi-Fi RTT(ラウンドトリップ時間)API が提供する Wi-Fi 位置情報機能を使用して、付近にある RTT 対応の Wi-Fi アクセス ポイントや Wi-Fi Aware ピア デバイスとの距離を測定できます。
3 つ以上のアクセス ポイントまでの距離を測定する場合は、マルチラテレーション アルゴリズムを使用して、測定に最適なデバイスの位置を推定できます。結果の精度は通常 1~2 メートルの誤差の範囲内です。
この精度を確保できることによって、屋内ナビゲーション、明確な音声操作(例: 「このライトをつけて」)、位置情報をベースとする情報(例: 「このサービスに関してスペシャル オファーはありますか?」)などの精度の高い、位置情報を利用したサービスを開発できます。
リクエスト元のデバイスは、Wi-Fi RTT で距離を測定するためにアクセス ポイントに接続する必要はありません。プライバシーを保護するために、アクセス ポイントまでの距離を判断できるのはリクエスト元のデバイスのみです。アクセス ポイントにはこの情報がありません。Wi-Fi RTT オペレーションでは、フォアグラウンド アプリに対する制限はありませんが、バックグラウンド アプリに対しては制限が課されます。
Wi-Fi RTT と関連する Fine-Time-Measurement(FTM)機能は、IEEE 802.11-2016 規格で規定されています。Wi-Fi RTT では、パケットがデバイス間を往復する時間を測定し、測定された時間に光速を乗じることによって 2 つのデバイス間の距離を計算するため、FTM による正確な時間測定が必要です。
Android 15(API レベル 35)では、IEEE 802.11az のトリガーベース以外の(NTB)測距のサポートが導入されました。
Android のバージョンに基づく実装の違い
Wi-Fi RTT は Android 9(API レベル 28)で導入されました。Android 9 搭載デバイスの場合、このプロトコルを使用してマルチラテレーションでデバイスの位置を特定するには、アプリが事前定義されたアクセス ポイント(AP)の位置情報データにアクセスする必要があります。このデータの保存方法や取得方法は任意に決定できます。
Android 10(API レベル 29)以降を搭載するデバイスでは、AP の位置情報データは緯度、経度、高度を含む ResponderLocation
オブジェクトとして表すことができます。Location Configuration Information / Location Civic Report(LCI / LCR データ)をサポートする Wi-Fi RTT AP の場合、プロトコルは距離測定プロセス中に ResponderLocation
オブジェクトを返します。
この機能を使用すると、アプリは事前にこの情報を保存する代わりに、AP に直接クエリを実行して位置を問い合わせることができます。そのため、ユーザーがある建物に初めて入ったときなど、AP を事前に把握できていない場合でも、アプリは AP を見つけてその位置を特定できます。
IEEE 802.11az NTB 測距のサポートは、Android 15(API レベル 35)以降を搭載したデバイスで利用できます。つまり、デバイスが IEEE 802.11az NTB イニシエーター モード(WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR
で示されます)をサポートしている場合、アプリは 1 回の測定リクエストで IEEE 802.11mc 対応 AP と IEEE 802.11az 対応 AP の両方を見つけることができます。RangingResult
API が拡張され、測定範囲の間隔に使用できる最小値と最大値に関する情報が提供されるようになりました。正確な間隔はアプリで制御できます。
要件
- 距離測定のリクエストを行うデバイスのハードウェアは、802.11-2016 FTM 規格または 802.11az 規格(トリガーベース以外の測定)を実装する必要があります。
- 測距リクエストを行うデバイスは、Android 9(API レベル 28)以降を搭載している必要があります。IEEE 802.11az のトリガーベース以外の測距は、Android 15(API レベル 35)以降を搭載したデバイスで有効になります。
- 距離測定のリクエストを行うデバイスでは、[設定] > [位置情報] で位置情報サービスを有効にして Wi-Fi スキャンをオンにする必要があります。
- 測距リクエストを行うアプリが Android 13(API レベル 33)以降をターゲットとしている場合は、
NEARBY_WIFI_DEVICES
権限が必要です。このようなアプリが以前のバージョンの Android をターゲットとしている場合は、代わりにACCESS_FINE_LOCATION
権限が必要です。 - アプリは表示中またはフォアグラウンドでの実行中に、アクセス ポイントの距離を照会する必要があります。アプリはバックグラウンドからは位置情報にアクセスできません。
- アクセス ポイントは、IEEE 802.11-2016 FTM 規格または IEEE 802.11az 規格(トリガーベース以外の測距)を実装する必要があります。
設定
Wi-Fi RTT を使用するようにアプリを設定するには、次の手順を行います。
1. 権限をリクエストする
アプリのマニフェストで次の権限をリクエストします。
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- If your app targets Android 13 (API level 33)
or higher, you must declare the NEARBY_WIFI_DEVICES permission. -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
<!-- If your app derives location information from Wi-Fi APIs,
don't include the "usesPermissionFlags" attribute. -->
android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
<!-- If any feature in your app relies on precise location
information, don't include the "maxSdkVersion"
attribute. -->
android:maxSdkVersion="32" />
NEARBY_WIFI_DEVICES
権限と ACCESS_FINE_LOCATION
権限は危険な権限であるため、RTT スキャン オペレーションの実行がユーザーに必要になるたびに実行時にリクエストする必要があります。権限がまだ付与されていない場合、アプリはユーザーの権限をリクエストする必要があります。ランタイム権限の詳細については、アプリの権限をリクエストするをご覧ください。
2. デバイスが Wi-Fi RTT に対応しているかどうかを確認する
デバイスが Wi-Fi RTT に対応しているかどうかを確認するには、PackageManager
API を使用します。
Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
3. Wi-Fi RTT が利用可能かどうかを確認する
デバイスに Wi-Fi RTT があっても、ユーザーが無効にしているために Wi-Fi RTT が利用できない場合があります。ハードウェアとファームウェアの機能によっては、SoftAP、またはテザリングが使用されている場合に、一部のデバイスで Wi-Fi RTT がサポートされない可能性があります。Wi-Fi RTT が利用可能かどうかを確認するには、isAvailable()
を呼び出します。
Wi-Fi RTT の有効な状態は随時変わる可能性があります。アプリは BroadcastReceiver
を登録して ACTION_WIFI_RTT_STATE_CHANGED
を受信する必要があります。これは、利用できるかどうかが変更されたときに送信されます。ブロードキャスト インテントを受け取ったら、アプリは現在の状態を確認し、それに応じて動作を調整する必要があります。
次に例を示します。
Kotlin
val filter = IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED) val myReceiver = object: BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (wifiRttManager.isAvailable) { … } else { … } } } context.registerReceiver(myReceiver, filter)
Java
IntentFilter filter = new IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED); BroadcastReceiver myReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (wifiRttManager.isAvailable()) { … } else { … } } }; context.registerReceiver(myReceiver, filter);
詳細については、ブロードキャストをご覧ください。
距離測定のリクエストを作成する
距離測定のリクエスト(RangingRequest
)は、距離をリクエストする対象の AP または Wi-Fi Aware ピアのリストを指定して作成します。1 つの距離測定リクエストで複数のアクセス ポイントまたは Wi-Fi Aware ピアを指定すると、すべてのデバイスまでの距離が測定され、返されます。
たとえば、次のように、リクエストで addAccessPoint()
メソッドを使用して、距離を測定する対象のアクセス ポイントを指定できます。
Kotlin
val req: RangingRequest = RangingRequest.Builder().run { addAccessPoint(ap1ScanResult) addAccessPoint(ap2ScanResult) build() }
Java
RangingRequest.Builder builder = new RangingRequest.Builder(); builder.addAccessPoint(ap1ScanResult); builder.addAccessPoint(ap2ScanResult); RangingRequest req = builder.build();
アクセス ポイントは、ScanResult
オブジェクトによって識別されます。このオブジェクトは、WifiManager.getScanResults()
を呼び出すことで取得できます。addAccessPoints(List<ScanResult>)
を使用すると、複数のアクセス ポイントを一括で追加できます。
ScanResult
オブジェクトには、IEEE 802.11mc(is80211mcResponder()
)と IEEE 802.11az のトリガーベース以外の測距(is80211azNtbResponder()
)をサポートする AP の両方を指定できます。IEEE 802.11az NTB 測距をサポートするデバイスは、AP の機能に応じて 802.11mc または 802.11az 測距を行います。AP が両方をサポートしている場合は、デフォルトで 802.11az になります。IEEE 802.11az をサポートしていないデバイスは、IEEE 802.11mc プロトコルを使用してすべての測距を行います。
同様に、距離測定のリクエストで MAC アドレスまたは PeerHandle
を使用して Wi-Fi Aware ピアを追加する場合は、addWifiAwarePeer(MacAddress peer)
メソッドまたは addWifiAwarePeer(PeerHandle peer)
メソッドをそれぞれ使用できます。Wi-Fi Aware ピアの検出について詳しくは、Wi-Fi Aware のドキュメントをご覧ください。
距離測定をリクエストする
アプリは、WifiRttManager.startRanging()
メソッドを使用して距離測定のリクエストを発行します。操作を表す RangingRequest
、コールバック コンテキストを表す Executor
、結果を受け取る RangingResultCallback
を指定します。
例:
Kotlin
val mgr = context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE) as WifiRttManager val request: RangingRequest = myRequest mgr.startRanging(request, executor, object : RangingResultCallback() { override fun onRangingResults(results: List<RangingResult>) { … } override fun onRangingFailure(code: Int) { … } })
Java
WifiRttManager mgr = (WifiRttManager) Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE); RangingRequest request ...; mgr.startRanging(request, executor, new RangingResultCallback() { @Override public void onRangingFailure(int code) { … } @Override public void onRangingResults(List<RangingResult> results) { … } });
距離測定オペレーションは非同期で実行され、距離測定の結果は RangingResultCallback
のコールバックの 1 つで返されます。
- 距離測定オペレーション全体が失敗した場合、
RangingResultCallback
で説明されているステータス コードでonRangingFailure
コールバックがトリガーされます。このような失敗は、Wi-Fi が無効になっている、アプリがリクエストした距離測定オペレーションが多すぎるため制限が課されている、または権限に問題があるなどの理由により、サービスで距離測定オペレーションが実行できない場合に発生します。 - 測距オペレーションが完了すると、
onRangingResults
コールバックが、リクエストのリストに一致する結果(各リクエストに対して 1 つの結果)のリストでトリガーされます。結果の順序は、リクエストの順序と一致しない場合があります。距離測定オペレーションが完了した場合でも、各結果が依然として特定の測定の失敗を示している可能性がある点に留意してください。
距離測定の結果を解釈する
onRangingResults
コールバックによって返される各結果は、RangingResult
オブジェクトによって指定されます。各リクエストで、次の操作を行います。
1. リクエストを特定する
RangingRequest
の作成時に提供された情報(ほとんどの場合は、ScanResult
で提供され、アクセス ポイントを特定する MAC アドレス)に基づいてリクエストを特定します。MAC アドレスは、getMacAddress()
メソッドを使用して距離測定の結果から取得できます。
距離測定の結果のリストにおける並び順は、距離測定リクエストで指定されたピア(アクセス ポイント)とは異なる場合があるため、結果の順序ではなく MAC アドレスを使用してピアを特定する必要があります。
2. 各測定が成功したかどうかを判断する
測定が成功したかどうかを判断するには、getStatus()
メソッドを使用します。STATUS_SUCCESS
以外の値は失敗を示します。失敗した場合、この結果の他のすべてのフィールド(上記のリクエスト ID を除く)は無効になり、対応する get*
メソッドは IllegalStateException
例外で失敗します。
3. 成功した各測定の結果を取得する
成功した測定(RangingResult
)ごとに、それぞれの get
メソッドを使用して結果の値を取得できます。
距離(mm)と測定の標準偏差:
測定に使用されたパケットの RSSI:
測定が行われた時間(ミリ秒。起動からの経過時間を示します):
試行された測定回数と成功した測定回数(距離測定はこれに基づきます):
クライアント デバイスが 11az NTB 測定の間に待機する最小時間と最大時間:
getMinTimeBetweenNtbMeasurementsMicros()
とgetMaxTimeBetweenNtbMeasurementsMicros()
は、最小時間と最大時間を返します。最小時間が経過する前に次の測定がリクエストされた場合、API はキャッシュに保存された測定結果を返します。最大時間が経過した後に次の測距測定がリクエストされた場合、API はトリガー以外の測距セッションを終了し、応答ステーションで新しい測距セッションをネゴシエートします。新しい測距セッションをリクエストすると、測距測定時間にオーバーヘッドが発生するため、リクエストしないでください。802.11az のトリガーベース以外の測定の効率を最大限に活用するには、前のRangingResult
測定で指定された最小測定時間と最大測定時間の間に次の測定リクエストをトリガーします。レスポンダ ステーションとイニシエーター ステーションが IEEE 802.11az NTB の結果のプリアンブルで使用したロング トレーニング フィールド(LTF)の繰り返し:
イニシエーター ステーションによって IEEE 802.11az NTB の結果に使用された送信空間時間ストリーム(STS)と受信空間時間ストリーム(STS)の数:
Wi-Fi-RTT 対応の Android デバイス
次の表に、WiFi-RTT をサポートするスマートフォン、アクセス ポイント、小売店、倉庫、配送センターのデバイスを示します。これらはごく一部を示したものです。こちらに RTT 対応プロダクトを掲載される場合は、お問い合わせいただくことをおすすめします。
アクセス ポイント
メーカーとモデル | サポート日 |
---|---|
Google Nest Wifi Pro (Wi-Fi 6E) | サポート対象 |
Compulab WILD AP | サポート対象 |
Google WiFi | サポート対象 |
Google Nest Wifi ルーター | サポート対象 |
Google Nest Wifi 拡張ポイント | サポート対象 |
Aruba AP-635 | サポート対象 |
Cisco 9130 | サポート対象 |
Cisco 9136 | サポート対象 |
Cisco 9166 | サポート対象 |
Cisco 9164 | サポート対象 |
Aruba AP-505 | サポート対象 |
Aruba AP-515 | サポート対象 |
Aruba AP-575 | サポート対象 |
Aruba AP-518 | サポート対象 |
Aruba AP-505H | サポート対象 |
Aruba AP-565 | サポート対象 |
Aruba AP-535 | サポート対象 |
スマートフォン
メーカーとモデル | Android バージョン |
---|---|
Google Pixel 6 | 9.0+ |
Google Pixel 6 Pro | 9.0+ |
Google Pixel 5 | 9.0+ |
Google Pixel 5a | 9.0+ |
Google Pixel 5a (5G) | 9.0+ |
Xiaomi Mi 10 Pro | 9.0+ |
Xiaomi Mi 10 | 9.0+ |
Xiaomi Redmi Mi 9T Pro | 9.0+ |
Xiaomi Mi 9T | 9.0+ |
Xiaomi Mi 9 | 9.0+ |
Xiaomi Mi Note 10 | 9.0+ |
Xiaomi Mi Note 10 Lite | 9.0+ |
Xiaomi Redmi Note 9S | 9.0+ |
Xiaomi Redmi Note 9 Pro | 9.0+ |
Xiaomi Redmi Note 8T | 9.0+ |
Xiaomi Redmi Note 8 | 9.0+ |
Xiaomi Redmi K30 Pro | 9.0+ |
Xiaomi Redmi K20 Pro | 9.0+ |
Xiaomi Redmi K20 | 9.0+ |
Xiaomi Redmi Note 5 Pro | 9.0+ |
Xiaomi Mi CC9 Pro | 9.0+ |
LG G8X ThinQ | 9.0+ |
LG V50S ThinQ | 9.0+ |
LG V60 ThinQ | 9.0+ |
LG V30 | 9.0+ |
Samsung Galaxy Note 10+ 5G | 9.0+ |
Samsung Galaxy S20+ 5G | 9.0+ |
Samsung Galaxy S20+ | 9.0+ |
Samsung Galaxy S20 5G | 9.0+ |
Samsung Galaxy S20 Ultra 5G | 9.0+ |
Samsung Galaxy S20 | 9.0+ |
Samsung Galaxy Note 10+ | 9.0+ |
Samsung Galaxy Note 10 5G | 9.0+ |
Samsung Galaxy Note10 | 9.0+ |
Samsung A9 Pro | 9.0+ |
Google Pixel 4 XL | 9.0+ |
Google Pixel 4 | 9.0+ |
Google Pixel 4a | 9.0+ |
Google Pixel 3 XL | 9.0+ |
Google Pixel 3 | 9.0+ |
Google Pixel 3a XL | 9.0+ |
Google Pixel 3a | 9.0+ |
Google Pixel 2 XL | 9.0+ |
Google Pixel 2 | 9.0+ |
Google Pixel 1 XL | 9.0+ |
Google Pixel 1 | 9.0+ |
Poco X2 | 9.0+ |
シャープ Aquos R3 SH-04L | 9.0+ |
小売店、倉庫、配送センター向けデバイス
メーカーとモデル | Android バージョン |
---|---|
Zebra PS20 | 10.0 以降 |
Zebra TC52/TC52HC | 10.0 以降 |
Zebra TC57 | 10.0 以降 |
Zebra TC72 | 10.0 以降 |
Zebra TC77 | 10.0 以降 |
Zebra MC93 | 10.0 以降 |
Zebra TC8300 | 10.0 以降 |
Zebra VC8300 | 10.0 以降 |
Zebra EC30 | 10.0 以降 |
Zebra ET51 | 10.0 以降 |
Zebra ET56 | 10.0 以降 |
Zebra L10 | 10.0 以降 |
Zebra CC600/CC6000 | 10.0 以降 |
Zebra MC3300x | 10.0 以降 |
Zebra MC330x | 10.0 以降 |
Zebra TC52x | 10.0 以降 |
Zebra TC57x | 10.0 以降 |
Zebra EC50(LAN と HC) | 10.0 以降 |
Zebra EC55(WAN) | 10.0 以降 |
Zebra WT6300 | 10.0 以降 |
Skorpio X5 | 10.0 以降 |