Puedes utilizar la función de ubicación Wi-Fi que proporciona la API de Wi-Fi RTT (tiempo de ida y vuelta) para medir la distancia a los puntos de acceso Wi-Fi con capacidad RTT cercanos y a los dispositivos pares Wi-Fi Aware.
Si mides la distancia a tres o más puntos de acceso, puedes usar un algoritmo de multilateración para calcular la posición del dispositivo que mejor se adecue a esas medidas. Por lo general, la diferencia en la precisión es de 1 a 2 metros.
Gracias a esta precisión, puedes desarrollar servicios basados en la ubicación detallados, como la navegación interior, el control por voz sin ambigüedades (por ejemplo, "Enciende esta luz") e información basada en la ubicación (por ejemplo, "¿Hay ofertas especiales para este producto?").
El dispositivo solicitante no necesita conectarse a los puntos de acceso para medir la distancia con Wi-Fi RTT. Para mantener la privacidad, solo el dispositivo solicitante puede determinar la distancia al punto de acceso; los puntos de acceso no tienen esta información. Las operaciones de Wi-Fi RTT son ilimitadas para las apps en primer plano, pero son limitadas para las que se ejecutan en segundo plano.
El estándar IEEE 802.11-2016 especifica el Wi-Fi RTT y las capacidades relacionadas de medición de tiempo preciso (FTM). Wi-Fi RTT requiere la medición precisa del tiempo proporcionada por FTM, ya que calcula la distancia entre dos dispositivos midiendo el tiempo que tarda un paquete en ir y volver entre ellos, y multiplicando ese tiempo por la velocidad de la luz.
Android 15 (nivel de API 35) introdujo la compatibilidad con la medición de distancia sin activación (NTB) de IEEE 802.11az.
Diferencias de implementación basadas en la versión de Android
Wi-Fi RTT se introdujo en Android 9 (API nivel 28). Cuando usas este protocolo para determinar la posición de un dispositivo mediante la multilateración en dispositivos que ejecutan Android 9, debes tener acceso a datos de ubicaciones de puntos de acceso (PA) predeterminados en tu app. Tú decides cómo almacenar y recuperar estos datos.
En los dispositivos con Android 10 (API nivel 29) y versiones posteriores, los datos de ubicación de PA se pueden representar como objetos ResponderLocation, lo que incluye latitud, longitud y altitud. En el caso de los PA de Wi-Fi RTT que admiten datos Location Configuration Information/Location Civic Report (LCI/LCR), el protocolo mostrará un objeto ResponderLocation durante el proceso de creación de rangos.
Esta función permite a las apps consultar a los PA para solicitarles su posición de forma directa en lugar de tener que almacenar esa información de manera anticipada. De esta forma, tu app puede encontrar PA y determinar sus posiciones incluso si antes no se conocían esos PA, como cuando un usuario entra en un nuevo edificio.
La compatibilidad con la medición de distancia de NTB de IEEE 802.11az está disponible en dispositivos que ejecutan Android 15 (nivel de API 35) y versiones posteriores. Esto significa que, si el dispositivo admite el modo de iniciador de NTB de IEEE 802.11az (indicado por WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR), tu app puede encontrar APs compatibles con IEEE 802.11mc y IEEE 802.11az con una sola solicitud de rango. Se extendió la API de RangingResult para proporcionar información sobre el valor mínimo y máximo que se puede usar para el intervalo entre las mediciones de rango, lo que deja el intervalo exacto bajo el control de tu app.
Requisitos
- El hardware del dispositivo que realiza la solicitud de medición de distancia debe implementar el estándar FTM 802.11-2016 o el estándar 802.11az (medición de distancia no basada en activadores).
- El dispositivo que realiza esa solicitud debe ejecutar Android 9 (API nivel 28) o una versión posterior. La medición de distancia no basada en activadores de IEEE 802.11az está habilitada en dispositivos que ejecutan Android 15 (nivel de API 35) y versiones posteriores.
- El dispositivo que realiza la solicitud de rango debe tener habilitados los servicios de ubicación y la búsqueda de Wi-Fi (en Configuración > Ubicación).
- Si la app que realiza la solicitud de medición de distancia se orienta a Android 13 (nivel de API 33) o versiones posteriores, debe tener el permiso
NEARBY_WIFI_DEVICES. Si una app de este tipo se orienta a una versión anterior de Android, debe tener el permisoACCESS_FINE_LOCATIONen su lugar. - La app debe consultar el rango de puntos de acceso mientras está visible o en un servicio en primer plano. La app no puede acceder a información de ubicación en segundo plano.
- El punto de acceso debe implementar el estándar IEEE 802.11-2016 FTM o el estándar IEEE 802.11az (medición de distancia sin activación).
Configuración
A fin de configurar tu app para que utilice Wi-Fi RTT, sigue estos pasos.
1. Solicita permisos
Solicita los siguientes permisos en el manifiesto de tu app:
<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" />
Los permisos NEARBY_WIFI_DEVICES y ACCESS_FINE_LOCATION son peligrosos, por lo que debes solicitarlos en el entorno de ejecución cada vez que el usuario quiera realizar una operación de análisis de RTT. Tu app deberá solicitar el permiso del usuario si aún no se otorgó. Para obtener más información sobre los permisos de tiempo de ejecución, consulta Cómo solicitar permisos de la app.
2. Comprueba si el dispositivo es compatible con Wi-Fi RTT
Para verificar si el dispositivo admite Wi-Fi RTT, usa la API de PackageManager:
Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
3. Comprueba si hay Wi-Fi RTT disponible
Es posible que el RTT Wi-Fi exista en el dispositivo, pero que no esté disponible porque el usuario inhabilitó la conexión Wi-Fi. Según sus capacidades de hardware y firmware, es posible que algunos dispositivos no admitan Wi-Fi RTT si se usan SoftAP o la conexión mediante dispositivo móvil. Para verificar si la RTT Wi-Fi está disponible, llama a isAvailable().
La disponibilidad de Wi-Fi RTT puede cambiar en cualquier momento. Tu app debe registrar un objeto BroadcastReceiver para recibir un objeto ACTION_WIFI_RTT_STATE_CHANGED, que se envía cuando cambia la disponibilidad. Cuando tu app recibe el intent de transmisión, debe comprobar el estado actual de disponibilidad y ajustar su comportamiento en consecuencia.
Por ejemplo:
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);
Para obtener más información, consulta Transmisiones.
Cómo crear una solicitud de rango
Se crea una solicitud de medición de distancia (RangingRequest) especificando una lista de AP o pares de Wi-Fi Aware para los que se solicita una distancia. Se pueden especificar múltiples puntos de acceso o pares Wi-Fi Aware en una sola solicitud de rango; se miden y se muestran las distancias a todos los dispositivos.
Por ejemplo, una solicitud puede usar el método addAccessPoint() para especificar un punto de acceso al que se medirá la distancia:
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();
Un punto de acceso se identifica por su objeto ScanResult, que se puede obtener llamando a WifiManager.getScanResults().
Puedes usar
addAccessPoints(List<ScanResult>)
para agregar varios puntos de acceso en un lote.
Los objetos ScanResult pueden contener APs compatibles con IEEE 802.11mc (is80211mcResponder()) y con la medición de distancia no basada en activadores de IEEE 802.11az (is80211azNtbResponder()). Los dispositivos que admiten la medición de distancia de NTB de IEEE 802.11az realizan la medición de distancia de 802.11mc o 802.11az según la capacidad del AP, y se establece de forma predeterminada en 802.11az cuando el AP admite ambos. Los dispositivos que no admiten el estándar IEEE 802.11az realizan todas las mediciones de distancia con el protocolo IEEE 802.11mc.
Del mismo modo, una solicitud de medición de distancia puede agregar un par de Wi-Fi Aware con su dirección MAC o su PeerHandle, con los métodos addWifiAwarePeer(MacAddress peer) y addWifiAwarePeer(PeerHandle peer), respectivamente. Para obtener más información sobre cómo descubrir pares de Wi-Fi Aware, consulta la documentación de Wi-Fi Aware.
Cómo solicitar rangos
Una app emite una solicitud de medición de distancia con el método WifiRttManager.startRanging() y proporciona lo siguiente: un RangingRequest para especificar la operación, un Executor para especificar el contexto de devolución de llamada y un RangingResultCallback para recibir los resultados.
Por ejemplo:
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) { … } });
La operación de medición de distancia se realiza de forma asíncrona, y los resultados se devuelven en una de las devoluciones de llamada de RangingResultCallback:
- Si falla toda la operación de medición de distancia, se activa la devolución de llamada
onRangingFailurecon un código de estado que se describe enRangingResultCallback. Este tipo de falla puede producirse si el servicio no puede ejecutar una operación de rango en ese momento, por ejemplo, porque la conexión Wi-Fi está inhabilitada, porque la aplicación solicitó demasiadas operaciones de rango y está limitada, o por una cuestión de permisos. - Cuando se completa la operación de medición de distancia, se activa la devolución de llamada
onRangingResultscon una lista de resultados que coincide con la lista de solicitudes (un resultado para cada solicitud). El orden de los resultados no coincide necesariamente con el de las solicitudes. Ten en cuenta que la operación de rango puede completarse, pero cada resultado puede indicar una falla de esa medición específica.
Cómo interpretar los resultados de rango
Cada uno de los resultados que devuelve la devolución de llamada onRangingResults se especifica con un objeto RangingResult. En cada solicitud, haz lo siguiente.
1. Identifica la solicitud
Identifica la solicitud según la información proporcionada cuando se crea el
RangingRequest:
con mayor frecuencia, una dirección MAC proporcionada en el ScanResult que identifica un punto de
acceso. La dirección MAC se puede obtener del resultado de la medición de distancia con el método getMacAddress().
La lista de resultados de rango puede estar en un orden diferente al de los pares (puntos de acceso) especificados en la solicitud de rango, por lo que debes utilizar la dirección MAC para identificar el par, no el orden de los resultados.
2. Determina si se realizó correctamente cada medición
Para determinar si una medición se realizó correctamente, usa el método
getStatus(). Cualquier valor que no sea
STATUS_SUCCESS
indica una falla. Un error significa que todos los demás campos de este resultado
(excepto la identificación de la solicitud anterior) no son válidos y el método
get* correspondiente fallará con una excepción
IllegalStateException.
3. Obtén resultados para cada medición que se haya realizado correctamente
Para cada medición correcta (RangingResult), puedes recuperar los valores de los resultados con los métodos get correspondientes:
Distancia, en mm, y la desviación estándar de la medición:
RSSI de los paquetes utilizados para las mediciones:
Tiempo en milisegundos en el que se realizó la medición (indicando el tiempo desde el inicio):
Cantidad de mediciones que se intentaron y cantidad de mediciones que se realizaron correctamente (y en las que se basan las mediciones de distancia):
Tiempo mínimo y máximo que un dispositivo cliente debe esperar entre las mediciones de NTB de 11az:
getMinTimeBetweenNtbMeasurementsMicros()ygetMaxTimeBetweenNtbMeasurementsMicros()devuelven el tiempo mínimo y máximo. Si se solicita la siguiente medición de rango antes de que haya transcurrido el tiempo mínimo, la API devuelve el resultado de rango almacenado en caché. Si se solicita la siguiente medición de rango después de que transcurrió el tiempo máximo, la API finaliza la sesión de rango sin activador y negocia una nueva sesión de rango con la estación de respuesta. Debes evitar solicitar una nueva sesión de medición de distancia, ya que agrega sobrecarga al tiempo de medición de distancia. Para aprovechar al máximo la eficiencia de la medición de distancia sin activación de 802.11az, activa la siguiente solicitud de medición de distancia entre el tiempo de medición mínimo y máximo especificado en la medición deRangingResultanterior.Repeticiones del campo de entrenamiento largo (LTF) que las estaciones de respuesta y de iniciador usaron en el preámbulo para el resultado de NTB de IEEE 802.11az:
Cantidad de transmisiones espaciales de tiempo (STS) de transmisión y recepción que usó la estación iniciadora para el resultado de NTB de IEEE 802.11az:
Dispositivos Android que admiten WiFi RTT
En las siguientes tablas, se enumeran algunos teléfonos, puntos de acceso y dispositivos de centros de distribución, almacenamiento y venta minorista que admiten Wi-Fi RTT. Estos datos no son exhaustivos. Te recomendamos que te comuniques con nosotros para incluir aquí tus productos compatibles con RTT.
Puntos de acceso
| Fabricante y modelo | Fecha de asistencia | Protocolo |
|---|---|---|
| Nest Wifi Pro (Wi-Fi 6E) | Compatible | mc |
| Compulab WILD AP | Compatible | mc |
| Wi-Fi de Google | Compatible | mc |
| Router Wi-Fi de Google Nest | Compatible | mc |
| Punto de Wi-Fi de Google Nest | Compatible | mc |
| Aruba AP-635 | Compatible | mc |
| Cisco 9130 | Compatible | mc |
| Cisco 9136 | Compatible | mc |
| Cisco 9166 | Compatible | mc |
| Cisco 9164 | Compatible | mc |
| Cisco CW9172I | Compatible | mc/az |
| Cisco CW9172H | Compatible | mc/az |
| Cisco CW9176I | Compatible | mc/az |
| Cisco CW9178I | Compatible | mc/az |
| Aruba AP-505 | Compatible | mc |
| Aruba AP-515 | Compatible | mc |
| Aruba AP-575 | Compatible | mc |
| Aruba AP-518 | Compatible | mc |
| Aruba AP-505H | Compatible | mc |
| Aruba AP-565 | Compatible | mc |
| Aruba AP-535 | Compatible | mc |
| Aruba AP567 | Compatible | mc |
| Aruba AP577 | Compatible | mc |
| Aruba AP555 | Compatible | mc |
| Aruba AP635 | Compatible | mc |
| Aruba AP655 | Compatible | mc |
| Aruba AP615 | Compatible | mc |
| Aruba AP734 | Compatible | mc/az |
| Aruba AP735 | Compatible | mc/az |
| Aruba AP754 | Compatible | mc/az |
| Aruba AP755 | Compatible | mc/az |
Teléfonos
| Fabricante y modelo | Versión de 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 y versiones posteriores |
| Pixel 6 Pro | 9.0 y versiones posteriores |
| Pixel 5 | 9.0 y versiones posteriores |
| Pixel 5a | 9.0 y versiones posteriores |
| Pixel 5a 5G | 9.0 y versiones posteriores |
| Xiaomi Mi 10 Pro | 9.0 y versiones posteriores |
| Xiaomi Mi 10 | 9.0 y versiones posteriores |
| Xiaomi Redmi Mi 9T Pro | 9.0 y versiones posteriores |
| Xiaomi Mi 9T | 9.0 y versiones posteriores |
| Xiaomi Mi 9 | 9.0 y versiones posteriores |
| Xiaomi Mi Note 10 | 9.0 y versiones posteriores |
| Xiaomi Mi Note 10 Lite | 9.0 y versiones posteriores |
| Xiaomi Redmi Note 9S | 9.0 y versiones posteriores |
| Xiaomi Redmi Note 9 Pro | 9.0 y versiones posteriores |
| Xiaomi Redmi Note 8T | 9.0 y versiones posteriores |
| Xiaomi Redmi Note 8 | 9.0 y versiones posteriores |
| Xiaomi Redmi K30 Pro | 9.0 y versiones posteriores |
| Xiaomi Redmi K20 Pro | 9.0 y versiones posteriores |
| Xiaomi Redmi K20 | 9.0 y versiones posteriores |
| Xiaomi Redmi Note 5 Pro | 9.0 y versiones posteriores |
| Xiaomi Mi CC9 Pro | 9.0 y versiones posteriores |
| LG G8X ThinQ | 9.0 y versiones posteriores |
| LG V50S ThinQ | 9.0 y versiones posteriores |
| LG V60 ThinQ | 9.0 y versiones posteriores |
| LG V30 | 9.0 y versiones posteriores |
| Samsung Galaxy Note 10+ 5G | 9.0 y versiones posteriores |
| Samsung Galaxy S20+ 5G | 9.0 y versiones posteriores |
| Samsung Galaxy S20+ | 9.0 y versiones posteriores |
| Samsung Galaxy S20 5G | 9.0 y versiones posteriores |
| Samsung Galaxy S20 Ultra 5G | 9.0 y versiones posteriores |
| Samsung Galaxy S20 | 9.0 y versiones posteriores |
| Samsung Galaxy Note 10+ | 9.0 y versiones posteriores |
| Samsung Galaxy Note 10 5G | 9.0 y versiones posteriores |
| Samsung Galaxy Note 10 | 9.0 y versiones posteriores |
| Samsung A9 Pro | 9.0 y versiones posteriores |
| Google Pixel 4 XL | 9.0 y versiones posteriores |
| Google Pixel 4 | 9.0 y versiones posteriores |
| Google Pixel 4a | 9.0 y versiones posteriores |
| Google Pixel 3 XL | 9.0 y versiones posteriores |
| Google Pixel 3 | 9.0 y versiones posteriores |
| Google Pixel 3a XL | 9.0 y versiones posteriores |
| Google Pixel 3a | 9.0 y versiones posteriores |
| Google Pixel 2 XL | 9.0 y versiones posteriores |
| Google Pixel 2 | 9.0 y versiones posteriores |
| Google Pixel 1 XL | 9.0 y versiones posteriores |
| Google Pixel 1 | 9.0 y versiones posteriores |
| Poco X2 | 9.0 y versiones posteriores |
| Sharp Aquos R3 SH-04L | 9.0 y versiones posteriores |
Dispositivos de centros de distribución, almacenamiento y venta minorista
| Fabricante y modelo | Versión de Android |
|---|---|
| Zebra PS20 | 10.0 y versiones posteriores |
| Zebra TC52/TC52HC | 10.0 y versiones posteriores |
| Zebra TC57 | 10.0 y versiones posteriores |
| Zebra TC72 | 10.0 y versiones posteriores |
| Zebra TC77 | 10.0 y versiones posteriores |
| Zebra MC93 | 10.0 y versiones posteriores |
| Zebra TC8300 | 10.0 y versiones posteriores |
| Zebra VC8300 | 10.0 y versiones posteriores |
| Zebra EC30 | 10.0 y versiones posteriores |
| Zebra ET51 | 10.0 y versiones posteriores |
| Zebra ET56 | 10.0 y versiones posteriores |
| Zebra L10 | 10.0 y versiones posteriores |
| Zebra CC600/CC6000 | 10.0 y versiones posteriores |
| Zebra MC3300x | 10.0 y versiones posteriores |
| Zebra MC330x | 10.0 y versiones posteriores |
| Zebra TC52x | 10.0 y versiones posteriores |
| Zebra TC57x | 10.0 y versiones posteriores |
| Zebra EC50 (LAN y HC) | 10.0 y versiones posteriores |
| Zebra EC55 (WAN) | 10.0 y versiones posteriores |
| Zebra WT6300 | 10.0 y versiones posteriores |
| Skorpio X5 | 10.0 y versiones posteriores |