Możesz użyć funkcji lokalizacji Wi-Fi udostępnianej przez interfejs API Wi-Fi RTT (Round-Trip-Time), aby zmierzyć odległość do pobliskich punktów dostępu Wi-Fi obsługujących RTT i urządzeń równorzędnych Wi-Fi Aware.
Jeśli zmierzysz odległość do co najmniej 3 punktów dostępu, możesz użyć algorytmu multilateracji, aby oszacować pozycję urządzenia, która najlepiej pasuje do tych pomiarów. Wynik jest zwykle dokładny z dokładnością do 1–2 metrów.
Dzięki tej dokładności możesz tworzyć precyzyjne usługi wykorzystujące lokalizację, takie jak nawigacja w pomieszczeniach, uściślone sterowanie głosowe (np. „Włącz to światło”) i informacje oparte na lokalizacji (np. „Czy są oferty specjalne na ten produkt?”).
Urządzenie wysyłające żądanie nie musi łączyć się z punktami dostępu, aby mierzyć odległość za pomocą Wi-Fi RTT. Aby zachować prywatność, tylko urządzenie wysyłające żądanie może określić odległość od punktu dostępu. Punkty dostępu nie mają tych informacji. Operacje Wi-Fi RTT są nieograniczone w przypadku aplikacji na pierwszym planie, ale są ograniczane w przypadku aplikacji działających w tle.
Wi-Fi RTT i powiązane funkcje Fine-Time-Measurement (FTM) są określone w standardzie IEEE 802.11-2016. Wi-Fi RTT wymaga precyzyjnego pomiaru czasu zapewnianego przez FTM, ponieważ oblicza odległość między 2 urządzeniami, mierząc czas, jaki zajmuje pakietowi przebycie drogi między urządzeniami, i mnożąc ten czas przez prędkość światła.
W Androidzie 15 (poziom API 35) wprowadzono obsługę pomiaru odległości bez wyzwalacza (NTB) IEEE 802.11az.
Różnice we wdrażaniu w zależności od wersji Androida
Funkcja Wi-Fi RTT została wprowadzona w Androidzie 9 (poziom API 28). Jeśli używasz tego protokołu do określania pozycji urządzenia za pomocą multilateracji z urządzeniami z Androidem 9, musisz mieć w aplikacji dostęp do wstępnie określonych danych o lokalizacji punktu dostępu (AP). To od Ciebie zależy, jak będziesz przechowywać i pobierać te dane.
Na urządzeniach z Androidem 10 (poziom interfejsu API 29) i nowszym dane o lokalizacji punktu dostępu mogą być reprezentowane jako obiekty ResponderLocation, które obejmują szerokość i długość geograficzną oraz wysokość. W przypadku punktów dostępu Wi-Fi RTT, które obsługują informacje o konfiguracji lokalizacji/raport o lokalizacji (dane LCI/LCR), protokół zwróci obiekt ResponderLocation podczas procesu określania odległości.
Ta funkcja umożliwia aplikacjom wysyłanie zapytań do punktów dostępu, aby bezpośrednio pytać o ich pozycję, zamiast przechowywać te informacje z wyprzedzeniem. Dzięki temu aplikacja może znajdować punkty dostępu i określać ich pozycje, nawet jeśli nie były wcześniej znane, np. gdy użytkownik wchodzi do nowego budynku.
Obsługa pomiaru odległości IEEE 802.11az NTB jest dostępna na urządzeniach z Androidem 15 (poziom API 35) i nowszym. Oznacza to, że jeśli urządzenie obsługuje tryb inicjatora IEEE 802.11az NTB (wskazywany przez WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR), aplikacja może znaleźć punkty dostępu obsługujące zarówno standard IEEE 802.11mc, jak i IEEE 802.11az, za pomocą jednego żądania zakresu. Interfejs API RangingResult został rozszerzony, aby dostarczać informacje o minimalnej i maksymalnej wartości, którą można wykorzystać jako odstęp między pomiarami odległości. Dokładny odstęp jest kontrolowany przez aplikację.
Wymagania
- Sprzęt urządzenia wysyłającego żądanie pomiaru odległości musi obsługiwać standard FTM 802.11-2016 lub 802.11az (pomiar odległości bez wyzwalacza).
- Urządzenie, które wysyła żądanie pomiaru odległości, musi mieć Androida 9 (poziom interfejsu API 28) lub nowszego. Pomiar odległości bez wyzwalania IEEE 802.11az jest włączony na urządzeniach z Androidem 15 (poziom API 35) lub nowszym.
- Urządzenie, które wysyła żądanie pomiaru odległości, musi mieć włączone usługi wykorzystujące lokalizację i skanowanie Wi-Fi (w sekcji Ustawienia > Lokalizacja).
- Jeśli aplikacja, która wysyła żądanie określenia odległości, jest kierowana na Androida 13 (API na poziomie 33) lub nowszego, musi mieć uprawnienie
NEARBY_WIFI_DEVICES. Jeśli taka aplikacja jest kierowana na starszą wersję Androida, musi mieć uprawnienieACCESS_FINE_LOCATION. - Aplikacja musi wysyłać zapytania o zakres punktów dostępu, gdy jest widoczna lub działa jako usługa na pierwszym planie. Aplikacja nie może uzyskiwać dostępu do informacji o lokalizacji w tle.
- Punkt dostępu musi implementować standard IEEE 802.11-2016 FTM lub IEEE 802.11az (pomiar odległości bez wyzwalania).
Konfiguracja
Aby skonfigurować aplikację do korzystania z Wi-Fi RTT, wykonaj te czynności.
1. Wyślij prośbę o uprawnienia
Poproś o te uprawnienia w pliku manifestu aplikacji:
<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" />
Uprawnienia NEARBY_WIFI_DEVICES i ACCESS_FINE_LOCATION są niebezpieczne, więc musisz prosić o nie w czasie działania za każdym razem, gdy użytkownik chce wykonać operację skanowania RTT. Jeśli uprawnienie nie zostało jeszcze przyznane, aplikacja będzie musiała poprosić użytkownika o zgodę. Więcej informacji o uprawnieniach w czasie działania aplikacji znajdziesz w artykule Prośba o uprawnienia aplikacji.
2. Sprawdzanie, czy urządzenie obsługuje Wi-Fi RTT
Aby sprawdzić, czy urządzenie obsługuje Wi-Fi RTT, użyj interfejsu API PackageManager:
Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
3. Sprawdzanie, czy funkcja Wi-Fi RTT jest dostępna
Funkcja Wi-Fi RTT może być dostępna na urządzeniu, ale może nie być dostępna, ponieważ użytkownik wyłączył Wi-Fi. W zależności od możliwości sprzętu i oprogramowania układowego niektóre urządzenia mogą nie obsługiwać Wi-Fi RTT, jeśli używany jest SoftAP lub tethering. Aby sprawdzić, czy funkcja Wi-Fi RTT jest dostępna, wywołaj funkcję isAvailable().
Dostępność Wi-Fi RTT może się zmienić w każdej chwili. Aplikacja powinna zarejestrować BroadcastReceiver, aby otrzymywać ACTION_WIFI_RTT_STATE_CHANGED, który jest wysyłany, gdy zmienia się dostępność. Gdy aplikacja otrzyma intencję rozgłoszeniową, powinna sprawdzić bieżący stan dostępności i odpowiednio dostosować swoje działanie.
Przykład:
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);
Więcej informacji znajdziesz w sekcji Transmisje.
Tworzenie żądania określenia zakresu
Żądanie określenia odległości (RangingRequest) jest tworzone przez określenie listy punktów dostępu lub urządzeń równorzędnych Wi-Fi Aware, do których jest wysyłane żądanie określenia odległości. W jednym żądaniu pomiaru odległości można określić wiele punktów dostępu lub urządzeń równorzędnych Wi-Fi Aware. Odległości do wszystkich urządzeń są mierzone i zwracane.
Na przykład żądanie może używać metody addAccessPoint(), aby określić punkt dostępu, do którego ma zostać zmierzona odległość:
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();
Punkt dostępu jest identyfikowany przez obiekt ScanResult, który można uzyskać, wywołując funkcję WifiManager.getScanResults().
Możesz użyć addAccessPoints(List<ScanResult>), aby dodać wiele punktów dostępu jednocześnie.
Obiekty ScanResult mogą zawierać punkty dostępu obsługujące zarówno standard IEEE 802.11mc (is80211mcResponder()), jak i IEEE 802.11az (is80211azNtbResponder()). Urządzenia obsługujące pomiar odległości IEEE 802.11az NTB wykonują pomiar odległości 802.11mc lub 802.11az w zależności od możliwości punktu dostępu, domyślnie wybierając 802.11az, gdy punkt dostępu obsługuje oba standardy. Urządzenia, które nie obsługują standardu IEEE 802.11az, wykonują wszystkie pomiary odległości przy użyciu protokołu IEEE 802.11mc.
Podobnie żądanie pomiaru odległości może dodać urządzenie równorzędne Wi-Fi Aware, używając jego adresu MAC lub PeerHandle, odpowiednio za pomocą metod addWifiAwarePeer(MacAddress peer) i addWifiAwarePeer(PeerHandle peer). Więcej informacji o wykrywaniu urządzeń równorzędnych Wi-Fi Aware znajdziesz w dokumentacji Wi-Fi Aware.
Żądanie określenia odległości
Aplikacja wysyła żądanie pomiaru odległości za pomocą metody WifiRttManager.startRanging() i podaje: RangingRequest, aby określić operację, Executor, aby określić kontekst wywołania zwrotnego, oraz RangingResultCallback, aby otrzymać wyniki.
Przykład:
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) { … } });
Operacja pomiaru odległości jest wykonywana asynchronicznie, a wyniki są zwracane w jednym z wywołań zwrotnych RangingResultCallback:
- Jeśli cała operacja pomiaru odległości się nie powiedzie, wywoływane jest wywołanie zwrotne
onRangingFailurez kodem stanu opisanym wRangingResultCallback. Taki błąd może wystąpić, jeśli usługa nie może w danym momencie wykonać operacji określania odległości – na przykład dlatego, że Wi-Fi jest wyłączone, aplikacja zażądała zbyt wielu operacji określania odległości i jest ograniczona lub z powodu problemu z uprawnieniami. - Po zakończeniu operacji pomiaru odległości wywoływane jest wywołanie zwrotne
onRangingResultsz listą wyników odpowiadającą liście żądań – po jednym wyniku dla każdego żądania. Kolejność wyników nie musi odpowiadać kolejności żądań. Pamiętaj, że operacja określania odległości może zostać zakończona, ale każdy wynik może nadal wskazywać na niepowodzenie tego konkretnego pomiaru.
Interpretowanie wyników pomiaru odległości
Każdy z wyników zwracanych przez wywołanie zwrotne onRangingResults jest określany przez obiekt RangingResult. W przypadku każdego żądania wykonaj te czynności:
1. Identyfikowanie żądania
Zidentyfikuj żądanie na podstawie informacji podanych podczas tworzenia RangingRequest: najczęściej jest to adres MAC podany w ScanResult, który identyfikuje punkt dostępu. Adres MAC można uzyskać z wyniku pomiaru odległości za pomocą metody getMacAddress().
Lista wyników pomiaru odległości może być w innej kolejności niż urządzenia równorzędne (punkty dostępu) określone w żądaniu pomiaru odległości, dlatego do identyfikacji urządzenia równorzędnego należy używać adresu MAC, a nie kolejności wyników.
2. Sprawdzanie, czy pomiary zakończyły się powodzeniem
Aby sprawdzić, czy pomiar się powiódł, użyj metody getStatus(). Każda wartość inna niż STATUS_SUCCESS oznacza niepowodzenie. Niepowodzenie oznacza, że wszystkie pozostałe pola tego wyniku (z wyjątkiem identyfikatora żądania powyżej) są nieprawidłowe, a odpowiednia metoda get* zakończy się niepowodzeniem z wyjątkiem IllegalStateException.
3. Uzyskiwanie wyników każdego udanego pomiaru
W przypadku każdego udanego pomiaru (RangingResult) możesz pobrać wartości wyników za pomocą odpowiednich metod get:
Odległość w milimetrach i odchylenie standardowe pomiaru:
RSSI pakietów użytych do pomiarów:
Czas w milisekundach, w którym dokonano pomiaru (wskazujący czas od uruchomienia):
Liczba prób pomiaru i liczba udanych pomiarów (na których opierają się pomiary odległości):
Minimalny i maksymalny czas, przez jaki urządzenie klienta musi czekać między pomiarami 11az NTB:
getMinTimeBetweenNtbMeasurementsMicros()igetMaxTimeBetweenNtbMeasurementsMicros()zwracają minimalny i maksymalny czas. Jeśli następny pomiar odległości zostanie zażądany przed upływem minimalnego czasu, interfejs API zwróci wynik pomiaru odległości z pamięci podręcznej. Jeśli następny pomiar odległości zostanie zażądany po upływie maksymalnego czasu, interfejs API zakończy sesję pomiaru odległości bez wyzwalacza i wynegocjuje nową sesję ze stacją odpowiadającą. Unikaj żądania nowej sesji pomiaru odległości, ponieważ wydłuża to czas pomiaru. Aby w pełni wykorzystać wydajność pomiaru odległości bez wyzwalacza w standardzie 802.11az, wyzwól następne żądanie pomiaru odległości między minimalnym a maksymalnym czasem pomiaru określonym w poprzednim pomiarzeRangingResult.Powtórzenia długiego pola treningowego (LTF), których stacje odpowiadające i inicjujące użyły we wprowadzeniu do wyniku IEEE 802.11az NTB:
Liczba strumieni czasowo-przestrzennych (STS) transmisji i odbioru, których stacja inicjująca użyła do uzyskania wyniku IEEE 802.11az NTB:
urządzenia z Androidem obsługujące Wi-Fi RTT,
W poniższych tabelach znajdziesz listę telefonów, punktów dostępu oraz urządzeń używanych w sklepach, magazynach i centrach dystrybucyjnych, które obsługują Wi-Fi RTT. Te przykłady nie są wyczerpujące. Zachęcamy do skontaktowania się z nami, aby umieścić tutaj swoje produkty obsługujące RTT.
Punkty dostępu
| Producent i model | Data pomocy | Protokół |
|---|---|---|
| Nest Wifi Pro (Wi-Fi 6E) | Obsługiwane | mc |
| Compulab WILD AP | Obsługiwane | mc |
| Google Wi-Fi | Obsługiwane | mc |
| Router Google Nest Wi-Fi | Obsługiwane | mc |
| Punkt Google Nest Wi-Fi | Obsługiwane | mc |
| Aruba AP-635 | Obsługiwane | mc |
| Cisco 9130 | Obsługiwane | mc |
| Cisco 9136 | Obsługiwane | mc |
| Cisco 9166 | Obsługiwane | mc |
| Cisco 9164 | Obsługiwane | mc |
| Cisco CW9172I | Obsługiwane | mc/az |
| Cisco CW9172H | Obsługiwane | mc/az |
| Cisco CW9176I | Obsługiwane | mc/az |
| Cisco CW9178I | Obsługiwane | mc/az |
| Aruba AP-505 | Obsługiwane | mc |
| Aruba AP-515 | Obsługiwane | mc |
| Aruba AP-575 | Obsługiwane | mc |
| Aruba AP-518 | Obsługiwane | mc |
| Aruba AP-505H | Obsługiwane | mc |
| Aruba AP-565 | Obsługiwane | mc |
| Aruba AP-535 | Obsługiwane | mc |
| Aruba AP567 | Obsługiwane | mc |
| Aruba AP577 | Obsługiwane | mc |
| Aruba AP555 | Obsługiwane | mc |
| Aruba AP635 | Obsługiwane | mc |
| Aruba AP655 | Obsługiwane | mc |
| Aruba AP615 | Obsługiwane | mc |
| Aruba AP734 | Obsługiwane | mc/az |
| Aruba AP735 | Obsługiwane | mc/az |
| Aruba AP754 | Obsługiwane | mc/az |
| Aruba AP755 | Obsługiwane | mc/az |
Telefony
| Producent i model | Wersja Androida |
|---|---|
| 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+ |
Urządzenia w handlu detalicznym, magazynach i centrach dystrybucyjnych
| Producent i model | Wersja Androida |
|---|---|
| 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 i HC) | 10.0+ |
| Zebra EC55 (WAN) | 10.0+ |
| Zebra WT6300 | 10.0+ |
| Skorpio X5 | 10.0+ |