Чтение состояния сети

Android позволяет приложениям узнавать о динамических изменениях в подключении. Используйте следующие классы для отслеживания и реагирования на изменения в подключении:

  • ConnectivityManager сообщает вашему приложению о состоянии подключения в системе.
  • Класс Network представляет одну из сетей, к которой подключено устройство. Вы можете использовать объект Network в качестве ключа для сбора информации о сети с помощью ConnectivityManager или для привязки сокетов в сети. Когда сеть отключается, объект Network перестает быть пригодным для использования. Даже если устройство позже снова подключается к тому же устройству, новый объект Network представляет новую сеть.
  • Объект LinkProperties содержит информацию о ссылке для сети, такую ​​как список DNS-серверов, локальных IP-адресов и сетевых маршрутов, установленных для сети.
  • Объект NetworkCapabilities содержит информацию о свойствах сети, таких как транспорты (Wi-Fi, мобильный, Bluetooth) и то, на что способна сеть. Например, вы можете запросить объект, чтобы определить, способна ли сеть отправлять MMS, находится ли она за порталом захвата или является ли она тарифицируемой.

Приложения, заинтересованные в непосредственном состоянии подключения в любой момент времени, могут вызывать методы ConnectivityManager , чтобы узнать, какой тип сети доступен. Эти методы полезны для отладки и для периодического просмотра снимка подключения, доступного в любой момент времени.

Однако синхронные методы ConnectivityManager не сообщают вашему приложению о том, что происходит после вызова, поэтому они не позволяют вам обновлять ваш пользовательский интерфейс. Они также не могут корректировать поведение приложения в зависимости от отключения сети или изменения сетевых возможностей.

Подключение может измениться в любой момент, и большинству приложений необходимо иметь всегда свежий, актуальный вид состояния сети на устройстве. Приложения могут регистрировать обратный вызов с помощью ConnectivityManager , чтобы получать оповещения об изменениях, которые важны для приложения. Используя обратный вызов, ваше приложение может немедленно реагировать на любые существенные изменения в подключении, не прибегая к дорогостоящему опросу, который может пропустить быстрые обновления.

Использование NetworkCallback и других способов узнать о состоянии подключения устройства не требует каких-либо особых разрешений. Однако некоторые сети требуют особых разрешений. Например, могут быть ограниченные сети, недоступные приложениям. Привязка к фоновой сети требует разрешения CHANGE_NETWORK_STATE . А для запуска некоторых вызовов могут потребоваться особые разрешения. Подробности см. в документации по каждому вызову.

Получить мгновенное состояние

Устройство на базе Android может поддерживать много подключений одновременно. Чтобы получить информацию о текущем состоянии сети, сначала получите экземпляр ConnectivityManager :

Котлин

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

Ява

ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);

Далее используйте этот экземпляр, чтобы получить ссылку на текущую сеть по умолчанию для вашего приложения:

Котлин

val currentNetwork = connectivityManager.getActiveNetwork()

Ява

Network currentNetwork = connectivityManager.getActiveNetwork();

Имея ссылку на сеть, ваше приложение может запрашивать информацию о ней:

Котлин

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

Ява

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

Для более полезной функциональности зарегистрируйте NetworkCallback . Для получения дополнительной информации о регистрации сетевых обратных вызовов см. Прослушивание сетевых событий .

Возможности сети и свойства ссылок

Объекты NetworkCapabilities и LinkProperties предоставляют информацию обо всех атрибутах, известных системе о сети.

Объект LinkProperties знает о маршрутах, адресах ссылок, имени интерфейса, информации о прокси (если есть) и DNS-серверах. Вызовите соответствующий метод на объекте LinkProperties , чтобы получить необходимую информацию.

Объект NetworkCapabilities инкапсулирует информацию о сетевых транспортах и ​​их возможностях .

Транспорт — это абстракция физической среды, на которой работает сеть. Распространенными примерами транспортов являются Ethernet, Wi-Fi и мобильный. VPN и одноранговый Wi-Fi также могут быть транспортами. На Android сеть может иметь несколько транспортов одновременно. Примером этого является VPN, работающий как через Wi-Fi, так и через мобильные сети. VPN имеет транспорты Wi-Fi, мобильный и VPN. Чтобы узнать, есть ли у сети определенный транспорт, используйте метод NetworkCapabilities.hasTransport(int) с одной из констант NetworkCapabilities.TRANSPORT_* .

