Wi-Fi 定位:使用 RTT 进行测距

您可以使用 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_STA_RESPONDER 指示),您的应用可以使用单个测距请求查找支持 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_DEVICESACCESS_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 或网络共享,则某些设备可能不支持 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 对等方列表来创建。可以在单个测距请求中指定多个接入点或 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 的回调之一中返回

  • 如果整个测距操作失败,则 onRangingFailure 回调将触发,并带有 RangingResultCallback 中描述的状态代码。如果服务无法在此时执行测距操作,则可能会发生此类错误,例如,因为 Wi-Fi 已禁用,因为应用程序已请求太多测距操作并被限制,或者因为权限问题。
  • 当测距操作完成时,onRangingResults 回调将触发,并带有一系列与请求列表匹配的结果,每个请求一个结果。结果的顺序不一定与请求的顺序匹配。请注意,测距操作可能会完成,但每个结果仍然可能表明该特定测量的失败。

解释测距结果

onRangingResults 回调返回的每个结果都由 RangingResult 对象指定。对于每个请求,请执行以下操作。

1. 识别请求

根据创建 RangingRequest 时提供的信息识别请求:最常见的是 ScanResult 中提供的标识接入点的 MAC 地址。可以使用 getMacAddress() 方法从测距结果中获取 MAC 地址。

测距结果列表的顺序可能与测距请求中指定的对等方(接入点)不同,因此您应该使用 MAC 地址来识别对等方,而不是结果的顺序。

2. 确定每个测量是否成功

要确定测量是否成功,请使用 getStatus() 方法。任何不是 STATUS_SUCCESS 的值都表示失败。失败意味着此结果的所有其他字段(除了上面的请求标识)均无效,并且相应的 get* 方法将引发 IllegalStateException 异常。

3. 获取每个成功测量的结果

对于每个成功的测量 (RangingResult),您可以使用相应的 get 方法检索结果值

支持 WiFi-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 扩展器 支持
Aruba AP-635 支持
Cisco 9130 支持
思科 9136 支持
思科 9166 支持
思科 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+
小米 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+
小米 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+
三星 Galaxy Note 10+ 5G 9.0+
三星 Galaxy S20+ 5G 9.0+
三星 Galaxy S20+ 9.0+
三星 Galaxy S20 5G 9.0+
三星 Galaxy S20 Ultra 5G 9.0+
三星 Galaxy S20 9.0+
三星 Galaxy Note 10+ 9.0+
三星 Galaxy Note 10 5G 9.0+
三星 Galaxy Note 10 9.0+
三星 A9 Pro 9.0+
谷歌 Pixel 4 XL 9.0+
谷歌 Pixel 4 9.0+
谷歌 Pixel 4a 9.0+
谷歌 Pixel 3 XL 9.0+
谷歌 Pixel 3 9.0+
谷歌 Pixel 3a XL 9.0+
谷歌 Pixel 3a 9.0+
谷歌 Pixel 2 XL 9.0+
谷歌 Pixel 2 9.0+
谷歌 Pixel 1 XL 9.0+
谷歌 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+