Odczytywanie stanu sieci

Android umożliwia aplikacjom poznawanie dynamicznych zmian w łączności. Aby śledzić zmiany w łączności i na nie reagować, użyj tych klas:

  • ConnectivityManager informuje aplikację o stanie łączności w systemie.
  • Klasa Network reprezentuje jedną z sieci, z którymi połączone jest urządzenie. Możesz użyć obiektu Network jako klucza do zbierania informacji o sieci za pomocą ConnectivityManager lub do wiązania gniazd w sieci. Gdy sieć zostanie rozłączona, obiekt Network przestanie być użyteczny. Nawet jeśli urządzenie później połączy się ponownie z tym samym urządzeniem, nowa sieć będzie reprezentowana przez nowy obiekt Network.
  • Obiekt LinkProperties zawiera informacje o połączeniu z siecią, takie jak lista serwerów DNS , lokalne adresy IP i trasy sieciowe zainstalowane w sieci.
  • Obiekt NetworkCapabilities zawiera informacje o właściwościach sieci, takie jak transporty (Wi-Fi, sieć komórkowa, Bluetooth) i możliwości sieci. Możesz na przykład wysłać zapytanie do obiektu, aby sprawdzić, czy sieć może wysyłać wiadomości MMS, czy znajduje się za portalem przechwytującym lub czy jest płatna.

Aplikacje, które chcą znać bieżący stan łączności, mogą w dowolnym momencie wywołać metody ConnectivityManager, aby sprawdzić, jaki rodzaj sieci jest dostępny. Te metody są przydatne do debugowania i do okresowego sprawdzania stanu łączności dostępnego w danym momencie.

Synchroniczne metody ConnectivityManager nie informują jednak aplikacji o niczym, co dzieje się po wywołaniu, więc nie pozwalają na aktualizowanie interfejsu. Nie mogą też dostosowywać działania aplikacji na podstawie rozłączenia sieci lub zmiany jej możliwości.

Łączność może się zmienić w dowolnym momencie, a większość aplikacji musi mieć zawsze aktualny widok stanu sieci na urządzeniu. Aplikacje mogą zarejestrować wywołanie zwrotne w ConnectivityManager, aby otrzymywać powiadomienia o zmianach, które je interesują. Za pomocą wywołania zwrotnego aplikacja może natychmiast reagować na wszelkie istotne zmiany w łączności bez konieczności stosowania kosztownego sondowania, które może nie wykryć szybkich aktualizacji.

Korzystanie z NetworkCallback i innych sposobów sprawdzania stanu łączności urządzenia nie wymaga żadnych specjalnych uprawnień. Niektóre sieci podlegają jednak określonym uprawnieniom. Mogą na przykład istnieć sieci o ograniczonym dostępie, które nie są dostępne dla aplikacji. Powiązanie z siecią w tle wymaga uprawnienia CHANGE_NETWORK_STATE. Niektóre wywołania mogą też wymagać określonych uprawnień. Szczegółowe informacje znajdziesz w dokumentacji poszczególnych wywołań.

Uzyskiwanie natychmiastowego stanu

Urządzenie z Androidem może utrzymywać wiele połączeń jednocześnie. Aby uzyskać informacje o bieżącym stanie sieci, najpierw uzyskaj instancję ConnectivityManager:

Kotlin

val connectivityManager = getSystemService(ConnectivityManager::class.java)

Java

ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);

Następnie użyj tej instancji, aby uzyskać odniesienie do bieżącej domyślnej sieci aplikacji:

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

Dzięki odniesieniu do sieci aplikacja może poprosić o informacje na jej temat:

Kotlin

val caps = connectivityManager.getNetworkCapabilities(currentNetwork)
val linkProperties = connectivityManager.getLinkProperties(currentNetwork)

Java

NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork);
LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);

Aby korzystać z bardziej przydatnych funkcji, zarejestruj a NetworkCallback. Więcej informacji o rejestrowaniu wywołań zwrotnych sieci znajdziesz w artykule Nasłuchiwanie zdarzeń sieciowych.

NetworkCapabilities i LinkProperties

Obiekty NetworkCapabilities i LinkProperties zawierają informacje o wszystkich atrybutach, które system zna o sieci.

Obiekt LinkProperties zawiera informacje o trasach, adresach linków, nazwie interfejsu, informacjach o serwerze proxy (jeśli są dostępne) i serwerach DNS. Aby pobrać potrzebne informacje, wywołaj odpowiednią metodę w obiekcie LinkProperties.

