Odczytywanie stanu sieci

Android umożliwia aplikacjom rozpoznawanie dynamicznych zmian w połączeniach. Za pomocą tych klas możesz śledzić zmiany połączeń i reagować na nie:

  • ConnectivityManager informuje aplikację o stanie połączeń w systemie.
  • Klasa Network reprezentuje jedną z sieci, z którymi urządzenie jest połączone. Możesz użyć obiektu Network jako klucza do zbierania informacji o sieci za pomocą ConnectivityManager lub do powiązania gniazd w sieci. Po rozłączeniu sieci obiekt Network przestaje być używany. Nawet jeśli później urządzenie ponownie połączy się z tym samym urządzeniem, nowy obiekt Network reprezentuje nową sieć.
  • Obiekt LinkProperties zawiera informacje o połączeniu do sieci, takie jak lista serwerów DNS, lokalnych adresów IP i tras sieciowych zainstalowanych na potrzeby sieci.
  • Obiekt NetworkCapabilities zawiera informacje o właściwościach sieci, np. o transporcie (Wi-Fi, komórkowe, Bluetooth) oraz o możliwościach danej sieci. Możesz na przykład wysłać zapytanie do obiektu, aby określić, czy sieć może wysyłać MMS-y, znajduje się za portalem przechwytującym lub czy sieć z pomiarem użycia danych.

Aplikacje zainteresowane natychmiastowym stanem połączenia mogą w dowolnym momencie wywoływać metody ConnectivityManager, aby dowiedzieć się, jaki rodzaj sieci jest dostępny. Te metody są pomocne przy debugowaniu i sporadycznie sprawdzaniu zrzutu dostępnego w danym momencie.

Synchroniczne metody ConnectivityManager nie informują jednak aplikacji o tym, co dzieje się po wywołaniu, więc nie umożliwiają aktualizacji interfejsu. Nie mogą też dostosowywać działania aplikacji w zależności od rozłączania się z siecią lub zmiany funkcji sieciowych.

Połączenie może się zmienić w dowolnym momencie, a większość aplikacji musi mieć zawsze aktualny i aktualny stan sieci na urządzeniu. Aplikacje mogą zarejestrować wywołanie zwrotne za pomocą funkcji ConnectivityManager, aby otrzymywać alerty o zmianach, na których im zależy. Dzięki wywołaniu zwrotnemu aplikacja może natychmiast zareagować na wszelkie istotne zmiany w połączeniu bez konieczności korzystania z drogich ankiet, które mogłyby przeoczyć szybkie aktualizacje.

Korzystanie z NetworkCallback i innych sposobów sprawdzenia stanu połączenia urządzenia nie wymaga żadnych konkretnych uprawnień. Niektóre sieci wymagają jednak określonych uprawnień. Na przykład mogą istnieć sieci z ograniczeniami, które są niedostępne dla aplikacji. Powiązanie z siecią w tle wymaga uprawnienia CHANGE_NETWORK_STATE. Do uruchomienia niektórych wywołań mogą być potrzebne odpowiednie uprawnienia. Szczegółowe informacje o poszczególnych wywołaniach znajdziesz w dokumentacji poszczególnych wywołań.

Pobieranie stanu natychmiastowego

Urządzenie z Androidem może obsługiwać 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 sieci domyślnej dla aplikacji:

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

Na podstawie sieci aplikacja może poprosić o informacje o niej:

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 NetworkCallback. Więcej informacji o rejestrowaniu wywołań zwrotnych sieci znajdziesz w artykule Odsłuchiwanie zdarzeń sieciowych.

Możliwości sieci i właściwości połączenia

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

Obiekt LinkProperties wie o trasach, adresach połączeń, nazwie interfejsu, informacjach o serwerze proxy (jeśli je masz) i serwerach DNS. Wywołaj odpowiednią metodę w obiekcie LinkProperties, aby pobrać potrzebne informacje.

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

Transport to abstrakcja medium fizycznego, nad którym działa sieć. Typowe przykłady środków transportu to Ethernet, Wi-Fi i sieć komórkowa. Sieci VPN i sieci Wi-Fi peer-to-peer również mogą być przesyłane. Na Androidzie sieć może mieć wiele transportu naraz. Przykładem może być usługa VPN działająca zarówno w sieciach Wi-Fi, jak i komórkowych. VPN obsługuje transmisję Wi-Fi, 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_*.

Funkcja opisuje właściwość sieci. Przykładowe możliwości to MMS, NOT_METERED i INTERNET. Sieć obsługująca MMS-y może wysyłać i odbierać wiadomości multimedialne, natomiast sieć bez takiej możliwości nie ma takiej możliwości. Sieć z funkcją NOT_METERED nie nalicza użytkownikowi opłat za dane. Aplikacja może sprawdzać odpowiednie możliwości, używając metody NetworkCapabilities.hasCapability(int) z jedną ze stałych NetworkCapabilities.NET_CAPABILITY_*.

