Możesz używać funkcji lokalizacji Wi-Fi udostępnianej przez interfejs Wi-Fi RTT (Round-Trip-Time) API, aby mierzyć 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 multilateracji, aby oszacować położenie urządzenia, które 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ć szczegółowe usługi oparte na lokalizacji, np. nawigację w budynkach, jednoznaczne sterowanie głosem (np. „Włącz to światło”) i informacje oparte na lokalizacji (np. „Czy istnieją oferty specjalne dla 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ść od punktu dostępu. Punkty dostępu nie mają takich informacji. Operacje RTT Wi-Fi są nieograniczone w przypadku aplikacji działających na pierwszym planie, ale są ograniczone w przypadku aplikacji działających w tle.
RTT sieci Wi-Fi i powiązane funkcje Fine-Time-Measurement (FTM) są określone w standardzie IEEE 802.11-2016. RTT sieci Wi-Fi wymaga dokładnego pomiaru czasu dostarczanego przez funkcję FTM, ponieważ oblicza odległość między dwoma urządzeniami, mierząc czas potrzebny na przelot w obie strony między urządzeniami i mnożąc ten czas przez prędkość światła.
Różnice w implementacji w zależności od wersji Androida
Wi-Fi RTT zostało wprowadzone w Androidzie 9 (poziom API 28). Jeśli używasz tego protokołu do określania pozycji urządzenia za pomocą multilateracji na urządzeniach z Androidem 9, musisz mieć dostęp do wstępnie określonych danych o lokalizacji punktów dostępu w aplikacji. To Ty decydujesz, jak te dane będą przechowywane i pobierane.
Na urządzeniach z Androidem 10 (poziom interfejsu API 29) lub nowszym dane o lokalizacji punktu dostępu mogą być przedstawiane jako obiekty ResponderLocation
, które obejmują szerokość i długość geograficzną oraz wysokość. W przypadku punktów AP RTT sieci Wi-Fi, które obsługują informacje o konfiguracji lokalizacji lub raport o lokalizacji (dane LCI/LCR), podczas procesu określania zakresu protokół zwraca obiekt ResponderLocation
.
Dzięki tej funkcji aplikacje mogą wysyłać zapytania do punktów dostępu i pytać ich bezpośrednio o swoje stanowisko, bez potrzeby zapisywania tych informacji z wyprzedzeniem. Dzięki temu aplikacja może wyszukiwać punkty AP i określać ich pozycję, nawet jeśli ich wcześniej nie znano, np. gdy użytkownik wejdzie do nowego budynku.
Wymagania
- Sprzęt urządzenia, które wysyła żądanie określania zakresu, musi implementować standard FTM 802.11-2016.
- Urządzenie wysyłające żądanie zakresu musi korzystać z Androida 9 (poziom interfejsu API 28) lub nowszego.
- 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, która używa żądania 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 wcześniejszą wersję Androida, musi mieć uprawnienieACCESS_FINE_LOCATION
. - Gdy aplikacja jest widoczna lub działa w usłudze na pierwszym planie, aplikacja musi wysyłać zapytania dotyczące zakresu punktów dostępu. Aplikacja nie może uzyskiwać dostępu do informacji o lokalizacji w tle.
- Punkt dostępu musi implementować standard IEEE 802.11-2016 FTM.
Skonfiguruj
Aby skonfigurować aplikację do korzystania z Wi-Fi RTT, wykonaj te czynności.
1. Poproś 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 o nie prosić w czasie działania za każdym razem, gdy użytkownik chce wykonać operację skanowania RTT. Twoja aplikacja będzie musiała prosić o zgodę użytkownika, jeśli uprawnienia nie zostały jeszcze przyznane. Więcej informacji o uprawnieniach w czasie działania znajdziesz w sekcji Wysyłanie prośby o uprawnienia aplikacji.
2. Sprawdź, czy urządzenie obsługuje RTT Wi-Fi
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ępny jest RTT sieci Wi-Fi
Sieć Wi-Fi RTT może istnieć na urządzeniu, ale może być aktualnie niedostę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ć RTT Wi-Fi, jeśli używana jest funkcja SoftAP lub tethering. Aby sprawdzić, czy RTT sieci Wi-Fi jest obecnie dostępny, wywołaj isAvailable().
Dostępność RTT Wi-Fi może się zmienić w każdej chwili. Twoja aplikacja powinna zarejestrować obiekt BroadcastReceivedr, aby odbierać sygnał ACTION_WIFI_RTT_STATE_CHANGED, który jest wysyłany w przypadku zmiany dostępności. Gdy aplikacja otrzyma intencję przesyłania, 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 sekcji Komunikaty.
Utwórz żądanie dotyczące zakresu
Żądanie zakresu (RangingRequest) jest tworzone przez określenie listy punktów dostępu lub połączeń Wi-Fi Aware, do których ma być wysyłane żądanie zakresu. W jednym żądaniu dotyczącym zakresu można określić wiele punktów dostępu lub sieci Wi-Fi Aware. Odległości do wszystkich urządzeń są mierzone i zwracane.
Na przykład żądanie może użyć metody addAccessPoint(), aby określić punkt dostępu, do którego ma być mierzona 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(). Możesz użyć funkcji addAccessPoints(List
Podobnie żądanie dotyczące zakresu może dodać peer Wi-Fi Aware za pomocą jego adresu MAC lub PeerHandle, korzystając odpowiednio z metod addWifiAwarePeer(MacAddress peer) i addWifiAwarePeer(PeerHandle peer). Więcej informacji o znajdowaniu sieci równorzędnych dzięki Wi-Fi Aware znajdziesz w dokumentacji Wi-Fi Aware.
Zakres żądania
Aplikacja wysyła żądanie określania zakresu za pomocą metody WifiRttManager.startRanging() i udostępnia żądanie RangingRequest, które określa operację, wykonawcę, który określa kontekst wywołania zwrotnego, oraz RangingResultCallback, aby otrzymać wyniki.
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 zakresu jest wykonywana asynchronicznie, a wyniki zakresu są zwracane w jednym z wywołań zwrotnych RangingResultCallback:
- Jeśli operacja określania zakresu nie powiedzie się, wywołanie zwrotne onRangingFailure zostanie aktywowane z kodem stanu opisanym w sekcji RangingResultCallback. Taka awaria może wystąpić, gdy usługa nie może w tym czasie wykonać operacji zakresu – na przykład gdy sieć Wi-Fi jest wyłączona, ponieważ aplikacja żąda zbyt wielu operacji zakresu i jest ograniczona bądź z powodu problemu z uprawnieniami.
- Po zakończeniu operacji określania zakresu wywoływane jest wywołanie zwrotne onRangingResults z listą wyników pasujących do listy żądań – po 1 wyniku na każde żądanie. Kolejność wyników nie musi odpowiadać kolejności żądań. Pamiętaj, że operacja zmiany zakresu może zostać zakończona, ale każdy wynik może nadal wskazywać na niepowodzenie danego pomiaru.
Zinterpretuj wyniki z zakresu
Wszystkie wyniki zwracane przez wywołanie zwrotne onRangingResults są określane przez obiekt RangingResult. Przy każdej prośbie wykonaj te czynności.
1. Zidentyfikuj żądanie
Zidentyfikuj żądanie na podstawie informacji podanych podczas tworzenia żądania RangingRequest: najczęściej jest to adres MAC podany w ScanResult
identyfikujący punkt dostępu. Adres MAC można uzyskać z wyników określania zakresu za pomocą metody getMacAddress().
Lista wyników określania zakresu może mieć inną kolejność niż elementy równorzędne (punkty dostępu) określone w żądaniu dotyczącym zakresu, dlatego do identyfikacji peera należy używać adresu MAC, a nie kolejności wyników.
2. Sprawdzanie, czy każdy pomiar zakończył się powodzeniem
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ższego identyfikatora żądania) są nieprawidłowe, a odpowiadająca mu metoda get*
zakończy się niepowodzeniem i wystąpi wyjątek IllegalStateException .
3. Uzyskuj wyniki 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żytych do pomiarów:
Czas wykonania pomiaru (w milisekundach), który wskazuje czas od uruchomienia:
Liczba przeprowadzonych pomiarów oraz liczba zakończonych pomiarów (i na których oparte są pomiary odległości):
Urządzenia z Androidem obsługujące Wi-Fi RTT
W tabelach poniżej znajdziesz listę niektórych telefonów, punktów dostępu i urządzeń handlowych, magazynowych i dystrybucyjnych obsługujących Wi-Fi-RTT. Są to dalekosiężne dane. Zachęcamy do skontaktowania się z nami, aby wymienić usługi, które obsługują RTT.
Punkty dostępu
Producent i model | Data wsparcia |
---|---|
Nest Wifi Pro (Wi-Fi 6E) | Obsługiwane |
Compulab WILD AP | Obsługiwane |
Google Wi-Fi | Obsługiwane |
router Wi-Fi Google Nest | Obsługiwane |
Punkt Wi-Fi Google Nest | 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 centrum dystrybucji
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+ |