Obiekt NetworkCapabilities zawiera informacje o transportach sieci i ich możliwościach.

Transport to abstrakcja medium fizycznego, przez które działa sieć. Typowe przykłady transportów to Ethernet, Wi-Fi i sieć komórkowa. Sieci VPN i Wi-Fi typu peer-to-peer mogą być też transportami. W Androidzie sieć może mieć jednocześnie wiele transportów. Przykładem jest sieć VPN działająca zarówno w sieciach Wi-Fi, jak i komórkowych. Sieć VPN ma transporty Wi-Fi, sieć komórkową i VPN. Aby sprawdzić, czy sieć ma określony transport, użyj metody NetworkCapabilities.hasTransport(int) z jedną ze stałych NetworkCapabilities.TRANSPORT_*.

Możliwość opisuje właściwość sieci. Przykłady możliwości to MMS, NOT_METERED i INTERNET. Sieć z możliwością MMS może wysyłać i odbierać wiadomości MMS, a sieć bez tej możliwości nie może tego robić. Sieć z możliwością NOT_METERED nie obciąża użytkownika za dane. Aplikacja może sprawdzić odpowiednie możliwości za pomocą metody NetworkCapabilities.hasCapability(int) z jedną ze stałych NetworkCapabilities.NET_CAPABILITY_*.

Najbardziej przydatne stałe NET_CAPABILITY_* to:

  • NET_CAPABILITY_INTERNET: wskazuje, że sieć jest skonfigurowana do dostępu do internetu. Dotyczy to konfiguracji, a nie rzeczywistej możliwości dotarcia do serwerów publicznych. Na przykład sieć może być skonfigurowana do dostępu do internetu, ale podlegać portalowi przechwytującemu.

    Sieć komórkowa operatora zwykle ma możliwość INTERNET, a lokalna sieć Wi-Fi P2P zwykle jej nie ma. Aby sprawdzić rzeczywistą łączność, zobacz NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED: wskazuje, że sieć nie jest płatna. Sieć jest klasyfikowana jako płatna, gdy użytkownik jest wrażliwy na duże zużycie danych w tym połączeniu ze względu na koszty, ograniczenia danych lub problemy z wydajnością baterii.

  • NET_CAPABILITY_NOT_VPN: wskazuje, że sieć nie jest wirtualną siecią prywatną.

  • NET_CAPABILITY_VALIDATED: wskazuje, że sieć zapewnia rzeczywisty dostęp do publicznego internetu, gdy jest sondowana. Sieć za portalem przechwytującym lub sieć, która nie zapewnia rozpoznawania nazw domen, nie ma tej możliwości. Jest to najbliższa informacja, jaką system może podać o sieci, która faktycznie zapewnia dostęp, chociaż zweryfikowana sieć może nadal podlegać filtrowaniu na podstawie adresu IP lub nagłym utratom łączności z powodu problemów takich jak słaby sygnał.

  • NET_CAPABILITY_CAPTIVE_PORTAL: wskazuje, że sieć ma portal przechwytujący, gdy jest sondowana.

Istnieją inne możliwości, które mogą zainteresować bardziej wyspecjalizowane aplikacje. Więcej informacji znajdziesz w definicjach parametrów w NetworkCapabilities.hasCapability(int).

Możliwości sieci mogą się zmienić w dowolnym momencie. Gdy system wykryje portal przechwytujący, wyświetli powiadomienie z prośbą o zalogowanie się. W tym czasie sieć ma możliwości NET_CAPABILITY_INTERNET i NET_CAPABILITY_CAPTIVE_PORTAL, ale nie ma możliwości NET_CAPABILITY_VALIDATED.

Gdy użytkownik podejmie działanie i zaloguje się na stronie portalu przechwytującego, urządzenie będzie mogło uzyskać dostęp do publicznego internetu, a sieć zyska możliwość NET_CAPABILITY_VALIDATED i utraci możliwość NET_CAPABILITY_CAPTIVE_PORTAL.

Podobnie transporty sieci mogą się zmieniać dynamicznie. Na przykład sieć VPN może się ponownie skonfigurować, aby używać szybszej sieci, która właśnie się pojawiła, np. przełączyć się z sieci komórkowej na Wi-Fi. W takim przypadku sieć traci transport TRANSPORT_CELLULAR i zyskuje transport TRANSPORT_WIFI, zachowując transport TRANSPORT_VPN.

