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 并确定其位置,例如当用户进入新建筑时。

IEEE 802.11az NTB 测距支持适用于运行 Android 15(API 级别 35)及更高版本的设备。这意味着,如果设备支持 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)或更高版本。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_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 地址,用于标识接入点。MAC 地址可以使用 getMacAddress() 方法从测距结果中获取。

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

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

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

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

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

支持 WiFi-RTT 的 Android 设备

下表列出了一些支持 WiFi-RTT 的手机接入点以及零售、仓储和配送中心设备。这些列表远非完整。我们鼓励您联系我们,在此处列出您的支持 RTT 的产品。

接入点

制造商和型号 支持日期 协议
Nest Wifi Pro (Wi-Fi 6E) 支持 mc
Compulab WILD AP 支持 mc
Google Wi-Fi 支持 mc
Google Nest Wi-Fi 路由器 支持 mc
Google Nest Wi-Fi 节点 支持 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+
小米 10 Pro 9.0+
小米 10 9.0+
小米 Redmi Mi 9T Pro 9.0+
小米 9T 9.0+
小米 9 9.0+
小米 Note 10 9.0+
小米 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+
小米 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+
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+