Как определить, когда WIFI-соединение установлено в Android?
Мне нужно определить, когда у меня есть подключение к сети через WIFI. Какая широковещательная рассылка отправляется, чтобы установить, что установлено правильное сетевое соединение. Мне нужно проверить, что существует действительное сетевое соединение для HTTP. Что я должен слушать и какие дополнительные тесты мне нужно сделать, чтобы узнать, что существует действительное соединение.
16 ответов
Вы можете зарегистрировать BroadcastReceiver
получать уведомление при установлении соединения WiFi (или если оно изменилось).
Зарегистрировать BroadcastReceiver
:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
И тогда в вашем BroadcastReceiver
сделать что-то вроде этого:
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
//do stuff
} else {
// wifi connection was lost
}
}
}
Для получения дополнительной информации см. Документацию для BroadcastReceiver
а также WifiManager
Конечно, перед этим вы должны проверить, подключено ли устройство к WiFi.
РЕДАКТИРОВАТЬ: Благодаря запрету геоинженерии, вот метод, чтобы проверить, подключено ли устройство уже:
private boolean isConnectedViaWifi() {
ConnectivityManager connectivityManager = (ConnectivityManager) appObj.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return mWifi.isConnected();
}
Лучшее, что сработало для меня:
AndroidManifest
<receiver android:name="com.AEDesign.communication.WifiReceiver" >
<intent-filter android:priority="100">
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
Класс BroadcastReceiver
public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(info != null && info.isConnected()) {
// Do your work.
// e.g. To check the Network Name or other info:
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ssid = wifiInfo.getSSID();
}
}
}
права доступа
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Только для меня WifiManager.NETWORK_STATE_CHANGED_ACTION
работает.
Зарегистрировать приемник вещания:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
и получить:
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean connected = info.isConnected();
//call your method
}
}
Ответ пользователя @JPM и @usman действительно очень полезен. Это работает нормально, но в моем случае это входит onReceive
несколько раз в моем случае 4 раза, поэтому мой код выполняется несколько раз.
Я делаю некоторые модификации и делаю в соответствии с моим требованием, и теперь это приходит только 1 раз
Вот класс Java для трансляции.
public class WifiReceiver extends BroadcastReceiver {
String TAG = getClass().getSimpleName();
private Context mContext;
@Override
public void onReceive(Context context, Intent intent) {
mContext = context;
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI &&
networkInfo.isConnected()) {
// Wifi is connected
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ssid = wifiInfo.getSSID();
Log.e(TAG, " -- Wifi connected --- " + " SSID " + ssid );
}
}
else if (intent.getAction().equalsIgnoreCase(WifiManager.WIFI_STATE_CHANGED_ACTION))
{
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
if (wifiState == WifiManager.WIFI_STATE_DISABLED)
{
Log.e(TAG, " ----- Wifi Disconnected ----- ");
}
}
}
}
В AndroidManifest
<receiver android:name=".util.WifiReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Вы можете запустить Wi-Fi-соединение, если вы предоставляете пользователю возможность переопределять обычное поведение запроса каждый раз.
Я решил использовать три метода...
public boolean isOnline()
{
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
Это быстрая проверка, если есть подключение к Интернету, Wifi или CellData. Отсюда вы можете выбрать, какое действие вы хотите предпринять. Это в режиме полета необходимо проверить также.
На отдельную ветку. Я устанавливаю переменную IpAddress = = " " и опрашиваю, пока у меня не будет действительного IP-адреса.
WifiManager wifi;
wifi = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifi.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
String ip = null;
ip = String.format("%d.%d.%d.%d",
(ipAddress & 0xff),
(ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff),
(ipAddress >> 24 & 0xff));
Log.e(" >>IP number Begin ",ip);
Другой фрагмент кода... Если его не включить, включите его (с предварительного разрешения пользователя)
if(wifi.isWifiEnabled()!=true)wifi.setWifiEnabled(true);
Чтобы обнаружить состояние соединения WIFI, я использовал CONNECTIVITY_ACTION из класса ConnectivityManager так:
IntentFilter filter=new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(receiver, filter);
и от вашего BroadCastReceiver:
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
int networkType = intent.getIntExtra(
android.net.ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
if (ConnectivityManager.TYPE_WIFI == networkType) {
NetworkInfo networkInfo = (NetworkInfo) intent
.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (networkInfo != null) {
if (networkInfo.isConnected()) {
// TODO: wifi is connected
} else {
// TODO: wifi is not connected
}
}
}
}
PS: отлично работает для меня:)
Этот код не требует разрешения вообще. Он ограничен только изменениями состояния подключения к сети Wi-Fi (любая другая сеть не учитывается). Получатель статически публикуется в файле AndroidManifest.xml и не нуждается в экспорте, так как он будет вызываться системой protected broadcast
, NETWORK_STATE_CHANGED_ACTION
при каждом изменении состояния подключения к сети.
AndroidManifest:
<receiver
android:name=".WifiReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<!--protected-broadcast: Special broadcast that only the system can send-->
<!--Corresponds to: android.net.wifi.WifiManager.NETWORK_STATE_CHANGED_ACTION-->
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
Класс BroadcastReceiver:
public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
/*
Tested (I didn't test with the WPS "Wi-Fi Protected Setup" standard):
In API15 (ICE_CREAM_SANDWICH) this method is called when the new Wi-Fi network state is:
DISCONNECTED, OBTAINING_IPADDR, CONNECTED or SCANNING
In API19 (KITKAT) this method is called when the new Wi-Fi network state is:
DISCONNECTED (twice), OBTAINING_IPADDR, VERIFYING_POOR_LINK, CAPTIVE_PORTAL_CHECK
or CONNECTED
(Those states can be obtained as NetworkInfo.DetailedState objects by calling
the NetworkInfo object method: "networkInfo.getDetailedState()")
*/
/*
* NetworkInfo object associated with the Wi-Fi network.
* It won't be null when "android.net.wifi.STATE_CHANGE" action intent arrives.
*/
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (networkInfo != null && networkInfo.isConnected()) {
// TODO: Place the work here, like retrieving the access point's SSID
/*
* WifiInfo object giving information about the access point we are connected to.
* It shouldn't be null when the new Wi-Fi network state is CONNECTED, but it got
* null sometimes when connecting to a "virtualized Wi-Fi router" in API15.
*/
WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
String ssid = wifiInfo.getSSID();
}
}
}
Разрешения:
None
Ноябрь 2020 г.:
Я слишком много работал с элементами, которые не рекомендуются Google. Наконец, я нашел решение для моего конкретного требования, используя "registerNetworkCallback", как в настоящее время предлагает Google.
Мне нужен был простой способ определить, что моему устройству назначен IPv4 в WIFI. (Я не пробовал другие случаи, мое требование было очень конкретным, но, возможно, этот метод без устаревших элементов послужит основой для других случаев).
Протестировано на API 23, 24 и 26 (физические устройства) и API 28 и 29 (эмулируемые устройства).
ConnectivityManager cm
= (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
cm.registerNetworkCallback
(
builder.build(),
new ConnectivityManager.NetworkCallback()
{
@Override
public void onAvailable(Network network)
{
//Actions to take with Wifi available.
}
@Override
public void onLost(Network network)
{
//Actions to take with lost Wifi.
}
}
);
(Реализовано внутри "MainActivity.Oncreate")
Примечание. В манифесте требуется "android.permission.ACCESS_NETWORK_STATE"
Android O убрал возможность получать неявные трансляции для изменения состояния Wi-Fi. Поэтому, если ваше приложение закрыто, вы не сможете их получить. Новый WorkManager
имеет возможность работать, когда ваше приложение закрыто, поэтому я немного поэкспериментировал с ним, и, похоже, он работает довольно хорошо:
Добавьте это к вашим зависимостям:
implementation "android.arch.work:work-runtime:1.0.0-alpha08"
WifiConnectWorker.kt
class WifiConnectWorker : Worker() {
override fun doWork(): Result {
Log.i(TAG, "I think we connected to a wifi")
return Result.SUCCESS
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
val workManager = WorkManager.getInstance()
// Add constraint to start the worker when connecting to WiFi
val request = OneTimeWorkRequest.Builder(WifiConnectWorker::class.java)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(UNMETERED)
.build())
.build()
// The worker should be started, even if your app is closed
workManager.beginUniqueWork("watch_wifi", REPLACE, request).enqueue()
}
}
Имейте в виду, что это был всего лишь быстрый тест для одноразового уведомления. Есть еще много работы, чтобы всегда получать уведомления, когда WiFi включен и выключен.
PS: когда приложение принудительно завершается, рабочий не запускается, кажется WorkManager
отменяет запросы тогда.
У меня есть два способа обнаружить WIFI-соединение, получающее контекст приложения:
1) мой старый метод
public boolean isConnectedWifi1(Context context) {
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null) {
NetworkInfo[] netInfo = connectivityManager.getAllNetworkInfo();
for (NetworkInfo ni : netInfo) {
if ((ni.getTypeName().equalsIgnoreCase("WIFI"))
&& ni.isConnected()) {
return true;
}
}
}
return false;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return false;
}
2) мой новый метод (в настоящее время я использую этот метод):
public boolean isConnectedWifi(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return networkInfo.isConnected();
}
Вот пример моего кода, который учитывает предпочтение пользователей только разрешать передачу сообщений при подключении к Wi-Fi.
Я называю этот код изнутри IntentService
прежде чем я попытаюсь загрузить материал.
Обратите внимание, что NetworkInfo
будет null
если нет какого-либо сетевого подключения.
private boolean canConnect()
{
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean canConnect = false;
boolean wifiOnly = SharedPreferencesUtils.wifiOnly();
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo != null)
{
if(networkInfo.isConnected())
{
if((networkInfo.getType() == ConnectivityManager.TYPE_WIFI) ||
(networkInfo.getType() != ConnectivityManager.TYPE_WIFI && !wifiOnly))
{
canConnect = true;
}
}
}
return canConnect;
}
1) Я также попробовал подход Broadcast Receiver, хотя я знаю, что CONNECTIVITY_ACTION/CONNECTIVITY_CHANGE устарела в API 28 и не рекомендуется. Также связанный с использованием явного регистра, он слушает, пока приложение работает.
2) Я также попробовал Firebase Dispatcher, который работает, но не выходит за рамки приложения.
3) Рекомендованным способом является WorkManager, чтобы гарантировать выполнение за пределами процесса и внутреннее использование registerNetworkRequest().
Самым большим доказательством в пользу подхода № 3 является сам Android doc. Особенно для приложений в фоновом режиме.
Также здесь
В Android 7.0 мы удаляем три часто используемых неявных трансляции - CONNECTIVITY_ACTION, ACTION_NEW_PICTURE и ACTION_NEW_VIDEO - так как они могут пробуждать фоновые процессы нескольких приложений одновременно и загружать память и батарею. Если ваше приложение получает их, воспользуйтесь Android 7.0 для перехода на JobScheduler и связанные API-интерфейсы.
До сих пор это работает нормально для нас, используя периодический запрос WorkManager.
Обратите внимание, что для всех тех, кому нравится трансляция CONNECTIVITY_CHANGE, это больше не срабатывает, когда приложение работает в фоновом режиме в Android O.
https://developer.android.com/about/versions/o/background.html
Я использовал этот код:
public class MainActivity extends Activity
{
.
.
.
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
.
.
.
}
@Override
protected void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(broadcastReceiver, intentFilter);
}
@Override
protected void onPause()
{
super.onPause();
unregisterReceiver(broadcastReceiver);
}
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION))
{
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false))
{
// wifi is enabled
}
else
{
// wifi is disabled
}
}
}
};
}
Вы можете использовать трансляцию с фильтром
<receiver
android:name=".receivers.ConnectionType"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
после этого вы можете прослушать возвращаемое значение
@Override
public void onReceive(Context context, Intent intent) {
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
if(wifiState==WifiManager.WIFI_STATE_ENABLED){
Toast.makeText(context, "WIFI on", Toast.LENGTH_SHORT).show();
}else if(wifiState==WifiManager.WIFI_STATE_DISABLED) {
Toast.makeText(context, "WIFI OFF", Toast.LENGTH_SHORT).show();
}
}
он будет срабатывать каждый раз, когда WIFI включен или отключен
Функция расширения Kotlin
val Context.isOnline: Boolean
get() {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
if (cm != null) {
if (Build.VERSION.SDK_INT < 23) {
val networkInfo = cm.activeNetworkInfo
if (networkInfo != null) {
return networkInfo.isConnected && (networkInfo.type == ConnectivityManager.TYPE_WIFI || networkInfo.type == ConnectivityManager.TYPE_MOBILE ||
networkInfo.type == ConnectivityManager.TYPE_VPN || networkInfo.type == ConnectivityManager.TYPE_ETHERNET)
}
} else {
val network = cm.activeNetwork
if (network != null) {
val nc = cm.getNetworkCapabilities(network)
return if (nc == null) {
false
} else {
nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
nc.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ||
nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
}
}
}
}
return false
}