Najczęściej używane stałe NET_CAPABILITY_* to:

  • NET_CAPABILITY_INTERNET: oznacza, że sieć jest skonfigurowana pod kątem dostępu do internetu. Chodzi o konfigurację, a nie o rzeczywistą możliwość połączenia z serwerami publicznymi. Na przykład sieć może mieć dostęp do internetu, ale musi podlegać portalowi przechwytującemu.

    Sieć komórkowa operatora zwykle obsługuje INTERNET, natomiast lokalna sieć Wi-Fi P2P zwykle nie. Informacje o rzeczywistym połączeniu znajdziesz tutaj: NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED: oznacza, że sieć nie jest objęta pomiarem. Sieć jest uznawana za sieć z pomiarem użycia danych, gdy użytkownik jest szczególnie wrażliwy na intensywny transfer danych w tym połączeniu z powodu kosztów finansowych, ograniczeń danych lub problemów z wydajnością baterii.

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

  • NET_CAPABILITY_VALIDATED: wskazuje, że sieć zapewnia rzeczywisty dostęp do publicznego internetu w trakcie sondowania. Sieć działająca za portalem przechwytującym lub sieć, która nie obsługuje rozpoznawania nazw domen, nie ma takiej możliwości. Jest to najbliższa sieć, jaką system może stwierdzić, że sieć rzeczywiście zapewnia dostęp. Zweryfikowana sieć może jednak zasadniczo podlegać filtrowaniu na podstawie adresu IP lub nagłej utracie połączenia z powodu problemów takich jak słaby sygnał.

  • NET_CAPABILITY_CAPTIVE_PORTAL: wskazuje, że podczas sondowania w sieci znajduje się portal przechwytujący.

Są też inne funkcje, którymi mogą zainteresować się bardziej specjalistyczne aplikacje. Więcej informacji znajdziesz w definicjach parametrów w artykule NetworkCapabilities.hasCapability(int).

Możliwości sieci mogą się zmienić w każdej chwili. Gdy system wykryje portal przechwytujący, wyświetli użytkownikowi powiadomienie z prośbą o zalogowanie się. Gdy ten proces trwa, sieć udostępnia funkcje NET_CAPABILITY_INTERNET i NET_CAPABILITY_CAPTIVE_PORTAL, ale nie udostępnia NET_CAPABILITY_VALIDATED.

Gdy użytkownik wykona działanie i zaloguje się na stronie portalu przechwytującego, urządzenie może uzyskać dostęp do publicznego internetu, a sieć zdobywa możliwość NET_CAPABILITY_VALIDATED i traci możliwość NET_CAPABILITY_CAPTIVE_PORTAL.

Analogicznie sposób transportu sieci zmienia się dynamicznie. Na przykład sieć VPN może się skonfigurować tak, aby korzystała z szybszej sieci, która właśnie została utworzona. Przykładem może być przełączenie się z sieci komórkowej na Wi-Fi. W tym przypadku sieć traci transport TRANSPORT_CELLULAR i zyskuje transport TRANSPORT_WIFI, zachowując jednocześnie transport TRANSPORT_VPN.

Odsłuchiwanie zdarzeń sieciowych

Aby dowiedzieć się więcej o zdarzeniach sieciowych, użyj klasy NetworkCallback w połączeniu z właściwościami ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) i ConnectivityManager.registerNetworkCallback(NetworkCallback). Te 2 metody służą do różnych celów.

Wszystkie aplikacje na Androida mają domyślną sieć, którą określa system. System preferuje sieci bez pomiaru od sieci z pomiarem użycia danych oraz szybsze sieci i wolniejsze.

Gdy aplikacja wysyła żądanie sieciowe, np. HttpsURLConnection, system realizuje je, korzystając z sieci domyślnej. Aplikacje mogą wysyłać ruch również 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 korzystania z aplikacji. Typowym przykładem jest to, że urządzenie znajduje się w zasięgu znanego, aktywnego, szybszego niż mobilny punktu dostępu Wi-Fi z pomiarem użycia danych, bez pomiaru użycia danych. Urządzenie połączy się z tym punktem dostępu i przełączy domyślną sieć dla wszystkich aplikacji na nową sieć Wi-Fi.

Gdy nowa sieć stanie się domyślną, każde nowe połączenie otwarte przez aplikację będzie z niej korzystać. W pewnym momencie wszystkie pozostałe połączenia w poprzedniej sieci domyślnej zostaną wymuszane. Jeśli aplikacja ma wiedzieć o zmianie sieci domyślnej, rejestruje wywołanie zwrotne sieci 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. Aby odpowiednio reagować na zmiany w połączeniach, zaimplementuj metodę onCapabilitiesChanged(Network,NetworkCapabilities) lub onLinkPropertiesChanged(Network,LinkProperties) albo oba te elementy.

