您可以使用 Wi-Fi RTT (往返時間) API 提供的 Wi-Fi 定位功能,測量與鄰近 RTT 支援 Wi-Fi 存取點和對等 Wi-Fi Aware 裝置的距離。
如果測量與三個以上存取點的距離,可以使用多邊定位演算法,估算最符合這些測量的裝置位置。結果通常準確度在 1 到 2 公尺內。
有了這項精確度,您就能開發精細的適地性服務,例如室內導航、語音控制消歧 (例如「開啟這盞燈」),以及適地性資訊 (例如「這項產品有特惠活動嗎?」)。
要求裝置不需要連線至存取點,即可使用 Wi-Fi RTT 測量距離。為維護隱私權,只有要求裝置可以判斷與存取點的距離,存取點不會有這項資訊。前景應用程式可無限次數執行 Wi-Fi RTT 作業,但背景應用程式會受到節流限制。
Wi-Fi RTT 和相關的精確時間測量 (FTM) 功能,是依據 IEEE 802.11-2016 標準指定。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 後,可能就無法使用。視硬體和韌體功能而定,部分裝置可能無法支援 Wi-Fi RTT,如果使用 SoftAP 或網路共用功能,如要查看 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 對等互連裝置清單。您可以在單一測距要求中指定多個存取點或 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
,分別使用 addWifiAwarePeer(MacAddress peer)
和 addWifiAwarePeer(PeerHandle peer)
方法,新增 Wi-Fi Aware 對等互連裝置。如要進一步瞭解如何探索 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
:通常是存取點識別資訊中提供的 MAC 位址。ScanResult
您可以使用 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-Fi RTT 的 Android 裝置
下表列出支援 Wi-Fi RTT 的部分手機、存取點,以及零售、倉儲和配送中心裝置。這些只是部分範例,建議你與我們聯絡,在此列出支援 RTT 的產品。
存取點
製造商和型號 | 支援日期 | 通訊協定 |
---|---|---|
Nest Wifi Pro (Wi-Fi 6E) | 支援 | mc |
Compulab WILD AP | 支援 | mc |
Google Wi-Fi | 支援 | mc |
Google Nest Wifi 路由器 | 支援 | mc |
Google Nest Wifi Point | 支援 | mc |
Aruba AP-635 | 支援 | mc |
Cisco 9130 | 支援 | mc |
Cisco 9136 | 支援 | mc |
Cisco 9166 | 支援 | mc |
Cisco 9164 | 支援 | mc |
Cisco CW9172I | 支援 | mc/az |
Cisco CW9172H | 支援 | mc/az |
Cisco CW9176I | 支援 | mc/az |
Cisco CW9178I | 支援 | mc/az |
Aruba AP-505 | 支援 | mc |
Aruba AP-515 | 支援 | mc |
Aruba AP-575 | 支援 | mc |
Aruba AP-518 | 支援 | mc |
Aruba AP-505H | 支援 | mc |
Aruba AP-565 | 支援 | mc |
Aruba AP-535 | 支援 | mc |
Aruba AP567 | 支援 | mc |
Aruba AP577 | 支援 | mc |
Aruba AP555 | 支援 | mc |
Aruba AP635 | 支援 | mc |
Aruba AP655 | 支援 | mc |
Aruba AP615 | 支援 | mc |
Aruba AP734 | 支援 | mc/az |
Aruba AP735 | 支援 | mc/az |
Aruba AP754 | 支援 | mc/az |
Aruba AP755 | 支援 | mc/az |
手機
製造商和型號 | Android 版本 |
---|---|
Google Pixel 9 Pro XL | 14+ |
Google Pixel 9 | 14+ |
Google Pixel 9 Pro | 14+ |
Google Pixel 9 Pro XL | 14+ |
Google Pixel 7a | 14+ |
Google Pixel 7 | 14+ |
Google Pixel 8 | 14+ |
Google Pixel 8 Pro | 14+ |
Google Pixel 8a | 14+ |
Samsung SM-S918B | 14+ |
Samsung SM-A515F | 14+ |
Google Pixel 9 Pro | 14+ |
Samsung SM-A546E | 14+ |
Samsung SM-S928B | 14+ |
Samsung SM-A217F | 14+ |
Samsung SM-A715F | 14+ |
Samsung SM-A528B | 14+ |
Samsung SM-A135F | 14+ |
Samsung SM-S911B | 14+ |
Xiaomi 21091116AI | 14+ |
Google Pixel 9 | 14+ |
Samsung SM-A127F | 14+ |
Google Pixel 7 Pro | 14+ |
Samsung SM-A556E | 14+ |
Pixel 6 | 9.0 以上版本 |
Pixel 6 Pro | 9.0 以上版本 |
Pixel 5 | 9.0 以上版本 |
Pixel 5a | 9.0 以上版本 |
Pixel 5a (5G) | 9.0 以上版本 |
小米 Mi 10 Pro | 9.0 以上版本 |
小米 Mi 10 | 9.0 以上版本 |
小米 Redmi Mi 9T Pro | 9.0 以上版本 |
小米 Mi 9T | 9.0 以上版本 |
小米 Mi 9 | 9.0 以上版本 |
小米 Mi Note 10 | 9.0 以上版本 |
小米 Mi Note 10 Lite | 9.0 以上版本 |
小米 Redmi Note 9S | 9.0 以上版本 |
小米 Redmi Note 9 Pro | 9.0 以上版本 |
小米 Redmi Note 8T | 9.0 以上版本 |
小米 Redmi Note 8 | 9.0 以上版本 |
小米 Redmi K30 Pro | 9.0 以上版本 |
Xiaomi Redmi K20 Pro | 9.0 以上版本 |
小米 Redmi K20 | 9.0 以上版本 |
小米 Redmi Note 5 Pro | 9.0 以上版本 |
小米 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 版本 |
---|---|
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 以上版本 |