Możesz użyć funkcji lokalizacji Wi-Fi dostępnej w interfejsie API Wi-Fi RTT (Round-Trip-Time), aby zmierzyć odległość od pobliskich punktów dostępu Wi-Fi obsługujących RTT i urządzeń równorzędnych Wi-Fi Aware.
Jeśli mierzysz odległość do co najmniej 3 punktów dostępu, możesz użyć algorytmu mnożnika, aby oszacować położenie urządzenia, które najlepiej pasuje do tych pomiarów. Wynik jest zwykle dokładny w zakresie 1–2 metrów.
Dzięki takiej dokładności możesz tworzyć bardziej szczegółowe usługi związane z lokalizacją, takie jak nawigacja wewnątrz budynków, jednoznaczne sterowanie głosowe (np. „Włącz to światło”) i informacje związane z lokalizacją (np. „Czy są dostępne oferty specjalne dotyczące tego produktu?”).
Urządzenie wysyłające żądanie nie musi łączyć się z punktami dostępu, aby mierzyć odległość za pomocą RTT Wi-Fi. Ze względu na ochronę prywatności tylko urządzenie wysyłające żądanie może określić odległość do punktu dostępu. Punkty dostępu nie mają tych informacji. Operacje Wi-Fi RTT są nieograniczone w przypadku aplikacji działających na pierwszym planie, ale są ograniczane w przypadku aplikacji działających w tle.
RTT Wi-Fi oraz powiązane funkcje dokładnego pomiaru czasu (FTM) są określone w standardzie IEEE 802.11-2016. RTT Wi-Fi wymaga dokładnego pomiaru czasu zapewnianego przez FTM, ponieważ oblicza odległość między dwoma urządzeniami, mierząc czas, jaki pakiet zajmuje pokonanie jednego urządzenia w obie strony, i mnożąc ten czas przez prędkość światła.
Różnice we wdrożeniu w zależności od wersji Androida
Protokół Wi-Fi RTT został wprowadzony w Androidzie 9 (poziom interfejsu API 28). Aby w przypadku urządzeń z Androidem 9 używać tego protokołu do ustalania pozycji urządzenia za pomocą wielopóźności, musisz mieć dostęp do danych o ustalonych lokalizacjach punktów dostępu w aplikacji. To Ty decydujesz, jak te dane mają być przechowywane i pobierane.
Na urządzeniach z Androidem 10 (poziom interfejsu API 29) lub nowszym dane o lokalizacji punktu dostępu mogą być przedstawione jako obiekty ResponderLocation
, które obejmują szerokość, długość geograficzną i wysokość. W przypadku punktów dostępu RTT Wi-Fi, które obsługują informacje o konfiguracji lokalizacji lub raport o lokalizacji (Location Civic Report (dane LCI/LCR)), protokół zwraca obiekt ResponderLocation
podczas procesu określania zakresu.
Ta funkcja pozwala aplikacjom wysyłać zapytania do punktów dostępu i w razie potrzeby bezpośrednio pytać ich o podanie pozycji, zamiast przechowywać je z wyprzedzeniem. Aplikacja może więc znajdować punkty dostępu i określać ich pozycje, nawet jeśli te punkty nie były wcześniej znane, na przykład gdy użytkownik wchodzi do nowego budynku.
Wymagania
- Sprzęt urządzenia wysyłającego żądanie określania zakresu musi obsługiwać standard 802.11-2016 FTM.
- Urządzenie wysyłające żądanie określania zakresu musi mieć system Android 9 (poziom interfejsu API 28) lub nowszy.
- Urządzenie wysyłające prośbę o określenie zakresu musi mieć włączone usługi lokalizacyjne i skanowanie Wi-Fi (w sekcji Ustawienia > Lokalizacja).
- Jeśli aplikacja wysyłająca żądanie określania zakresu jest kierowana na Androida 13 (poziom interfejsu API 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 dotyczące zakresu punktów dostępu, gdy aplikacja jest widoczna lub działa na pierwszym planie. Aplikacja nie może uzyskać dostępu do informacji o lokalizacji w tle.
- Punkt dostępu musi obsługiwać standard IEEE 802.11-2016 FTM.
Konfiguruj
Aby skonfigurować w aplikacji korzystanie z Wi-Fi RTT, wykonaj te czynności.
1. Poproś o uprawnienia
W pliku manifestu aplikacji poproś o te uprawnienia:
<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, dlatego musisz o nie prosić za każdym razem, gdy użytkownik chce przeprowadzić operację skanowania RTT. Aplikacja musi poprosić użytkownika o zgodę, jeśli nie zostało ono jeszcze przyznane. Więcej informacji o uprawnieniach czasu działania znajdziesz w artykule o wysyłaniu próśb o uprawnienia aplikacji.
2. Sprawdź, czy urządzenie obsługuje Wi-Fi RTT
Aby sprawdzić, czy urządzenie obsługuje RTT Wi-Fi, użyj interfejsu API PackageManager:
Kotlin
context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
Java
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);
3. Sprawdź, czy dostępna jest funkcja RTT Wi-Fi
Na urządzeniu może istnieć funkcja RTT Wi-Fi, ale ta funkcja może być obecnie niedostępna, ponieważ użytkownik wyłączył Wi-Fi. W zależności od możliwości sprzętowych i oprogramowania niektóre urządzenia mogą nie obsługiwać RTT w sieci Wi-Fi, jeśli w użyciu jest funkcja SoftAP lub tethering. Aby sprawdzić, czy RTT Wi-Fi jest obecnie dostępny, wywołaj isAvailable().
Dostępność funkcji RTT w sieci Wi-Fi może się zmienić w każdej chwili. Aplikacja powinna zarejestrować urządzenie BroadcastReceiver na wysyłanie ACTION_WIFI_RTT_STATE_CHANGED, które jest wysyłane w przypadku zmiany dostępności. Gdy aplikacja otrzyma intencję transmisji, powinna sprawdzić bieżący stan dostępności i odpowiednio dostosować swoje działanie.
Na 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 artykule Komunikaty.
Utwórz prośbę o zakres
Żądanie dotyczące zakresu (RangingRequest) jest tworzone przez określenie listy punktów dostępu lub równorzędnych elementów usługi Wi-Fi Aware, do których zażądano zakresu. W jednym żądaniu dotyczącym zakresu można określić wiele punktów dostępu lub równorzędnych połączeń Wi-Fi Aware Aware. Odległość od wszystkich urządzeń jest mierzona i zwracana.
Na przykład w żądaniu można użyć metody addAccessPoint(), aby określić punkt dostępu, do którego mierzy się 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 metodę WifiManager.getScanResults().
Za pomocą funkcji addAccessPoints(List
Podobnie żądanie określania zakresu może dodać równorzędny element sieci Wi-Fi AwarePeer za pomocą jego adresu MAC lub PeerHandle przy użyciu metod addWifiAwarePeer(MacAddress peer) i addWifiAwarePeer(PeerHandle peer). Więcej informacji o znajdowaniu elementów równorzędnych korzystających z Wi-Fi Aware znajdziesz w dokumentacji Wi-Fi Aware.
Zakres żądań
Aplikacja wysyła żądanie określania zakresu za pomocą metody WifiRttManager.startRanging(), podając następujące dane: RangingRequest do określenia operacji, Executor do określenia kontekstu wywołania zwrotnego oraz RangingResultCallback do otrzymania wyników.
Na 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 określania zakresu jest wykonywana asynchronicznie, a wyniki określania zakresu są zwracane w jednym z wywołań zwrotnych funkcji RangingResultCallback:
- Jeśli cała operacja zakresu się nie uda, wywoływane jest wywołanie zwrotne onRangingFailure z kodem stanu opisanym w sekcji RangingResultCallback. Taka awaria może wystąpić, gdy usługa nie może w danej chwili wykonać operacji określania zakresu, np. gdy sieć Wi-Fi jest wyłączona, aplikacja zażądała zbyt wielu operacji określania zakresu i została ograniczona lub z powodu problemu z uprawnieniami.
- Po zakończeniu operacji określania zakresu wykonywane jest wywołanie zwrotne onRangingResults z listą wyników zgodnych z listą żądań – po jednym wyniku dla każdego żądania. Kolejność wyników nie musi być zgodna z kolejnością żądań. Pamiętaj, że operacja określania zakresu może się zakończyć, ale każdy wynik może wskazywać na niepowodzenie konkretnego pomiaru.
Zinterpretuj wyniki określania zakresu
Każdy wynik zwrócony przez wywołanie zwrotne onRangingResults jest określany przez obiekt RangingResult. Wykonaj te czynności przy każdym żądaniu.
1. Zidentyfikuj żądanie
Określ żądanie na podstawie informacji podanych podczas tworzenia żądania RangingRequest. Zazwyczaj jest to adres MAC podany w żądaniu ScanResult
identyfikujący punkt dostępu. Adres MAC można uzyskać z wyniku określania zakresu za pomocą metody getMacAddress().
Lista wyników z zakresu zakresu może mieć inną kolejność niż równorzędne (punkty dostępu) określone w żądaniu określania zakresu, dlatego do identyfikowania elementu równorzędnego należy używać adresu MAC, a nie kolejności wyników.
2. sprawdzać, czy każdy pomiar się udał.
Aby sprawdzić, czy pomiar się udał, użyj metody getStatus(). Każda wartość inna niż STATUS_success oznacza błąd. Błąd oznacza, że wszystkie pozostałe pola tego wyniku (z wyjątkiem powyższej identyfikacji żądania) są nieprawidłowe, a odpowiednia metoda get*
zakończy się niepowodzeniem z wyjątkiem IllegalStateException .
3. Uzyskaj wyniki dla każdego udanego pomiaru
W przypadku każdego udanego pomiaru możesz pobrać wartości wyników za pomocą odpowiednich metod get
:
Odległość w mm i odchylenie standardowe pomiaru:
RSSI pakietów używanych na potrzeby pomiarów:
Czas (w milisekundach), w którym wykonano pomiar (wskazujący czas od uruchomienia):
Liczba przeprowadzonych pomiarów oraz liczba udanych pomiarów (oraz pomiarów, na których opierają się pomiary):
Urządzenia z Androidem obsługujące Wi-Fi-RTT
W tabelach poniżej znajdziesz listę niektórych telefonów, punktów dostępu oraz urządzeń z centrum handlowym, magazynu i dystrybucji, które obsługują Wi-Fi-RTT. Nie są one wyczerpujące. Zachęcamy, aby skontaktować się z nami i wymienić tutaj usługi obsługujące RTT.
Punkty dostępu
Producent i model | Data wsparcia |
---|---|
Nest Wifi Pro (Wi-Fi 6E) | Obsługiwane |
Przeprowadź obliczenia WILD AP | Obsługiwane |
Wi-Fi od Google | Obsługiwane |
router Wi-Fi Google Nest | Obsługiwane |
Punkt Google Nest Wi-Fi | Obsługiwane |
Aruba AP-635 | Obsługiwane |
Cisco 9130 | Obsługiwane |
Cisco 9136 | Obsługiwane |
Cisco 9166 | Obsługiwane |
Cisco 9164 | Obsługiwane |
Aruba AP-505 | Obsługiwane |
Aruba AP-515 | Obsługiwane |
Aruba AP-575 | Obsługiwane |
Aruba AP-518 | Obsługiwane |
Aruba AP-505H | Obsługiwane |
Aruba AP-565 | Obsługiwane |
Aruba AP-535 | Obsługiwane |
Telefony
Producent i model | Wersja Androida |
---|---|
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 lub nowszy | 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 do handlu detalicznego, magazynowania i dystrybucyjnego
Producent i model | Wersja Androida |
---|---|
Zebra PS20 | 10.0 lub nowszy |
Zebra TC52/TC52HC | 10.0 lub nowszy |
Zebra TC57 | 10.0 lub nowszy |
Zebra TC72 | 10.0 lub nowszy |
Zebra TC77 | 10.0 lub nowszy |
Zebra MC93 | 10.0 lub nowszy |
Zebra TC8300 | 10.0 lub nowszy |
Zebra VC8300 | 10.0 lub nowszy |
Zebra EC30 | 10.0 lub nowszy |
Zebra ET51 | 10.0 lub nowszy |
Zebra ET56 | 10.0 lub nowszy |
Zebra L10 | 10.0 lub nowszy |
Zebra CC600/CC6000 | 10.0 lub nowszy |
Zebra MC3300x | 10.0 lub nowszy |
Zebra MC330x | 10.0 lub nowszy |
Zebra TC52x | 10.0 lub nowszy |
Zebra TC57x | 10.0 lub nowszy |
Zebra EC50 (LAN i HC) | 10.0 lub nowszy |
Zebra EC55 (WAN) | 10.0 lub nowszy |
Zebra WT6300 | 10.0 lub nowszy |
Skorpio X5 | 10.0 lub nowszy |