W przypadku wywołania zwrotnego zarejestrowanego przy użyciu registerDefaultNetworkCallback() wartość onLost() oznacza, że sieć utraciła status sieci domyślnej. Być może jest odłączone.

Informacje o środkach transportu używanych przez sieć domyślną możesz uzyskać, wysyłając zapytanie do NetworkCapabilities.hasTransport(int), ale jest to słaby serwer proxy pod względem przepustowości lub wykorzystania przepustowości sieci. Aplikacja nie może zakładać, że sieć Wi-Fi jest zawsze bez pomiaru użycia danych, a przepustowość sieci Wi-Fi jest zawsze większa od sieci komórkowej.

Zamiast tego użyj metody NetworkCapabilities.getLinkDownstreamBandwidthKbps() do pomiaru przepustowości, a metody NetworkCapabilites.hasCapability(int) – z argumentami NET_CAPABILITY_NOT_METERED do określania pomiaru wykorzystania. Więcej informacji znajdziesz w sekcji dotyczącej NetworkCapabilities i LinkWłaściwości.

Domyślnie metody wywołania zwrotnego są wywoływane w wątku połączenia aplikacji, który jest oddzielnym wątkiem używanym przez funkcję ConnectivityManager. Jeśli Twoje wdrożenie wywołań zwrotnych musi już działać, wywołaj je w oddzielnym wątku roboczym, używając wariantu ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

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

Dodatkowe sieci

W przypadku większości aplikacji sieć domyślna to jedyna odpowiednia sieć, ale niektóre aplikacje mogą być zainteresowane innymi dostępnymi sieciami. Aby dowiedzieć się więcej na ich temat, aplikacje tworzą NetworkRequest odpowiadającą ich potrzebom i wywołują metodę ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

Przypomina to słuchanie sieci domyślnej. Mimo że w danym momencie do aplikacji może mieć zastosowanie tylko jedna sieć domyślna, ta wersja umożliwia jej jednoczesne wyświetlanie wszystkich dostępnych sieci. Wywołanie onLost(Network) oznacza więc, że sieć została rozłączona na stałe. Nie oznacza, że już nie jest to sieć domyślna.

Aplikacja tworzy NetworkRequest, aby poinformować ConnectivityManager, jakiego rodzaju sieci chce nasłuchiwać. Z poniższego przykładu dowiesz się, jak utworzyć NetworkRequest dla aplikacji, która interesuje tylko połączenia z internetem bez pomiaru użycia danych:

Kotlin

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

connectivityManager.registerNetworkCallback(request, myNetworkCallback)

Java

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

connectivityManager.registerNetworkCallback(request, myNetworkCallback);

Oznacza to, że aplikacja będzie otrzymywać informacje o wszelkich zmianach dotyczących sieci bez pomiaru w systemie.

Jeśli chodzi o domyślne wywołanie zwrotne sieci, istnieje wersja registerNetworkCallback(NetworkRequest, NetworkCallback, Handler), która akceptuje żądanie Handler, więc nie wczytuje on wątku Connectivity Twojej aplikacji.

Zadzwoń pod numer ConnectivityManager.unregisterNetworkCallback(NetworkCallback), gdy wywołanie zwrotne nie jest już potrzebne. Aplikacja może jednocześnie zarejestrować wiele wywołań zwrotnych sieci.

Dla wygody obiekt NetworkRequest zawiera typowe funkcje potrzebne większości aplikacji, w tym:

Podczas tworzenia aplikacji sprawdź wartości domyślne, aby zobaczyć, czy pasują do Twojego przypadku użycia, i wyczyść je, jeśli chcesz otrzymywać powiadomienia o sieciach, które nie mają tych funkcji. Z drugiej strony dodaj możliwości, które pozwolą uniknąć wywoływania w przypadku zmian w połączeniach w sieciach, z którymi Twoja aplikacja nie korzysta.

Jeśli na przykład aplikacja musi wysyłać MMS-y, dodaj NET_CAPABILITY_MMS do NetworkRequest, aby nie otrzymywać informacji o wszystkich sieciach, które nie mogą wysyłać MMS-ów. Dodaj TRANSPORT_WIFI_AWARE, jeśli Twoja aplikacja obsługuje tylko połączenia P2P Wi-Fi. NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED są przydatne, jeśli interesuje Cię możliwość przenoszenia danych z serwera w internecie.

Przykładowa sekwencja wywołań zwrotnych