Возможность описывает свойство сети. Примерами возможностей являются MMS , NOT_METERED и INTERNET . Сеть с возможностью MMS может отправлять и получать сообщения службы мультимедийных сообщений, а сеть без этой возможности не может. Сеть с возможностью NOT_METERED не выставляет счет пользователю за данные. Ваше приложение может проверить наличие соответствующих возможностей, используя метод NetworkCapabilities.hasCapability(int) с одной из констант NetworkCapabilities.NET_CAPABILITY_* .

Наиболее полезные константы NET_CAPABILITY_* включают в себя:

  • NET_CAPABILITY_INTERNET : указывает, что сеть настроена для доступа в Интернет. Это касается настройки , а не фактической возможности доступа к публичным серверам. Например, сеть может быть настроена для доступа в Интернет, но подчиняться порталу захвата.

    Мобильная сеть оператора обычно имеет возможность INTERNET , в то время как локальная сеть P2P Wi-Fi обычно не имеет. Для фактического подключения см. NET_CAPABILITY_VALIDATED .

  • NET_CAPABILITY_NOT_METERED : указывает, что сеть не тарифицируется. Сеть классифицируется как тарифицируемая, когда пользователь чувствителен к интенсивному использованию данных по этому соединению из-за денежных затрат, ограничений данных или проблем с производительностью батареи.

  • NET_CAPABILITY_NOT_VPN : указывает, что сеть не является виртуальной частной сетью.

  • NET_CAPABILITY_VALIDATED : указывает, что сеть предоставляет фактический доступ к публичному Интернету при ее зондировании. Сеть за порталом авторизации или сеть, которая не обеспечивает разрешение доменных имен, не имеет такой возможности. Это самое близкое, что система может сказать о сети, фактически предоставляющей доступ, хотя проверенная сеть все еще может, в принципе, подвергаться фильтрации на основе IP или испытывать внезапные потери связи из-за таких проблем, как плохой сигнал.

  • NET_CAPABILITY_CAPTIVE_PORTAL : указывает, что сеть имеет портал захвата при его зондировании.

Существуют и другие возможности, которые могут быть интересны более специализированным приложениям. Для получения дополнительной информации ознакомьтесь с определениями параметров в NetworkCapabilities.hasCapability(int) .

Возможности сети могут измениться в любой момент. Когда система обнаруживает портал захвата, она показывает уведомление, приглашающее пользователя войти в систему. Пока это происходит, сеть имеет возможности NET_CAPABILITY_INTERNET и NET_CAPABILITY_CAPTIVE_PORTAL но не имеет возможности NET_CAPABILITY_VALIDATED .

Когда пользователь предпринимает действие и входит на страницу портала авторизации, устройство получает доступ к общедоступному Интернету, а сеть получает возможность NET_CAPABILITY_VALIDATED и теряет возможность NET_CAPABILITY_CAPTIVE_PORTAL .

Аналогично, транспорты сети могут динамически меняться. Например, VPN может перенастроить себя на использование более быстрой сети, которая только что появилась, например, переключиться с мобильной на Wi-Fi для своей базовой сети. В этом случае сеть теряет транспорт TRANSPORT_CELLULAR и получает транспорт TRANSPORT_WIFI , сохраняя при этом транспорт TRANSPORT_VPN .

Слушайте сетевые события

Чтобы узнать о сетевых событиях, используйте класс NetworkCallback вместе с ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) и ConnectivityManager.registerNetworkCallback(NetworkCallback) . Эти два метода служат разным целям.

Все приложения Android имеют сеть по умолчанию, которая определяется системой. Система обычно предпочитает безлимитные сети лимитным и более быстрые сети более медленным.

Когда приложение отправляет сетевой запрос, например, с помощью HttpsURLConnection , система удовлетворяет этот запрос, используя сеть по умолчанию. Приложения также могут отправлять трафик в другие сети. Для получения дополнительной информации см. раздел о дополнительных сетях .

Сеть, которая установлена ​​как сеть по умолчанию, может измениться в любой момент в течение жизненного цикла приложения. Типичным примером является попадание устройства в зону действия известной, активной, безлимитной и более быстрой, чем мобильная, точки доступа Wi-Fi. Устройство подключается к этой точке доступа и переключает сеть по умолчанию для всех приложений на новую сеть Wi-Fi.

Когда новая сеть становится сетью по умолчанию, любое новое соединение, которое открывает приложение, использует эту сеть. В какой-то момент все оставшиеся соединения в предыдущей сети по умолчанию принудительно завершаются. Если приложению важно знать, когда изменяется сеть по умолчанию, оно регистрирует обратный вызов сети по умолчанию следующим образом:

Котлин

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)
    }
})

