您可以使用 Wi-Fi RTT (Round-Trip-Time) API 提供的 Wi-Fi 定位功能,測量到附近支援 RTT 的 Wi-Fi 存取點和同級 Wi-Fi Aware 裝置的距離。
如果您測量到三個以上存取點的距離,可以使用多邊測量演算法,估算最符合這些測量值的裝置位置。結果通常會在 1 到 2 公尺的範圍內。
有了這項精確度,您就能開發精細的適地性服務,例如室內導航、不易混淆的語音控制 (例如「打開這盞燈」),以及適地性資訊 (例如「這項產品有特惠嗎?」)。
要求裝置不需要連線至存取點,即可透過 Wi-Fi RTT 測量距離。為了維護隱私權,只有提出要求的裝置可以判斷與存取點的距離;存取點沒有這項資訊。前景應用程式可無限制執行 Wi-Fi RTT 作業,但背景應用程式則會受到限制。
IEEE 802.11-2016 標準會指定 Wi-Fi RTT 和相關的 Fine-Time-Measurement (FTM) 功能。Wi-Fi RTT 需要 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
物件,包括緯度、經度和高度。對於支援位置設定資訊/位置公民報告 (LCI/LCR 資料) 的 Wi-Fi RTT AP,通訊協定會在測距程序期間傳回 ResponderLocation
物件。
這項功能可讓應用程式查詢 AP,直接要求對方提供位置,而不需要事先儲存這項資訊。因此,即使未知 AP 位置 (例如使用者進入新建築物時),應用程式仍可找到 AP 並判斷其位置。
搭載 Android 15 (API 級別 35) 以上版本的裝置支援 IEEE 802.11az NTB 測距功能。也就是說,如果裝置支援 IEEE 802.11az NTB 啟動器模式 (由 WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR
表示),您的應用程式就能透過單一範圍要求找到支援 IEEE 802.11mc 和 IEEE 802.11az 的 AP。RangingResult
API 已擴充,可提供可用於測量範圍間隔的最小值和最大值資訊,讓應用程式可控制確切的間隔。
需求條件
- 提出測距要求的裝置硬體必須實作 802.11-2016 FTM 標準或 802.11az 標準 (非觸發式測距)。
- 提出測距要求的裝置必須搭載 Android 9 (API 級別 28) 以上版本。在搭載 Android 15 (API 級別 35) 以上版本的裝置上,可啟用 IEEE 802.11az 非觸發式測距功能。
- 提出測距要求的裝置必須啟用定位服務,並開啟 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,因此可能無法使用。視硬體和韌體功能而定,部分裝置在使用 SoftAP 或 Tethering 時,可能不支援 Wi-Fi RTT。如要確認是否可使用 Wi-Fi 即時文字訊息功能,請撥打 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);
詳情請參閱廣播的相關說明。
建立測距要求
指定要要求範圍的 AP 或 Wi-Fi Aware 同端節點清單,即可建立測距要求 (RangingRequest
)。在單一測距要求中指定多個存取點或 Wi-Fi 感知對等項目,系統會測量並傳回所有裝置的距離。
舉例來說,要求可以使用 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()
) 的無線基地台。支援 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
回呼傳回:
- 如果整個測距作業失敗,系統會觸發
onRangingFailure
回呼,並傳回RangingResultCallback
中所述的狀態碼。如果服務無法在當下執行測距作業 (例如因為 Wi-Fi 已停用、應用程式要求過多測距作業而遭到節流,或因為權限問題),就可能發生這種失敗。 - 當測距作業完成後,系統會觸發
onRangingResults
回呼,並提供與要求清單相符的結果清單,也就是每個要求一個結果。結果的順序不一定會與要求的順序相符。請注意,測距作業可能會完成,但每個結果仍可能表示該特定測量失敗。
解讀測距結果
onRangingResults
回呼傳回的每個結果都是由 RangingResult
物件指定。在每個要求中執行下列操作。
1. 識別要求
根據建立 RangingRequest
時提供的資訊識別要求:通常是 ScanResult
中提供的 MAC 位址,用於識別存取點。您可以使用 getMacAddress()
方法,從測距結果取得 MAC 位址。
測距結果清單的順序可能與測距要求中指定的同儕 (存取點) 不同,因此您應使用 MAC 位址來識別同儕,而非結果順序。
2. 判斷各項測量是否成功
如要判斷測量是否成功,請使用 getStatus()
方法。任何值如果不是 STATUS_SUCCESS
,都表示失敗。失敗表示此結果的所有其他欄位 (上述要求 ID 除外) 皆無效,且對應的 get*
方法會失敗,並擲回 IllegalStateException
例外狀況。
3. 取得每項成功評估的結果
針對每個成功的測量結果 (RangingResult
),您可以使用對應的 get
方法擷取結果值:
距離 (以公釐為單位) 和測量標準差:
用於評估的封包 RSSI:
測量作業的執行時間 (以毫秒為單位),表示裝置啟動後所經過的時間:
嘗試的測量次數和成功的測量結果數 (以及測量距離的計算依據):
用戶端裝置必須在 11az NTB 測量之間等待的最短和最長時間:
getMinTimeBetweenNtbMeasurementsMicros()
和getMaxTimeBetweenNtbMeasurementsMicros()
會傳回最短和最長時間。如果在最短時間內要求下一個測距量測,API 會傳回快取的測距結果。如果在最長時間過後要求下一個測量範圍,API 會終止非觸發測量範圍工作階段,並與回應站協商新的測量範圍工作階段。請避免要求新的測距工作階段,因為這會增加測距測量時間的額外負擔。如要充分利用 802.11az 非觸發式測距效率,請在先前RangingResult
測量指定的最小和最大測量時間之間觸發下一個測距要求。回應端和啟動端無線基地台在 IEEE 802.11az NTB 結果前置碼中使用的長訓練欄位 (LTF) 重複次數:
發起端站點用於 IEEE 802.11az NTB 結果的傳送和接收空間時間串流 (STS) 數量:
支援 Wi-RTT 的 Android 裝置
下表列出支援 WiFi-RTT 的部分手機、存取點和零售、倉儲和配送中心裝置。這些絕非全面的解決方案。建議你與我們聯絡,將支援 RTT 的產品列入清單。
存取點
製造商和型號 | 支援日期 |
---|---|
Nest Wifi Pro (Wi-Fi 6E) | 支援 |
Compulab WILD AP | 支援 |
Google Wi-Fi | 支援 |
Google Nest Wifi 路由器 | 支援 |
Google Nest Wifi Point | 支援 |
Aruba AP-635 | 支援 |
思科 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 版本 |
---|---|
Pixel 6 | 9.0 以上 |
Pixel 6 Pro | 9.0 以上 |
Pixel 5 | 9.0 以上 |
Pixel 5a | 9.0 以上版本 |
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 以上版本 |
小米 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 以上 |
小米 Redmi K30 Pro | 9.0 以上版本 |
小米 Redmi K20 Pro | 9.0 以上 |
小米 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 Note 10 | 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 以上版本 |
Sharp Aquos R3 SH-04L | 9.0 以上 |
零售、倉儲和配送中心裝置
製造商和型號 | Android 版本 |
---|---|
賽布拉 PS20 (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 以上 |
賽布拉第 10 級 | 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 以上 |