Lokalizacja Wi-Fi: w zakresie z RTT

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ć uprawnienie ACCESS_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), aby dodać wiele punktów dostępu naraz.

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:

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+