Ява

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);
    }
});

Когда новая сеть становится сетью по умолчанию, приложение получает вызов onAvailable(Network) для новой сети. Реализуйте onCapabilitiesChanged(Network,NetworkCapabilities) , onLinkPropertiesChanged(Network,LinkProperties) или оба, чтобы соответствующим образом реагировать на изменения в подключении.

Для обратного вызова, зарегистрированного с помощью registerDefaultNetworkCallback() , onLost() означает, что сеть потеряла статус сети по умолчанию. Она может быть отключена.

Хотя вы можете узнать о транспортах, которые использует сеть по умолчанию, запросив NetworkCapabilities.hasTransport(int) , это плохой прокси для пропускной способности или тарификации сети. Ваше приложение не может предполагать, что Wi-Fi всегда безтарифицируется и всегда обеспечивает лучшую пропускную способность, чем мобильный.

Вместо этого используйте NetworkCapabilities.getLinkDownstreamBandwidthKbps() для измерения пропускной способности и NetworkCapabilites.hasCapability(int) с аргументами NET_CAPABILITY_NOT_METERED для определения измеренности. Для получения дополнительной информации см. раздел о NetworkCapabilities и LinkProperties .

По умолчанию методы обратного вызова вызываются в потоке подключения вашего приложения, который является отдельным потоком, используемым ConnectivityManager . Если вашей реализации обратных вызовов необходимо выполнить более длительную работу, вызовите их в отдельном рабочем потоке, используя вариант ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler) .

Отмените регистрацию обратного вызова, когда он вам больше не нужен, вызвав ConnectivityManager.unregisterNetworkCallback(NetworkCallback) . onPause() вашего основного действия — хорошее место для этого, особенно если вы зарегистрируете обратный вызов в onResume() .

Дополнительные сети (расширенные варианты использования)

Хотя сеть по умолчанию является единственной подходящей сетью для большинства приложений, некоторые приложения могут быть заинтересованы в других доступных сетях. Чтобы узнать о них, приложения создают NetworkRequest , соответствующий их потребностям, и вызывают ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback) .

Процесс похож на прослушивание сети по умолчанию. Однако, хотя в любой момент времени может быть только одна сеть по умолчанию, которая применяется к приложению, эта версия позволяет вашему приложению видеть все доступные сети одновременно, поэтому вызов onLost(Network) означает, что сеть отключилась навсегда, а не то, что она больше не является сетью по умолчанию.

Приложение создает NetworkRequest , чтобы сообщить ConnectivityManager , какие сети оно хочет прослушивать. В следующем примере показано, как создать NetworkRequest для приложения, которое интересуется только безлимитными интернет-подключениями:

Котлин

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

connectivityManager.registerNetworkCallback(request, myNetworkCallback)

Ява

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

connectivityManager.registerNetworkCallback(request, myNetworkCallback);

Это означает, что ваше приложение узнает обо всех изменениях, касающихся любой безлимитной сети в системе.

Что касается обратного вызова сети по умолчанию, существует версия registerNetworkCallback(NetworkRequest, NetworkCallback, Handler) , которая принимает Handler , поэтому не загружает поток Connectivity вашего приложения.

Вызовите ConnectivityManager.unregisterNetworkCallback(NetworkCallback) , когда обратный вызов больше не актуален. Приложение может одновременно регистрировать несколько сетевых обратных вызовов.

Для удобства объект NetworkRequest содержит общие возможности, необходимые большинству приложений, включая следующие:

При написании приложения проверьте значения по умолчанию, чтобы увидеть, соответствуют ли они вашему варианту использования, и очистите их, если вы хотите, чтобы ваше приложение получало уведомления о сетях, в которых нет этих возможностей. С другой стороны, добавьте возможности, чтобы избежать вызова для любого изменения подключения в сетях, с которыми ваше приложение не взаимодействует.

Например, если вашему приложению необходимо отправлять MMS-сообщения, добавьте NET_CAPABILITY_MMS в NetworkRequest , чтобы избежать уведомлений обо всех сетях, которые не могут отправлять MMS-сообщения. Добавьте TRANSPORT_WIFI_AWARE , если ваше приложение заинтересовано только в подключении P2P Wi-Fi. NET_CAPABILITY_INTERNET и NET_CAPABILITY_VALIDATED полезны, если вам нужна возможность передавать данные с сервером в Интернете.

Пример последовательности обратного вызова