Nasłuchiwanie zdarzeń sieciowych

Aby dowiedzieć się o zdarzeniach sieciowych, użyj klasy NetworkCallback razem z ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) i ConnectivityManager.registerNetworkCallback(NetworkCallback). Te 2 metody służą różnym celom.

Wszystkie aplikacje na Androida mają domyślną sieć, która jest określana przez system. System zwykle preferuje sieci bez pomiaru użycia danych od sieci płatnych oraz szybsze sieci od wolniejszych.

Gdy aplikacja wyśle żądanie sieciowe, np. za pomocą HttpsURLConnection, system zrealizuje to żądanie za pomocą sieci domyślnej. Aplikacje mogą też wysyłać ruch w innych sieciach. Więcej informacji znajdziesz w sekcji dotyczącej dodatkowych sieci.

Sieć ustawiona jako domyślna może się zmienić w dowolnym momencie podczas działania aplikacji. Typowym przykładem jest sytuacja, gdy urządzenie znajdzie się w zasięgu znanego, aktywnego, bez pomiaru i szybszego niż sieć komórkowa punktu dostępu Wi-Fi. Urządzenie łączy się z tym punktem dostępu i przełącza domyślną sieć dla wszystkich aplikacji na nową sieć Wi-Fi.

Gdy nowa sieć stanie się domyślną, każde nowe połączenie otwierane przez aplikację będzie korzystać z tej sieci. W pewnym momencie wszystkie pozostałe połączenia w poprzedniej sieci domyślnej zostaną wymuszone. Jeśli aplikacja musi wiedzieć, kiedy zmienia się sieć domyślna, rejestruje wywołanie zwrotne sieci domyślnej w ten sposób:

Kotlin

connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network : Network) {
        Log.e(TAG, "The default network is now: " + network)
    }

    override fun onLost(network : Network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network)
    }

    override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities)
    }

    override fun onLinkPropertiesChanged(network : Network, linkProperties : LinkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties)
    }
})

Java

connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        Log.e(TAG, "The default network is now: " + network);
    }

    @Override
    public void onLost(Network network) {
        Log.e(TAG, "The application no longer has a default network. The last default network was " + network);
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        Log.e(TAG, "The default network changed capabilities: " + networkCapabilities);
    }

    @Override
    public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
        Log.e(TAG, "The default network changed link properties: " + linkProperties);
    }
});

Gdy nowa sieć stanie się domyślną, aplikacja otrzyma wywołanie onAvailable(Network) dla nowej sieci. Zaimplementuj onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties), lub obie te metody, aby odpowiednio reagować na zmiany w łączności.

W przypadku wywołania zwrotnego zarejestrowanego za pomocą registerDefaultNetworkCallback() metoda onLost() oznacza, że sieć utraciła status sieci domyślnej. Może zostać rozłączona.

Chociaż możesz dowiedzieć się o transportach używanych przez sieć domyślną, wysyłając zapytanie do querying NetworkCapabilities.hasTransport(int), jest to słaby wskaźnik przepustowości lub płatności sieci. Aplikacja nie może zakładać, że Wi-Fi jest zawsze bez pomiaru i zawsze zapewnia lepszą przepustowość niż sieć komórkowa.

Zamiast tego użyj NetworkCapabilities.getLinkDownstreamBandwidthKbps() do pomiaru przepustowości oraz NetworkCapabilites.hasCapability(int) z NET_CAPABILITY_NOT_METERED argumentami, aby określić, czy sieć jest płatna. Więcej informacji znajdziesz w sekcji o NetworkCapabilities i LinkProperties.

Domyślnie metody wywołania zwrotnego są wywoływane w wątku łączności aplikacji, który jest oddzielnym wątkiem używanym przez ConnectivityManager. Jeśli implementacja wywołań zwrotnych wymaga dłuższego czasu, wywołaj je w osobnym wątku instancji roboczej za pomocą wariantu ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

Wyrejestruj wywołanie zwrotne, gdy nie będzie już potrzebne, wywołując ConnectivityManager.unregisterNetworkCallback(NetworkCallback). Dobrym miejscem na to jest onPause() głównej aktywności, zwłaszcza jeśli zarejestrujesz wywołanie zwrotne w onResume().

Dodatkowe sieci (zaawansowane przypadki użycia)

