您可以使用 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_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 或网络共享,则某些设备可能不支持 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
方法检索结果值
距离(以毫米为单位)和测量的标准偏差
用于测量的报文的 RSSI
进行测量时的时间(以毫秒为单位)(表示自启动以来的时间)
尝试的测量次数和成功的测量次数(以及距离测量基于的次数)
客户端设备在 11az NTB 测量之间必须等待的最小和最大时间
getMinTimeBetweenNtbMeasurementsMicros()
和getMaxTimeBetweenNtbMeasurementsMicros()
返回最小和最大时间。如果在最小时间过去之前请求下一个测距测量,则 API 将返回缓存的测距结果。如果在最大时间过去之后请求下一个测距测量,则 API 将终止非触发测距会话并与响应站协商新的测距会话。您应避免请求新的测距会话,因为它会增加测距测量时间开销。为了充分利用 802.11az 非触发式测距的效率,请在先前RangingResult
测量中指定的最小和最大测量时间之间触发下一个测距请求。响应器和发起站用于 IEEE 802.11az NTB 结果的前导码中的长训练字段 (LTF) 重复次数
发起站用于 IEEE 802.11az NTB 结果的发送和接收空间时间流 (STS) 数量
支持 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+ |