В этом разделе описывается последовательность обратных вызовов, которые может получить приложение, если оно регистрирует как обратный вызов по умолчанию, так и обычный обратный вызов на устройстве с мобильным подключением. В этом примере устройство подключается к хорошей точке доступа Wi-Fi, а затем отключается от нее. В примере также предполагается, что на устройстве включена настройка «Мобильные данные всегда включены».

Хронология выглядит следующим образом:

  1. Когда приложение вызывает registerNetworkCallback() , обратный вызов немедленно получает вызовы от onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для мобильной сети, поскольку доступна только эта сеть. Если доступна другая сеть, приложение также получает обратные вызовы для другой сети.

    Диаграмма состояний, показывающая событие обратного вызова сети регистрации и обратные вызовы, вызванные событием
    Рисунок 1. Состояние приложения после вызова registerNetworkCallback() .

  2. Затем приложение вызывает registerDefaultNetworkCallback() . Обратный вызов сети по умолчанию начинает принимать вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для мобильной сети, поскольку мобильная сеть является сетью по умолчанию. Если работает другая, нестандартная сеть, приложение не может принимать вызовы для нестандартной сети.

    Диаграмма состояний, показывающая регистрацию события обратного вызова сети по умолчанию и обратные вызовы, вызванные событием
    Рисунок 2. Состояние приложения после регистрации сети по умолчанию.

  3. Позже устройство подключается к (безлимитной) сети Wi-Fi. Обратный вызов обычной сети получает вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для сети Wi-Fi.

    Диаграмма состояний, показывающая обратные вызовы, срабатывающие при подключении приложения к новой сети
    Рисунок 3. Состояние приложения после подключения к безлимитной сети Wi-Fi.

  4. На этом этапе возможно, что сети Wi-Fi требуется некоторое время для проверки. В этом случае вызовы onNetworkCapabilitiesChanged() для обычного обратного вызова сети не включают возможность NET_CAPABILITY_VALIDATED . Через короткое время он получает вызов onNetworkCapabilitiesChanged() , где новые возможности включают NET_CAPABILITY_VALIDATED . В большинстве случаев проверка выполняется очень быстро.

    Когда сеть Wi-Fi проходит валидацию, система отдает ей предпочтение перед мобильной сетью, в основном потому, что она не тарифицируется. Сеть Wi-Fi становится сетью по умолчанию, поэтому обратный вызов сети по умолчанию получает вызов onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для сети Wi-Fi. Мобильная сеть переходит в фоновый режим, а обратный вызов обычной сети получает вызов onLosing() для мобильной сети.

    Поскольку этот пример предполагает, что мобильные данные всегда включены для этого устройства, мобильная сеть никогда не отключается. Если настройка отключена, то через некоторое время мобильная сеть отключается, и регулярный сетевой обратный вызов получает вызов onLost() .

    Диаграмма состояний, показывающая обратные вызовы, срабатывающие при проверке подключения к сети Wi-Fi
    Рисунок 4. Состояние приложения после проверки сети Wi-Fi.

  5. Позже устройство внезапно отключается от Wi-Fi, потому что оно вышло из зоны действия. Поскольку Wi-Fi отключается, обычный сетевой обратный вызов получает вызов onLost() для Wi-Fi. Поскольку мобильная сеть является новой сетью по умолчанию, сетевой обратный вызов по умолчанию получает вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для мобильной сети.

    Диаграмма состояний, показывающая обратные вызовы, срабатывающие при потере соединения с сетью Wi-Fi
    Рисунок 5. Состояние приложения после отключения от сети Wi-Fi.

Если настройка Mobile data always on отключена, то при отключении Wi-Fi устройство пытается повторно подключиться к мобильной сети. Картина похожая, но с небольшой дополнительной задержкой для вызовов onAvailable() , а обратный вызов обычной сети также получает вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() поскольку мобильная связь становится доступной.

Ограничения на использование сети для передачи данных

Возможность видеть сеть с сетевым обратным вызовом не означает, что ваше приложение может использовать сеть для передачи данных. Некоторые сети не обеспечивают подключение к Интернету, а некоторые сети могут быть ограничены для привилегированных приложений. Чтобы проверить подключение к Интернету, см. NET_CAPABILITY_INTERNET и NET_CAPABILITY_VALIDATED .

Использование фоновых сетей также подлежит проверке разрешений. Если ваше приложение хочет использовать фоновую сеть, ему необходимо разрешение CHANGE_NETWORK_STATE .

Приложения с этим разрешением позволяют системе попытаться поднять сеть, которая не работает, например, мобильную сеть, когда устройство подключено к сети Wi-Fi. Такое приложение вызывает ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) с NetworkCallback , который будет вызван, когда сеть будет поднята.