W tej sekcji opisujemy sekwencję wywołań zwrotnych, które może otrzymać aplikacja, jeśli rejestruje zarówno domyślne, jak i zwykłe wywołanie na urządzeniu z połączeniem mobilnym. W tym przykładzie urządzenie łączy się z dobrym punktem dostępu Wi-Fi, a następnie rozłącza się z nim. W przykładzie zakładamy też, że urządzenie ma włączone ustawienie Mobilna transmisja danych zawsze włączona.

Harmonogram jest następujący:

  1. Gdy aplikacja wywołuje metodę registerNetworkCallback(), wywołanie zwrotne natychmiast odbiera połączenia z sieci onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() z sieci komórkowej, ponieważ dostępna jest tylko ta sieć. Jeśli dostępna jest inna sieć, aplikacja odbiera też z niej wywołania zwrotne.

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

  2. Następnie aplikacja wywołuje registerDefaultNetworkCallback(). Wywołanie zwrotne sieci domyślnej rozpoczyna odbieranie połączeń z operatorami onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() w przypadku sieci komórkowej, ponieważ jest ona siecią domyślną. Jeśli uruchomiona jest inna sieć inna niż domyślna, aplikacja nie może odbierać wywołań z tej sieci.

    Diagram stanu pokazujący rejestrowanie domyślnego zdarzenia wywołania zwrotnego sieci oraz wywołań zwrotnych aktywowanych przez to zdarzenie
    Rysunek 2. Stan aplikacji po zarejestrowaniu sieci domyślnej.

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

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

  4. W tym momencie weryfikacja sieci Wi-Fi może zająć trochę czasu. W takim przypadku wywołania onNetworkCapabilitiesChanged() w przypadku zwykłego wywołania zwrotnego sieci nie obejmują możliwości NET_CAPABILITY_VALIDATED. Po krótkim czasie narzędzie otrzymuje wywołanie onNetworkCapabilitiesChanged(), gdzie nowe możliwości to NET_CAPABILITY_VALIDATED. W większości przypadków weryfikacja przebiega bardzo szybko.

    Po zweryfikowaniu sieci Wi-Fi system preferuje ją względem sieci komórkowej, głównie dlatego, że nie ma pomiaru użycia danych. Sieć Wi-Fi staje się siecią domyślną, więc wywołanie zwrotne sieci domyślnej odbiera wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci Wi-Fi. Sieć komórkowa przechodzi w tle, a zwykłe wywołanie zwrotne sieci komórkowej otrzymuje połączenie z siecią onLosing().

    Zakładamy w nim, że komórkowa transmisja danych jest zawsze włączona na tym urządzeniu, więc sieć komórkowa nigdy się nie rozłącza. Jeśli to ustawienie jest wyłączone, po pewnym czasie sieć komórkowa zostanie rozłączona i zwykłe wywołanie zwrotne otrzyma połączenie onLost().

    Schemat stanu pokazujący wywołania zwrotne uruchamiane podczas sprawdzania połączenia z siecią Wi-Fi
    Rysunek 4. Stan aplikacji po weryfikacji sieci Wi-Fi.

  5. Później urządzenie nagle rozłącza się z Wi-Fi, ponieważ było poza zasięgiem. Ponieważ sieć Wi-Fi zostanie rozłączona, zwykłe wywołanie zwrotne sieci spowoduje połączenie z siecią onLost() w celu uzyskania połączenia z Wi-Fi. Ponieważ sieć komórkowa jest nową siecią domyślną, wywołanie zwrotne sieci komórkowej odbiera połączenia z numerami onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() z sieci komórkowej.

    Schemat stanu pokazujący wywołania zwrotne aktywowane 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 przez Wi-Fi urządzenie spróbuje ponownie połączyć się z siecią komórkową. Obraz jest podobny, ale z krótkim dodatkowym opóźnieniem w przypadku wywołań onAvailable(). Zwykłe wywołanie zwrotne sieci otrzymuje też połączenia z numerami onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged(), ponieważ urządzenia mobilne stają się dostępne.

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

To, że aplikacja jest widoczna w sieci z wywołaniem zwrotnym, nie oznacza, że może ona używać tej sieci do przesyłania danych. Niektóre sieci nie zapewniają połączenia z internetem, a inne mogą być ograniczone do aplikacji z uprawnieniami. Aby sprawdzić połączenie z internetem, zobacz NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED.

Korzystanie z sieci w tle podlega również sprawdzeniu uprawnień. Jeśli Twoja aplikacja chce korzystać z sieci w tle, musi mieć uprawnienie CHANGE_NETWORK_STATE.

Aplikacje z tymi uprawnieniami umożliwiają systemowi wywołanie sieci, która nie działa, np. sieci komórkowej, gdy urządzenie jest połączone z siecią Wi-Fi. Taka aplikacja wywołuje metodę ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) z parametrem NetworkCallback, który zostanie wywołany po nawiązaniu połączenia z siecią.