Wi-Fi 位置:範圍涵蓋即時文字訊息

您可以使用 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 版本的實作差異

Android 9 (API 級別 28) 已導入 Wi-Fi RTT。如果在搭載 Android 9 的裝置中使用多重延遲功能判斷裝置的位置,您必須能在應用程式中存取預先定義的存取點 (AP) 位置資料,並由您決定如何儲存及擷取這項資料。

在搭載 Android 10 (API 級別 29) 以上版本的裝置上,AP 位置資料可以表示為 ResponderLocation 物件,包括緯度、經度和高度。如果是支援位置資訊設定資訊/位置資訊公民報告 (LCI/LCR 資料) 的 Wi-Fi RTT AP,通訊協定會在計量程序期間傳回 ResponderLocation 物件。

這項功能可讓應用程式查詢 AP 直接要求其位置,不必事先儲存這項資訊。因此,即使在使用者進入新建築物時 (例如使用者進入新建築時),應用程式仍可找到 AP 並判斷其位置,即使沒有 AP 也不例外。

規定

  • 發出測距要求的裝置硬體必須實作 802.11-2016 FTM 標準。
  • 發出測距要求的裝置必須搭載 Android 9 (API 級別 28) 以上版本。
  • 發出測距要求的裝置必須啟用定位服務並且開啟 Wi-Fi 掃描功能 (在「設定」>「位置」下)。
  • 如果發出測距要求的應用程式指定 Android 13 (API 級別 33) 以上版本,則必須具備 NEARBY_WIFI_DEVICES 權限。如果這類應用程式指定舊版 Android,則必須擁有 ACCESS_FINE_LOCATION 權限。
  • 當應用程式處於可見狀態或前景服務中時,應用程式必須查詢存取點的範圍。應用程式無法從背景存取位置資訊
  • 存取點必須導入 IEEE 802.11-2016 FTM 標準。

設定

如要將應用程式設為使用 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_DEVICESACCESS_FINE_LOCATION 權限為危險權限,因此您每次使用者要執行 RTT 掃描作業時,都需要在執行階段提出要求。如果應用程式尚未授予權限,則應用程式必須要求使用者的權限。如要進一步瞭解執行階段權限,請參閱「要求應用程式權限」。

2. 檢查裝置是否支援 Wi-Fi 即時文字訊息

如要檢查裝置是否支援 Wi-Fi RTT,請使用 PackageManager API:

Kotlin

context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)

Java

context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);

3. 檢查是否可使用 Wi-Fi 即時文字訊息

裝置上可能存在 Wi-Fi RTT,但目前可能無法使用,因為使用者已停用 Wi-Fi。視硬體和韌體功能而定,如果使用 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);

詳情請參閱廣播的相關說明。

建立測距要求

透過指定要求範圍的 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),分批新增多個存取點。

同樣地,分距要求可分別使用 addWifiAwarePeer(MacAddress 對等點)addWifiAwarePeer(對等對等互連) 方法,透過其 MAC 位址或 PeerHandle 新增 Wi-Fi 感知對等點。如要進一步瞭解如何探索 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 的其中一個回呼中傳回:

  • 如果整個測距作業失敗,系統會使用 RangingResultCallback 所述的狀態碼觸發 onRangingFailure 回呼。如果服務無法即時執行測距作業 (例如因為 Wi-Fi 已停用、應用程式要求過多範圍作業且受到限制,或者是權限問題),就可能會發生這種失敗。
  • 範圍作業完成後,系統會觸發 onRangingResults 回呼,並附上與要求清單相符的結果清單 (每個要求各有一個結果)。結果的順序不一定會與要求的順序一致。請注意,測距作業可能已完成,但每項結果可能仍表示該項測量作業失敗。

解讀範圍結果

onRangingResults 回呼傳回的每個結果,都是由 RangingResult 物件指定。在每個要求中執行下列操作。

1. 確定要求

根據建立 RangingRequest 時提供的資訊來識別要求:通常是在 ScanResult 中提供的 MAC 位址,用於識別存取點。您可使用 getMacAddress() 方法從測距結果取得 MAC 位址。

估算結果清單的順序可能與分距要求中指定的對等點 (存取點) 不同,因此建議您使用 MAC 位址來識別對等互連,而非使用結果的順序。

2. 判斷各項評估是否成功

如要判斷測量是否成功,請使用 getStatus() 方法。STATUS_SUCCESS 以外的任何值都表示失敗。失敗表示此結果的所有其他欄位 (上方要求識別除外) 無效,對應的 get* 方法將失敗,並產生 IllegalStateException 例外狀況。

3. 每次成功評估成效

針對每個成功的測量結果,您可以使用各自的 get 方法擷取結果值:

支援 Wi-RTT 的 Android 裝置

下表列出部分支援 WiFi-RTT 的手機存取點,以及零售、倉儲和配送中心裝置。但這些其實並未涵蓋所有情況。建議您與我們聯絡,在這裡列出支援 RTT 的產品。

存取點

製造商和型號 支援日期
Nest Wifi Pro (Wi-Fi 6E) 有權限
Compulab WILD AP 有權限
Google Wi-Fi 有權限
Google Nest Wi-Fi 路由器 有權限
Google Nest Wi-Fi Point 有權限
阿魯巴 AP-635 有權限
思科 9130 有權限
思科 9136 有權限
思科 9166 有權限
Cisco 9164 有權限
阿魯巴 AP-505 有權限
阿魯巴 AP-515 有權限
阿魯巴 AP-575 有權限
阿魯巴 AP-518 有權限
阿魯巴 AP-505H 有權限
阿魯巴 AP-565 有權限
阿魯巴 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 以上版本
小米 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 以上版本
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 以上版本
小米 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 以上版本
夏普 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 以上版本
斑馬 MC93 10.0 以上版本
Zebra TC8300 10.0 以上版本
Zebra VC8300 10.0 以上版本
斑馬 EC30 10.0 以上版本
斑馬 ET51 10.0 以上版本
斑馬 ET56 10.0 以上版本
賽布拉第 10 級 10.0 以上版本
薩布拉 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 以上版本
澤布拉 WT6300 10.0 以上版本
Skorpio X5 10.0 以上版本