您可以利用 Wi-Fi RTT(往返时间)API 提供的 Wi-Fi 位置功能测量距附近支持 RTT 的 Wi-Fi 接入点和 Wi-Fi 感知对等设备的距离。
如果您测量与三个或更多接入点的距离,可以使用多点定位算法来预估与这些测量值最相符的设备位置。结果通常可以精确到 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(例如用户进入新建筑物时),您的应用也可以找到 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 测距。
- 测距请求发出设备必须启用位置信息服务并打开 WLAN 扫描(位于设置 > 位置信息下)。
- 如果发出测距请求的应用以 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,但由于用户已停用 WLAN,该功能可能无法使用。如果 SoftAP 或网络共享处于使用状态,某些设备可能不支持 Wi-Fi RTT,具体视设备的硬件和固件功能而定。如需检查 Wi-Fi RTT 是否可用,请调用 isAvailable()
。
Wi-Fi RTT 的可用性随时都可能发生变化。您的应用应注册 BroadcastReceiver
才能收到当可用性发生变化时发送的 ACTION_WIFI_RTT_STATE_CHANGED
。应用收到该广播 intent 后,应检查可用性的当前状态并相应地调整其行为。
例如:
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 感知对等设备的列表,即可创建测距请求 (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<ScanResult>)
批量添加多个接入点。
ScanResult
对象可以同时包含支持 IEEE 802.11mc (is80211mcResponder()
) 和 IEEE 802.11az 非触发器测距 (is80211azNtbResponder()
) 的 AP。支持 IEEE 802.11az NTB 测距的设备会执行 802.11mc 或 802.11az 测距,具体取决于 AP 的功能,如果 AP 同时支持这两种测距,则默认使用 802.11az。不支持 IEEE 802.11az 的设备使用 IEEE 802.11mc 协议执行所有测距操作。
同样,测距请求可以通过以下两种途径添加 Wi-Fi 感知对等设备:使用 addWifiAwarePeer(MacAddress peer)
方法利用相应设备的 MAC 地址,或者使用 addWifiAwarePeer(PeerHandle peer)
方法利用相应设备的 PeerHandle
。如需详细了解如何发现 Wi-Fi 感知对等设备,请参阅 Wi-Fi 感知文档。
请求测距
应用使用 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
中描述的状态代码。如果该服务当时出于某些原因(例如 WLAN 已停用、应用请求的测距操作过多并受到限制,或者存在权限问题)无法执行测距操作,可能会发生此类失败。 - 测距操作完成后,会触发
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) 的数量:
支持 Wi-Fi RTT 的 Android 设备
以下表格列出了支持 Wi-Fi 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 | 支持 |
Cisco 9136 | 支持 |
Cisco 9166 | 支持 |
Cisco 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 及更高版本 |
小米红米 NOTE 8 | 9.0 及更高版本 |
小米 Redmi K30 Pro | 9.0 及更高版本 |
小米 Redmi K20 Pro | 9.0 及更高版本 |
小米 Redmi K20 | 9.0 及更高版本 |
Xiaomi 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 及更高版本 |
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 及更高版本 |
三星 Galaxy Note 10+ | 9.0 及更高版本 |
三星 Galaxy Note 10 5G | 9.0 及更高版本 |
三星 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 及更高版本 |