Chociaż sieć domyślna jest jedyną istotną siecią dla większości aplikacji, niektóre aplikacje mogą być zainteresowane innymi dostępnymi sieciami. Aby się o nich dowiedzieć, aplikacje tworzą NetworkRequest odpowiadający ich potrzebom i wywołują ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

Proces jest podobny do nasłuchiwania sieci domyślnej. Chociaż w danym momencie może istnieć tylko 1 sieć domyślna, która ma zastosowanie do aplikacji, ta wersja umożliwia aplikacji jednoczesne wyświetlanie wszystkich dostępnych sieci, więc wywołanie onLost(Network) oznacza, że sieć została rozłączona na stałe, a nie że nie jest już domyślna.

Aplikacja tworzy NetworkRequest, aby poinformować ConnectivityManager, jakiego rodzaju sieci chce nasłuchiwać. Ten przykład pokazuje, jak utworzyć NetworkRequest dla aplikacji, która jest zainteresowana tylko połączeniami internetowymi bez pomiaru użycia danych:

Kotlin

val request = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build()

connectivityManager.registerNetworkCallback(request, myNetworkCallback)

Java

NetworkRequest request = new NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build();

connectivityManager.registerNetworkCallback(request, myNetworkCallback);

Oznacza to, że aplikacja będzie otrzymywać informacje o wszystkich zmianach dotyczących dowolnej sieci bez pomiaru użycia danych w systemie.

Podobnie jak w przypadku wywołania zwrotnego sieci domyślnej, istnieje wersja registerNetworkCallback(NetworkRequest, NetworkCallback, Handler) , która akceptuje Handler, dzięki czemu nie obciąża wątku Connectivity aplikacji.

Gdy wywołanie zwrotne nie będzie już istotne, wywołaj ConnectivityManager.unregisterNetworkCallback(NetworkCallback). Aplikacja może jednocześnie zarejestrować wiele wywołań zwrotnych sieci.

Dla wygody obiekt NetworkRequest zawiera typowe możliwości, których potrzebuje większość aplikacji, w tym:

Podczas pisania aplikacji sprawdź ustawienia domyślne, aby zobaczyć, czy pasują do Twojego przypadku użycia, i wyczyść je, jeśli chcesz, aby aplikacja otrzymywała powiadomienia o sieciach, które nie mają tych możliwości. Z drugiej strony dodaj możliwości, aby uniknąć wywoływania w przypadku każdej zmiany łączności w sieciach, z którymi aplikacja nie wchodzi w interakcje.

Jeśli na przykład aplikacja musi wysyłać wiadomości MMS, dodaj NET_CAPABILITY_MMS do NetworkRequest, aby nie otrzymywać informacji o wszystkich sieciach, które nie mogą wysyłać wiadomości MMS. Dodaj TRANSPORT_WIFI_AWARE , jeśli aplikacja jest zainteresowana tylko łącznością Wi-Fi P2P. NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED są przydatne, jeśli chcesz przesyłać dane na serwer w internenecie.

Przykładowa sekwencja wywołań zwrotnych

W tej sekcji opisujemy sekwencję wywołań zwrotnych, które aplikacja może otrzymać, jeśli zarejestruje zarówno domyślne, jak i zwykłe wywołanie zwrotne na urządzeniu z łącznością komórkową. W tym przykładzie urządzenie łączy się z dobrym punktem dostępu Wi-Fi, a następnie się od niego rozłącza. Przykład zakłada też, że na urządzeniu jest włączone ustawienie Mobilna transmisja danych zawsze włączona.

