Вы можете использовать функцию определения местоположения по Wi-Fi, предоставляемую Wi-Fi RTT (Round-Trip-Time) API, чтобы измерять расстояние до ближайших точек доступа Wi-Fi с поддержкой RTT и одноранговых устройств Wi-Fi Aware.
Если вы измерите расстояние до трех или более точек доступа, то сможете использовать алгоритм мультилатерации, чтобы определить положение устройства, которое лучше всего соответствует этим измерениям. Обычно погрешность составляет 1–2 метра.
Такая точность позволяет разрабатывать сервисы, использующие геолокацию, например навигацию внутри помещений, голосовое управление (например, "Включи этот свет") и информацию о местоположении (например, "Есть ли специальные предложения для этого товара?").
Для измерения расстояния с помощью Wi-Fi RTT запрашивающему устройству не нужно подключаться к точкам доступа. В целях конфиденциальности расстояние до точки доступа может определить только запрашивающее устройство. У точек доступа нет такой информации. Для активных приложений операции Wi-Fi RTT не ограничены, а для фоновых – ограничены.
Wi-Fi RTT и связанные с ним возможности Fine-Time-Measurement (FTM) определяются стандартом IEEE 802.11-2016. Для Wi-Fi RTT требуется точное измерение времени, обеспечиваемое FTM, поскольку расстояние между двумя устройствами рассчитывается путем измерения времени, необходимого пакету для прохождения туда и обратно между устройствами, и умножения этого времени на скорость света.
В Android 15 (уровень API 35) добавлена поддержка измерения расстояния по стандарту IEEE 802.11az без триггеров.
Различия в реализации в зависимости от версии Android
Технология Wi-Fi RTT была представлена в Android 9 (уровень API 28). Чтобы определить местоположение устройства с Android 9 с помощью мультилатерации, в приложении должен быть доступ к данным о местоположении точек доступа. Вы можете сами выбрать, как хранить и получать эти данные.
На устройствах с Android 10 (уровень API 29) и более поздних версий данные о местоположении ТД могут быть представлены в виде объектов ResponderLocation, которые включают широту, долготу и высоту. Для точек доступа Wi-Fi RTT, поддерживающих LCI/LCR, протокол возвращает объект ResponderLocation во время определения расстояния.
Эта функция позволяет приложениям запрашивать у точек доступа информацию об их местоположении напрямую, а не хранить ее заранее. Таким образом, ваше приложение может находить точки доступа и определять их местоположение, даже если они не были известны ранее, например когда пользователь входит в новое здание.
Поддержка определения расстояния по стандарту IEEE 802.11az NTB доступна на устройствах с Android 15 (уровень API 35) и более поздними версиями. Это означает, что если устройство поддерживает режим инициатора NTB IEEE 802.11az (обозначается как WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR), то ваше приложение может найти точки доступа, поддерживающие как IEEE 802.11mc, так и IEEE 802.11az, с помощью одного запроса диапазона. API RangingResult теперь предоставляет информацию о минимальном и максимальном значении, которое можно использовать для интервала между измерениями дальности, оставляя точный интервал под контролем вашего приложения.
Требования
- Аппаратное обеспечение устройства, отправляющего запрос на измерение расстояния, должно поддерживать стандарт 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_DEVICES и ACCESS_FINE_LOCATION относятся к категории опасных, поэтому их нужно запрашивать каждый раз, когда пользователь хочет выполнить сканирование RTT. Если разрешение не было предоставлено ранее, приложение должно запросить его у пользователя. Подробнее о динамических разрешениях…
2. Проверьте, поддерживает ли устройство Wi-Fi RTT
Чтобы проверить, поддерживает ли устройство Wi-Fi RTT, используйте API PackageManager:
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. В зависимости от аппаратного и встроенного ПО некоторые устройства могут не поддерживать Wi-Fi RTT, если используется SoftAP или режим модема. Чтобы проверить, доступна ли функция 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) создается путем указания списка точек доступа или одноранговых узлов 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()). Устройства, поддерживающие измерение расстояния по стандарту IEEE 802.11az NTB, выполняют измерение по стандарту 802.11mc или 802.11az в зависимости от возможностей ТД. Если она поддерживает оба стандарта, по умолчанию используется 802.11az. Устройства, которые не поддерживают IEEE 802.11az, выполняют все измерения расстояния с помощью протокола IEEE 802.11mc.
Аналогично, запрос на определение расстояния может добавить одноранговый узел Wi-Fi Aware, используя его MAC-адрес или PeerHandle, с помощью методов addWifiAwarePeer(MacAddress peer) и addWifiAwarePeer(PeerHandle peer) соответственно. Подробнее об обнаружении одноранговых узлов 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. Чаще всего это MAC-адрес, указанный в ScanResult, который идентифицирует точку доступа. MAC-адрес можно получить из результата измерения расстояния с помощью метода getMacAddress().
Список результатов может быть в другом порядке, чем одноранговые узлы (точки доступа), указанные в запросе на определение расстояния, поэтому для идентификации однорангового узла следует использовать MAC-адрес, а не порядок результатов.
2. Определите, было ли каждое измерение успешным
Чтобы определить, было ли измерение успешным, используйте метод getStatus(). Любое другое значение, кроме STATUS_SUCCESS, указывает на ошибку. Если произойдет сбой, все остальные поля этого результата (кроме идентификатора запроса выше) будут недействительны, а соответствующий метод get* завершится с исключением IllegalStateException.
3. Получайте результаты каждого успешного измерения.
Для каждого успешного измерения (RangingResult) вы можете получить значения результатов с помощью соответствующих методов get:
Расстояние в миллиметрах и стандартное отклонение измерения:
RSSI пакетов, используемых для измерений:
Время в миллисекундах, когда было выполнено измерение (указывает время с момента загрузки):
Количество попыток измерения и количество успешных измерений (на которых основаны измерения расстояния):
Минимальное и максимальное время, которое клиентское устройство должно ждать между измерениями 11az NTB:
getMinTimeBetweenNtbMeasurementsMicros()иgetMaxTimeBetweenNtbMeasurementsMicros()возвращают минимальное и максимальное время. Если следующее измерение расстояния запрашивается до истечения минимального времени, API возвращает кэшированный результат измерения расстояния. Если следующий запрос на измерение расстояния поступит после истечения максимального времени, API завершит сеанс измерения расстояния без триггера и согласует новый сеанс с отвечающей станцией. Не запрашивайте новый сеанс определения расстояния, поскольку это увеличивает время измерения. Чтобы в полной мере использовать преимущества эффективности определения расстояния без триггеров по стандарту 802.11az, активируйте следующий запрос на определение расстояния в период между минимальным и максимальным временем измерения, указанным в предыдущем измеренииRangingResult.Повторения длинного поля обучения (LTF), которые станции инициатора и ответчика использовали в преамбуле для результата IEEE 802.11az NTB:
Количество пространственно-временных потоков (STS) передачи и приема, которые инициирующая станция использовала для результата IEEE 802.11az NTB:
Устройства Android с поддержкой Wi-Fi RTT
В таблицах ниже перечислены некоторые телефоны, точки доступа и устройства для розничной торговли, складов и распределительных центров, которые поддерживают Wi-Fi RTT. Это далеко не полный список. Если вы хотите, чтобы ваши продукты с поддержкой RTT были указаны здесь, свяжитесь с нами.
Точки доступа
| Производитель и модель | Дата поддержки | Протокол |
|---|---|---|
| Nest Wifi Pro (Wi-Fi 6E) | Поддерживается | mc |
| Compulab WILD AP | Поддерживается | mc |
| Google Wi-Fi | Поддерживается | mc |
| Маршрутизатор Google Nest Wi-Fi | Поддерживается | mc |
| Точка Wi-Fi Google Nest | Поддерживается | 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 и более поздних версий |
| Xiaomi Mi 10 Pro | 9.0 и более поздних версий |
| Xiaomi Mi 10 | 9.0 и более поздних версий |
| Xiaomi Redmi Mi 9T Pro | 9.0 и более поздних версий |
| Xiaomi Mi 9T | 9.0 и более поздних версий |
| Xiaomi Mi 9 | 9.0 и более поздних версий |
| Xiaomi Mi Note 10 | 9.0 и более поздних версий |
| Xiaomi Mi Note 10 Lite | 9.0 и более поздних версий |
| Xiaomi Redmi Note 9S | 9.0 и более поздних версий |
| Xiaomi Redmi Note 9 Pro | 9.0 и более поздних версий |
| Xiaomi Redmi Note 8T | 9.0 и более поздних версий |
| Xiaomi Redmi Note 8 | 9.0 и более поздних версий |
| Xiaomi Redmi K30 Pro | 9.0 и более поздних версий |
| Xiaomi Redmi K20 Pro | 9.0 и более поздних версий |
| Xiaomi Redmi K20 | 9.0 и более поздних версий |
| Xiaomi Redmi Note 5 Pro | 9.0 и более поздних версий |
| Xiaomi Mi CC9 Pro | 9.0 и более поздних версий |
| LG G8X ThinQ | 9.0 и более поздних версий |
| LG V50S ThinQ | 9.0 и более поздних версий |
| LG V60 ThinQ | 9.0 и более поздних версий |
| LG V30 | 9.0 и более поздних версий |
| Samsung 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 и более поздних версий |
| Samsung Galaxy Note 10+ | 9.0 и более поздних версий |
| Samsung Galaxy Note 10 5G | 9.0 и более поздних версий |
| Samsung 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 и более поздних версий |