Android 16 引入了 Ranging 模块,该模块提供了统一且标准化的接口,用于在设备之间进行精确测距。您可以使用此 API Surface 来测量对等设备的距离和位置,而无需单独处理每种测距技术。
测距模块支持以下技术:
- 超宽带
- 蓝牙声道响铃
- Wi-Fi NAN RTT
- 蓝牙 RSSI 测距
测距功能和可用性
RangingManager
类可向应用提供有关本地设备支持的测距技术的信息,以及每项技术的可用性和功能。应用可以注册 Callback
,以便在任何受支持技术的可用性或功能发生任何变化时收到更新。
设备角色
参与测距会话的设备必须是发起方或响应方。发起器设备与一台或多台响应器设备启动测距会话。响应器设备一次只能响应来自一个发起器的测距请求。您可以使用 RangingPreference
类为测距会话中的给定设备指定角色。
范围会话类型
在设备之间启动测距会话时,通常需要建立带外 (OOB) 数据传输来交换会话参数。
测距模块可以为您处理 OOB 协商,但也支持自定义 OOB 实现。

默认 OOB 实现
在此会话类型 (RANGING_SESSION_OOB
) 中,测距模块会处理 OOB 协商以启动测距会话。它会根据应用提供的测距偏好设置选择合适的参数,并根据两部设备支持的技术使用适当的技术。此会话类型使用标准化的 OOB specification
。
测距模块仅定义了用于与对等设备交互的 OOB 数据格式和序列。它不处理对等设备发现或连接建立。
自定义 OOB 实现
在此会话类型 (RANGING_SESSION_RAW
) 中,应用会绕过 Ranging 模块的 OOB 流程,并处理自己的 OOB 协商和参数。这意味着,应用必须确定对等设备支持哪些技术、协商测距参数,以及开始测距会话。
测距偏好设置
使用 RangingPreference
对象指定测距会话的所需参数。您可以执行以下操作:
- 设备角色。这表示设备是发起方还是响应方。
- 测距配置。
RangingConfig
对象用于指定测距会话类型以及启动测距会话所需的其他参数。 - 会话配置。
SessionConfig
对象用于指定要对测距会话强制执行的参数,例如测量限制、传感器融合、地理围栏配置等。
测距权限
测距模块需要新的统一权限 (android.permission.RANGING
) 才能访问当前和未来的所有测距技术。此权限位于 NEARBY_DEVICES_PERMISSIONS
列表中。
<uses-permission android:name="android.permission.RANGING" />
限制和局限
测距模块可能会出于多种原因限制测距,其中包括:
- 第三方应用只能在受支持的设备上使用超宽带执行后台测距。不允许使用其他技术在后台进行测距。
- 当设备的并发测距会话数量达到上限时,系统不允许进行测距。
- 由于电池、性能或内存等系统运行状况问题,测距功能可能会受到限制。
测距模块还存在以下已知限制:
- 测距模块仅支持将测距数据传送到超宽带对等设备。对于其他技术,测距模块仅会将测距数据传递给发起端设备。
- 测距模块仅支持在原始测距模式下动态添加设备,且仅适用于超宽带。
- 测距模块不支持针对默认 OOB 实现的一对多超宽带会话。如果您传入多个设备句柄,该模块会为每台支持超宽带的对等设备创建一对一会话。
进行测距会话
如需使用 Ranging 模块进行测距会话,请按以下步骤操作:
- 验证所有设备均搭载 Android 16 或更高版本。
- 在应用清单中请求
android.permission.RANGING
权限。 - 评估测距技术的功能和可用性。
- 发现用于测距操作的对等设备。
- 使用测距会话类型中所述的任一会话类型,为带外频道交换建立连接。
- 发起测距并持续获取测距数据。
- 终止测距会话。
以下代码示例演示了发起者角色和响应方角色的这些步骤。
Kotlin
class RangingApp {
// Starts a ranging session on the initiator side.
fun startRangingInitiator(
context: Context,
deviceHandle: DeviceHandle,
executor: Executor,
callback: RangingSessionCallback
) {
// Get the RangingManager which is the entry point for ranging module.
val manager = context.getSystemService(RangingManager::class.java)
// Create a new RangingSession using the provided executor and callback.
val session = manager.createRangingSession(executor, callback)
// Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
// the initiator role.
val config = OobInitiatorRangingConfig.Builder()
.setFastestRangingInterval(Duration.ofMillis(100))
.setSlowestRangingInterval(Duration.ofMillis(5000))
.setRangingMode(RANGING_MODE_AUTO)
.setSecurityLevel(SECURITY_LEVEL_BASIC)
.addDeviceHandle(deviceHandle)
.build()
// Create a RangingPreference, which specifies the role (initiator) and
// configuration for the ranging session.
val preference =
RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build()
// Start ranging session.
session.start(preference)
// If successful, the ranging data will be sent through callback#onResults
// Stop ranging session
session.stop()
}
// Starts a ranging session on the responder side.
fun startRangingResponder(
context: Context,
deviceHandle: DeviceHandle,
executor: Executor,
callback: RangingSessionCallback
) {
// Get the RangingManager which is the entry point for ranging module.
val manager = context.getSystemService(RangingManager::class.java)
// Create a new RangingSession using the provided executor and callback.
val session = manager.createRangingSession(executor, callback)
// Create an OobResponderRangingConfig, which specifies the ranging parameters for
// the responder role.
val config = OobResponderRangingConfig.Builder(deviceHandle).build()
// Create a RangingPreference, which specifies the role (responder) and
// configuration for the ranging session.
val preference =
RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build()
// Start the ranging session.
session.start(preference)
// Stop the ranging session
session.stop()
}
}
Java
public class RangingApp {
// Starts a ranging session on the initiator side.
void startRangingInitiator(Context context, DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {
// Get the RangingManager which is the entry point for ranging module.
RangingManager manager = context.getSystemService(RangingManager.class);
// Create a new RangingSession using the provided executor and callback.
RangingSession session = manager.createRangingSession(executor, callback);
// Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
// the initiator role.
OobInitiatorRangingConfig config = new OobInitiatorRangingConfig.Builder()
.setFastestRangingInterval(Duration.ofMillis(100))
.setSlowestRangingInterval(Duration.ofMillis(5000))
.setRangingMode(RANGING_MODE_AUTO)
.setSecurityLevel(SECURITY_LEVEL_BASIC)
.addDeviceHandle(deviceHandle)
.build();
// Create a RangingPreference, which specifies the role (initiator) and
// configuration for the ranging session.
RangingPreference preference =
new RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build();
// Start ranging session.
session.start(preference);
// If successful, the ranging data will be sent through callback#onResults
// Stop ranging session
session.stop();
}
// Starts a ranging session on the responder side.
void startRangingResponder(Context context, DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {
// Get the RangingManager which is the entry point for ranging module.
RangingManager manager = context.getSystemService(RangingManager.class);
// Create a new RangingSession using the provided executor and callback.
RangingSession session = manager.createRangingSession(executor, callback);
// Create an OobResponderRangingConfig, which specifies the ranging parameters for
// the responder role.
OobResponderRangingConfig config = new OobResponderRangingConfig.Builder( deviceHandle).build();
// Create a RangingPreference, which specifies the role (responder) and
// configuration for the ranging session.
RangingPreference preference =
new RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build();
// Start the ranging session.
session.start(preference);
// Stop the ranging session
session.stop();
}
}
示例应用
如需查看有关如何使用 Ranging 模块的端到端示例,请参阅 AOSP 中的示例应用。此示例应用涵盖 Ranging 模块支持的所有测距技术,并包含适用于这两种支持的会话类型的流程。