Oś czasu wygląda tak:

  1. Gdy aplikacja wywoła registerNetworkCallback(), wywołanie zwrotne natychmiast otrzyma wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci komórkowej, ponieważ tylko ta sieć jest dostępna. Jeśli dostępna jest inna sieć, aplikacja otrzyma też wywołania zwrotne dla tej sieci.

    Diagram stanu przedstawiający zdarzenie wywołania zwrotnego sieci rejestracji i wywołania zwrotne wywoływane przez to zdarzenie
    Rysunek 1. Stan aplikacji po wywołaniu registerNetworkCallback().

  2. Następnie aplikacja wywołuje registerDefaultNetworkCallback(). Wywołanie zwrotne sieci domyślnej zaczyna otrzymywać wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci komórkowej, ponieważ sieć komórkowa jest siecią domyślną. Jeśli inna sieć, która nie jest domyślna, jest aktywna, aplikacja nie może otrzymywać wywołań dla tej sieci.

    Diagram stanu przedstawiający zdarzenie wywołania zwrotnego rejestracji domyślnej sieci i wywołania zwrotne wywoływane przez to zdarzenie
    Rysunek 2. Stan aplikacji po zarejestrowaniu sieci domyślnej.

  3. Później urządzenie łączy się z siecią Wi-Fi (bez pomiaru użycia danych). Zwykłe wywołanie zwrotne sieci otrzymuje wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci Wi-Fi.

    Diagram stanu przedstawiający wywołania zwrotne uruchamiane, gdy aplikacja łączy się z nową siecią
    Rysunek 3. Stan aplikacji po połączeniu z siecią Wi-Fi bez pomiaru użycia danych.

  4. W tym momencie weryfikacja sieci Wi-Fi może potrwać. W takim przypadku wywołania onNetworkCapabilitiesChanged() dla zwykłego wywołania zwrotnego sieci nie zawierają możliwości NET_CAPABILITY_VALIDATED. Po krótkim czasie otrzymuje wywołanie onNetworkCapabilitiesChanged(), w którym nowe możliwości obejmują NET_CAPABILITY_VALIDATED. W większości przypadków weryfikacja jest bardzo szybka.

    Gdy sieć Wi-Fi zostanie zweryfikowana, system preferuje ją od sieci komórkowej, głównie dlatego, że nie jest płatna. Sieć Wi-Fi staje się siecią domyślną, więc wywołanie zwrotne sieci domyślnej otrzymuje wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci Wi-Fi. Sieć komórkowa przechodzi w tle, a zwykłe wywołanie zwrotne sieci otrzymuje wywołanie onLosing() dla sieci komórkowej.

    Ponieważ w tym przykładzie zakłada się, że mobilna transmisja danych jest zawsze włączona na tym urządzeniu, sieć komórkowa nigdy się nie rozłącza. Jeśli to ustawienie jest wyłączone, po pewnym czasie sieć komórkowa rozłączy się, a zwykłe wywołanie zwrotne sieci otrzyma wywołanie onLost().

    Diagram stanu przedstawiający wywołania zwrotne uruchamiane po zweryfikowaniu połączenia z siecią Wi-Fi
    Rysunek 4. Stan aplikacji po zweryfikowaniu sieci Wi-Fi.

  5. Później urządzenie nagle rozłącza się z Wi-Fi, ponieważ wyszło poza zasięg. Ponieważ sieć Wi-Fi się rozłącza, zwykłe wywołanie zwrotne sieci otrzymuje wywołanie onLost() dla Wi-Fi. Ponieważ sieć komórkowa jest nową siecią domyślną, wywołanie zwrotne sieci domyślnej otrzymuje wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci komórkowej.

    Diagram stanu przedstawiający wywołania zwrotne uruchamiane po utracie połączenia z siecią Wi-Fi
    Rysunek 5. Stan aplikacji po rozłączeniu z siecią Wi-Fi.

Jeśli ustawienie Mobilna transmisja danych zawsze włączona jest wyłączone, po rozłączeniu Wi-Fi urządzenie próbuje ponownie połączyć się z siecią komórkową. Obraz jest podobny, ale z krótkim dodatkowym opóźnieniem w przypadku wywołań onAvailable(), a zwykłe wywołanie zwrotne sieci otrzymuje też wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged(), ponieważ sieć komórkowa staje się dostępna.

Ograniczenia dotyczące korzystania z sieci do przesyłania danych

Możliwość wyświetlenia sieci za pomocą wywołania zwrotnego sieci nie oznacza, że aplikacja może używać tej sieci do przesyłania danych. Niektóre sieci nie zapewniają łączności z internetem, a niektóre mogą być ograniczone do aplikacji z uprawnieniami. Aby sprawdzić łączność z internetem, zobacz NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED.

Korzystanie z sieci w tle podlega też sprawdzaniu uprawnień. Jeśli aplikacja chce korzystać z sieci w tle, potrzebuje CHANGE_NETWORK_STATE uprawnienia.

Aplikacje z tym uprawnieniem umożliwiają systemowi próbę uruchomienia sieci, która nie jest aktywna, np. sieci komórkowej, gdy urządzenie jest połączone z siecią Wi-Fi. Taka aplikacja wywołuje ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) z NetworkCallback, które ma być wywoływane po uruchomieniu sieci.