Android позволяет приложениям узнавать о динамических изменениях в подключении. Чтобы отслеживать изменения в подключении и реагировать на них, используйте следующие классы:
ConnectivityManagerсообщает приложению о состоянии подключения в системе.- Класс
Networkпредставляет одну из сетей, к которым подключено устройство. ОбъектNetworkможно использовать в качестве ключа для сбора информации о сети с помощьюConnectivityManagerили для привязки сокетов в сети. Когда сеть отключается, объектNetworkперестает быть доступным. Даже если устройство позже повторно подключится к тому же устройству, новая сеть будет представлена новым объектомNetwork. - Объект
LinkPropertiesсодержит информацию о ссылке для сети, например список DNS-серверов, локальные IP-адреса и сетевые маршруты, установленные для сети. - Объект
NetworkCapabilitiesсодержит информацию о свойствах сети, например о транспорте (Wi-Fi, мобильная сеть, Bluetooth) и возможностях сети. Например, вы можете запросить объект, чтобы определить, способна ли сеть отправлять MMS, находится ли она за страницей входа или является ли она лимитной.
Приложения, которым требуется информация о текущем состоянии подключения, могут вызывать методы ConnectivityManager, чтобы узнать, какой тип сети доступен. Эти методы полезны для отладки и периодического просмотра снимка доступных подключений в любой момент времени.
Однако синхронные методы ConnectivityManager не сообщают приложению о том, что происходит после вызова, поэтому они не позволяют обновлять пользовательский интерфейс. Они также не могут корректировать поведение приложения в зависимости от отключения сети или изменения ее возможностей.
Подключение может измениться в любой момент, и большинству приложений необходимо иметь всегда свежее и актуальное представление о состоянии сети на устройстве. Приложения могут зарегистрировать обратный вызов с помощью ConnectivityManager, чтобы получать оповещения об изменениях. Используя обратный вызов, ваше приложение может немедленно реагировать на любые соответствующие изменения в подключении, не прибегая к дорогостоящему опросу, который может пропустить быстрые обновления.
Для использования NetworkCallback и других способов определения состояния подключения устройства не требуется специальное разрешение.
Однако для некоторых сетей действуют особые разрешения.
Например, некоторые сети могут быть недоступны для приложений. Для привязки к фоновой сети требуется разрешение CHANGE_NETWORK_STATE. А для выполнения некоторых вызовов могут потребоваться определенные разрешения. Подробную информацию можно найти в документации по каждому вызову.
Получение мгновенного статуса
Устройство Android может поддерживать несколько подключений одновременно.
Чтобы получить информацию о текущем состоянии сети, сначала получите экземпляр ConnectivityManager:
Kotlin
val connectivityManager = getSystemService(ConnectivityManager::class.java)
Java
ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);
Затем используйте этот экземпляр, чтобы получить ссылку на текущую сеть по умолчанию для вашего приложения:
Kotlin
val currentNetwork = connectivityManager.getActiveNetwork()
Java
Network currentNetwork = connectivityManager.getActiveNetwork();
Получив ссылку на сеть, приложение может запросить информацию о ней:
Kotlin
val caps = connectivityManager.getNetworkCapabilities(currentNetwork) val linkProperties = connectivityManager.getLinkProperties(currentNetwork)
Java
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork); LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);
Чтобы получить доступ к дополнительным функциям, зарегистрируйте NetworkCallback.
Подробнее о том, как регистрировать обратные вызовы, читайте в разделе Прослушивание сетевых событий.
NetworkCapabilities и LinkProperties
Объекты 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, а локальная одноранговая сеть 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.
Когда новая сеть становится сетью по умолчанию, все новые подключения, которые открывает приложение, используют эту сеть. Через некоторое время все оставшиеся подключения к предыдущей сети по умолчанию принудительно завершаются. Если приложению важно знать, когда меняется сеть по умолчанию, оно регистрирует обратный вызов сети по умолчанию следующим образом:
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); } });
Когда сеть по умолчанию меняется, приложение получает вызов 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 для приложения, которому требуется только безлимитное подключение к интернету:
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);
Это означает, что ваше приложение будет получать информацию обо всех изменениях, касающихся любой безлимитной сети в системе.
Что касается обратного вызова сети по умолчанию, существует версия registerNetworkCallback(NetworkRequest, NetworkCallback, Handler), которая принимает Handler, поэтому она не загружает поток Connectivity вашего приложения.
Вызовите ConnectivityManager.unregisterNetworkCallback(NetworkCallback), когда обратный вызов больше не нужен. Приложение может одновременно регистрировать несколько обратных вызовов сети.
Для удобства объект NetworkRequest содержит общие возможности, необходимые большинству приложений, в том числе:
При написании приложения проверьте, соответствуют ли значения по умолчанию вашему сценарию использования, и очистите их, если хотите, чтобы приложение получало уведомления о сетях, у которых нет этих возможностей. С другой стороны, добавьте возможности, чтобы избежать вызова при любом изменении подключения в сетях, с которыми ваше приложение не взаимодействует.
Например, если приложению нужно отправлять MMS-сообщения, добавьте NET_CAPABILITY_MMS в NetworkRequest, чтобы не получать уведомления обо всех сетях, которые не могут отправлять MMS-сообщения. Добавьте TRANSPORT_WIFI_AWARE, если вашему приложению требуется только одноранговое подключение по Wi-Fi.
NET_CAPABILITY_INTERNET и NET_CAPABILITY_VALIDATED полезны, если вы хотите передавать данные на сервер в интернете.
Пример последовательности обратных вызовов
В этом разделе описывается последовательность обратных вызовов, которые может получить приложение, если оно регистрирует как обратный вызов по умолчанию, так и обычный обратный вызов на устройстве с мобильным подключением. В этом примере устройство подключается к точке доступа Wi-Fi с хорошим сигналом, а затем отключается от нее. В примере также предполагается, что на устройстве включен параметр Мобильный интернет всегда включен.
Вот хронология событий:
Когда приложение вызывает
registerNetworkCallback(), обратный вызов немедленно получает вызовы отonAvailable(),onNetworkCapabilitiesChanged()иonLinkPropertiesChanged()для мобильной сети, поскольку доступна только эта сеть. Если доступна другая сеть, приложение также получает обратные вызовы для нее.
Рисунок 1. Состояние приложения после вызоваregisterNetworkCallback().Затем приложение вызывает
registerDefaultNetworkCallback(). Обратный вызов сети по умолчанию начинает получать вызовыonAvailable(),onNetworkCapabilitiesChanged()иonLinkPropertiesChanged()для мобильной сети, поскольку она является сетью по умолчанию. Если активна другая сеть, не заданная по умолчанию, приложение не сможет принимать вызовы для нее.
Рисунок 2. Состояние приложения после регистрации сети по умолчанию.Позже устройство подключается к сети Wi-Fi (без тарификации трафика). Обычный обратный вызов сети получает вызовы
onAvailable(),onNetworkCapabilitiesChanged()иonLinkPropertiesChanged()для сети Wi-Fi.
Рисунок 3. Состояние приложения после подключения к сети Wi-Fi без тарификации трафика.На этом этапе проверка сети Wi-Fi может занять некоторое время. В этом случае вызовы
onNetworkCapabilitiesChanged()для обратного вызова обычной сети не включают возможностьNET_CAPABILITY_VALIDATED. Через некоторое время вызывается методonNetworkCapabilitiesChanged(), в котором новые возможности включаютNET_CAPABILITY_VALIDATED. В большинстве случаев проверка выполняется очень быстро.Когда сеть Wi-Fi проходит проверку, система предпочитает ее мобильной сети, главным образом потому, что она не тарифицируется. Сеть Wi-Fi становится сетью по умолчанию, поэтому обратный вызов сети по умолчанию получает вызов
onAvailable(),onNetworkCapabilitiesChanged()иonLinkPropertiesChanged()для сети Wi-Fi. Мобильная сеть переходит в фоновый режим, а обратный вызов обычной сети получает вызовonLosing()для мобильной сети.Поскольку в этом примере предполагается, что мобильный интернет на устройстве всегда включен, мобильная сеть никогда не отключается. Если настройка отключена, то через некоторое время мобильная сеть отключается, а обычный обратный вызов сети получает вызов
onLost().
Рисунок 4. Состояние приложения после проверки сети Wi-Fi.Затем устройство внезапно отключается от Wi-Fi, потому что выходит из зоны действия сети. Поскольку Wi-Fi отключается, обычный обратный вызов сети получает вызов
onLost()для Wi-Fi. Поскольку мобильная сеть теперь является сетью по умолчанию, обратный вызов сети по умолчанию получает вызовыonAvailable(),onNetworkCapabilitiesChanged()иonLinkPropertiesChanged()для мобильной сети.
Рисунок 5. Состояние приложения после отключения от сети Wi-Fi.
Если параметр Мобильный интернет всегда активен отключен, то при отключении Wi-Fi устройство пытается подключиться к мобильной сети. Картина похожа, но с небольшой дополнительной задержкой для вызовов onAvailable(), а обычный обратный вызов сети также получает вызовы onAvailable(), onNetworkCapabilitiesChanged() и onLinkPropertiesChanged(), поскольку мобильная сеть становится доступной.
Ограничения на использование сети для передачи данных
Если сеть видна в обратном вызове, это не значит, что приложение может использовать ее для передачи данных. Некоторые сети не предоставляют подключение к интернету, а некоторые могут быть ограничены приложениями с привилегиями. Чтобы проверить подключение к интернету, ознакомьтесь со статьями NET_CAPABILITY_INTERNET и NET_CAPABILITY_VALIDATED.
Использование фоновых сетей также подлежит проверке разрешений. Если приложение использует фоновый мобильный трафик, ему требуется разрешение CHANGE_NETWORK_STATE.
Приложения с этим разрешением позволяют системе пытаться подключиться к сети, которая не используется, например к мобильной сети, когда устройство подключено к сети Wi-Fi. Такое приложение вызывает ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) с NetworkCallback, который будет вызван при подключении к сети.