一. 问题背景
Android12上,有的app模块判断当前网络的类型和连接状态时,还是使用的旧的API,导致返回的结果不准确,影响代码逻辑判断,本篇文章就这一问题,整理一下判断网络类型和连接状态的新方法。
二. 原因分析
在Android 10以前的版本,大家都是通过NetworkInfo.java 的getType()方法获取网络类型,通过isConnected()方法来判断是否连接上, 判断网络连接的旧方法如下:
1.是否连接:
2. 网络类型
但是在Android10之后,这些方法已过时,官方不推荐使用,我们先来看下官方的源码说明
左边是Android10,右边是Android9的源码 , 在10上已经标记Deprecated,新加的注释也推荐了使用的API。
还有一个旧广播String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE" 在Android 9之后也废弃,不推荐使用,之前的使用方法:
看下官方说明:
官方标记Deprecated,是避免在高版本的设备上获取返回的网络状态不对,并且给了推荐的API,以Android10为一个分界点, 之后的版本都推荐使用新的API方法。
三. 官方推荐API
官方推荐:监控 Android 中的互联网连接,可以使用ConnectivityManager类,这是一个允许您查询网络状态的系统服务类, 还有一个NetworkCapabilities类,代表活动网络的功能。
体使用方法如下:
registerNetworkCallback():此函数注册一个NetworkCallback对象来监听网络状态变化。它以一个NetworkCallback对象作为参数。
unregisterNetworkCallback():此函数取消注册以前注册的NetworkCallback对象。
接下来重点关注NetworkCallback中的回调方法描述
回调方法 | 描述 |
onCapabilitiesChanged | 当网络状态改变时回调,比如信号强度切换,或者连接上网络—>断开网络,或者 mobile网络切换到Wifi网络,都会回调 |
onAvailable | 网络连接成功 但不能判断该网络是否可以正常上网 |
onUnavailable | 当网络连接超时或网络请求达不到可用要求时调用 |
onBlockedStatusChanged | 当访问指定的网络被阻止或解除阻塞时调用 |
onLosing | 当网络正在断开连接时调用 |
onLost | 当网络已断开连接时调用 |
onLinkPropertiesChanged | 当网络连接的属性被修改时调用 |
接下来再说一下
NetworkCapabilities.java类中的NET_CAPABILITY_VALIDATED字段,描述为:
表示此网络上的连接已成功验证。例如,对于具有NET_CAPABILITY_INTERNET的网络,这意味着已成功检测到INTERNET连接。
通过实际log来描述说明一下:
1. 连接上可上网的wifi,可看到VALIDATED的标记:
2. 连接上需要认证和不能上网的wifi,找不到VALIDATED标记:
3. 用数据流量上网,可以看到VALIDATED的标记:
我们可以通过networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)这个方法作为(连接可以正常上网的网络)判断条件。进一步通过networkCapabilities.hasTransport方法来判断当前的网络类型。
四. 使用方法
看代码更直接一点:
MainActivity.java
@SuppressLint("NewApi")
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ConnectManager";
private ConnectivityManager networkService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
networkService = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
if (networkService != null) {
//注册 NetworkCallBack
networkService.registerDefaultNetworkCallback(networkCallBack);
}
}
/*
* 测试网络工具类方法
* */
@Override
protected void onResume() {
super.onResume();
//Log.e(TAG, "=====在onResume方法中判断 : isMobileNetwork :" + NetworkUtils.isMobileNetwork(this));
//Log.e(TAG, "=====在onResume方法中判断 : isWifiNetwork :" + NetworkUtils.isWifiNetwork(this));
//Log.e(TAG, "=====在onResume方法中判断 : getConnectedNetworkType :" + NetworkUtils.getConnectedNetworkType(this));
}
@Override
protected void onDestroy() {
super.onDestroy();
if (networkService != null && networkCallBack != null) {
networkService.unregisterNetworkCallback(networkCallBack);
}
}
private final ConnectivityManager.NetworkCallback networkCallBack = new ConnectivityManager.NetworkCallback(){
//当网络状态修改但仍旧是可用状态时调用
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
if (NetworkUtils.isConnectedAvailableNetwork(getBaseContext())) {
Log.d(TAG, "onCapabilitiesChanged ---> ====网络可正常上网===网络类型为: "+ NetworkUtils.getConnectedNetworkType(MainActivity.this));
}
//表明此网络连接验证成功
if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
Log.d(TAG, "===当前在使用Mobile流量上网===");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.d(TAG, "====当前在使用WiFi上网===");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
Log.d(TAG, "=====当前使用蓝牙上网=====");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
Log.d(TAG, "=====当前使用以太网上网=====");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
Log.d(TAG, "===当前使用VPN上网====");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
Log.d(TAG, "===表示此网络使用Wi-Fi感知传输====");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
Log.d(TAG, "=====表示此网络使用LoWPAN传输=====");
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
Log.d(TAG, "=====表示此网络使用USB传输=====");
}
}
}
@Override
public void onAvailable(@NonNull Network network) {
super.onAvailable(network);
Log.e(TAG, "==网络连接成功,通知可以使用的时候调用====onAvailable===");
}
@Override
public void onUnavailable() {
Log.e(TAG, "==当网络连接超时或网络请求达不到可用要求时调用====onUnavailable===");
super.onUnavailable();
}
@Override
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {
Log.e(TAG, "==当访问指定的网络被阻止或解除阻塞时调用===onBlockedStatusChanged==");
super.onBlockedStatusChanged(network, blocked);
}
@Override
public void onLosing(@NonNull Network network, int maxMsToLive) {
Log.e(TAG, "==当网络正在断开连接时调用===onLosing===");
super.onLosing(network, maxMsToLive);
}
@Override
public void onLost(@NonNull Network network) {
Log.e(TAG, "==当网络已断开连接时调用===onLost===");
super.onLost(network);
}
@Override
public void onLinkPropertiesChanged(@NonNull Network network, @NonNull LinkProperties linkProperties) {
Log.e(TAG, "==当网络连接的属性被修改时调用===onLinkPropertiesChanged===");
super.onLinkPropertiesChanged(network, linkProperties);
}
};
}
网络工具类NetworkUtils.java
@SuppressLint("NewApi")
public class NetworkUtils {
private static final String TAG = "ConnectManager";
/**
* Indicates this network uses a Cellular transport.
*/
public static final int TRANSPORT_CELLULAR = 0;
/**
* Indicates this network uses a Wi-Fi transport.
*/
public static final int TRANSPORT_WIFI = 1;
/**
* Indicates this network uses a Bluetooth transport.
*/
public static final int TRANSPORT_BLUETOOTH = 2;
/**
* Indicates this network uses an Ethernet transport.
*/
public static final int TRANSPORT_ETHERNET = 3;
/**
* Indicates this network uses a VPN transport.
*/
public static final int TRANSPORT_VPN = 4;
/**
* Indicates this network uses a Wi-Fi Aware transport.
*/
public static final int TRANSPORT_WIFI_AWARE = 5;
/**
* Indicates this network uses a LoWPAN transport.
*/
public static final int TRANSPORT_LOWPAN = 6;
/**
* Indicates this network uses a Test-only virtual interface as a transport.
* @hide
*/
public static final int TRANSPORT_TEST = 7;
/**
* Indicates this network uses a USB transport.
*/
public static final int TRANSPORT_USB = 8;
/**
* >= Android 10(Q版本)推荐
*
* 当前使用MOBILE流量上网
*/
public static boolean isMobileNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10(Q版本)推荐
*
* 当前使用WIFI上网
*/
public static boolean isWifiNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10(Q版本)推荐
*
* 当前使用以太网上网
*/
public static boolean isEthernetNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10(Q版本)推荐
*
* NetworkCapabilities.NET_CAPABILITY_INTERNET,表示此网络应该(maybe)能够访问internet
*
* 判断当前网络可以正常上网
* 表示此连接此网络并且能成功上网。 例如,对于具有NET_CAPABILITY_INTERNET的网络,这意味着已成功检测到INTERNET连接。
*/
public static boolean isConnectedAvailableNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return false;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return false;
}
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* >= Android 10(Q版本)推荐
*
* 获取成功上网的网络类型
* value = {
* TRANSPORT_CELLULAR, 0 表示此网络使用蜂窝传输。
* TRANSPORT_WIFI, 1 表示此网络使用Wi-Fi传输。
* TRANSPORT_BLUETOOTH, 2 表示此网络使用蓝牙传输。
* TRANSPORT_ETHERNET, 3 表示此网络使用以太网传输。
* TRANSPORT_VPN, 4 表示此网络使用VPN传输。
* TRANSPORT_WIFI_AWARE, 5 表示此网络使用Wi-Fi感知传输。
* TRANSPORT_LOWPAN, 6 表示此网络使用LoWPAN传输。
* TRANSPORT_TEST, 7 指示此网络使用仅限测试的虚拟接口作为传输。
* TRANSPORT_USB, 8 表示此网络使用USB传输
* }
*/
public static int getConnectedNetworkType(Context context) {
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network network = cm.getActiveNetwork();
if (null == network) {
return -1;
}
NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
if (null == capabilities) {
return -1;
}
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return NetworkCapabilities.TRANSPORT_CELLULAR;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return NetworkCapabilities.TRANSPORT_WIFI;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
return NetworkCapabilities.TRANSPORT_BLUETOOTH;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
return NetworkCapabilities.TRANSPORT_ETHERNET;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
return NetworkCapabilities.TRANSPORT_VPN;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
return NetworkCapabilities.TRANSPORT_WIFI_AWARE;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)) {
return NetworkCapabilities.TRANSPORT_LOWPAN;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)) {
return NetworkCapabilities.TRANSPORT_USB;
}
}
return -1;
}
}
Android10之后,请使用新的API方法, 工具类可以根据业务需求去扩展, 供参考。