在 Android 中获取网络类型时,我们通常先使用 ConnectivityManager.getActiveNetworkInfo() 判断是不是 Wifi , 再通过 TelephonyManager.getNetworkType() 判断具体是 3G 还是 4G。
但是,这两个函数分别在 API23(Android M)和 API24(Android N)中已经被标记为 @Deprecated。
那么,在更高版本的 Android 系统中,我们该如何判断 Wifi 和 具体的移动网络类型呢?
1. Android M 以上版本判断是不是 Wifi
先获取网络连接管理器对象,
代码语言:javascript复制ConnectivityManager connectManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
然后获取当前活动的网络对象(Network)信息:
代码语言:javascript复制Network network = connectManager.getActiveNetwork();
再获取描述当前网络对象属性(能力)的对象:
代码语言:javascript复制NetworkCapabilities capabilities = connectManager.getNetworkCapabilities(network);
通过hasCapability() 中可以获取某个网络属性的状态,下面代码判断网络是否已经连接。需要注意,连接上并不代表能访问网络,比如连接到的无线路由器没有接入互联网:
代码语言:javascript复制/**
* CnPeng:1/22/21 5:18 PM 是否已经连接到网络(连接上但不代表可以访问网络)
*/
private boolean isNetConnected(NetworkCapabilities capabilities) {
boolean hasCapability = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
Log.d(TAG, "是否已经连接到网络:" hasCapability);
return hasCapability;
}
当网络已经连接上了,那么我么再通过 hasTransport() 来判断当前连接网络类型:
代码语言:javascript复制/**
* CnPeng:1/22/21 4:14 PM 判断是不是 Wifi
*/
private boolean isWifi(NetworkCapabilities capabilities) {
boolean hasWifiTrans = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
Log.d(TAG, "连接到 Wifi网络:" hasWifiTrans "| -------------------------");
return hasWifiTrans;
}
2. Android N 以上版本判断移动网络类型
先获取存储电话机本身服务信息的对象:
代码语言:javascript复制TelephonyManager telephonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
然后通过 getDataNetworkType() 可以获取当前连接到的移动网络类型:
代码语言:javascript复制int netWorkType;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
netWorkType = telephonyManager.getDataNetworkType();
}
获取到网络类型之后,我们通常还需要区分是 2G 、3G、4G ,其对应关系如下:
NetworkType | 类型 | 说明 |
---|---|---|
GPRS | 2G(2.5) | General Packet Radia Service 114kbps |
EDGE | 2G(2.75G) | Enhanced Data Rate for GSM Evolution 384kbps |
CDMA | 2G 电信 | Code Division Multiple Access 码分多址 |
1xRTT | 2G CDMA2000 | 1xRTT (RTT - 无线电传输技术) 144kbps 2G的过渡, |
IDEN | 2G | Integrated Dispatch Enhanced Networks 集成数字增强型网络 (属于2G,来自维基百科) |
UMTS | 3G WCDMA 联通3G | Universal Mobile Telecommunication System 完整的3G移动通信技术标准 |
EVDO_0 | 3G (EVDO 全称 CDMA2000 1xEV-DO) | Evolution-Data Only (Data Optimized) 153.6kps - 2.4mbps 属于3G |
EVDO_A | 3G | 1.8mbps - 3.1mbps 属于3G过渡,3.5G |
EVDO_B | 3G EV-DO | Rev.B 14.7Mbps 下行 3.5G |
HSPA | 3G(分HSDPA,HSUPA) | High Speed Packet Access |
HSPAP | 3G | HSPAP 比 HSDPA 快些 |
HSDPA | 3.5G | 高速下行分组接入 3.5G WCDMA High Speed Downlink Packet Access 14.4mbps |
HSUPA | 3.5G | High Speed Uplink Packet Access 高速上行链路分组接入 1.4 - 5.8 mbps |
EHRPD | 3G | CDMA2000向LTE 4G的中间产物 Evolved High Rate Packet Data HRPD的升级 |
LTE | 4G | Long Term Evolution FDD-LTE 和 TDD-LTE , 3G过渡,升级版 LTE Advanced 才是4G |
3. 完整示例代码
- CpNetUtil.java
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.RequiresPermission;
import java.util.List;
/**
* CnPeng 1/22/21
* 功用:网络工具类
* 其他:
*/
class CpNetUtil {
private static final CpNetUtil ourInstance = new CpNetUtil();
private final String TAG = getClass().getSimpleName();
static CpNetUtil getInstance() {
return ourInstance;
}
private CpNetUtil() {
}
/**
* CnPeng:1/22/21 10:11 AM 官方文档参考:https://developer.android.google.cn/training/basics/network-ops/reading-network-state
*
* ConnectivityManager 管理器 | 系统连接状态:the state of connectivity in the system
* Network 当前连接的网络对象 | ,网络切换后会变更为新的 Network 对象:one of the networks that the device is currently connected to
*
* LinkProperties 网络详细信息 | 如 DNS、IP 、interface name 、proxy
* NetworkCapabilities 网络属性 | properties of a network, such as the transports (Wi-Fi, cellular, Bluetooth) and what the network is capable o
*/
@SuppressLint("MissingPermission")
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
public CpNetEnum getNetType(Context ctx) throws SecurityException {
ConnectivityManager connectManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network network = connectManager.getActiveNetwork();
NetworkCapabilities capabilities = connectManager.getNetworkCapabilities(network);
if (null == capabilities || !isNetConnected(capabilities)) {
return CpNetEnum.TYPE_NONE;
}
if (isWifi(capabilities)) {
return CpNetEnum.TYPE_WIFI;
}
} else {
NetworkInfo networkInfo = connectManager.getActiveNetworkInfo();
if (null == networkInfo) {
return CpNetEnum.TYPE_NONE;
}
if (ConnectivityManager.TYPE_WIFI == networkInfo.getType()) {
return CpNetEnum.TYPE_WIFI;
}
}
return getMobileNetType(ctx);
}
/**
* CnPeng:1/22/21 4:28 PM 获取移动数据类型
*/
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
private CpNetEnum getMobileNetType(Context ctx) throws SecurityException {
TelephonyManager telephonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
if (null == telephonyManager) {
return CpNetEnum.TYPE_NONE;
}
int netWorkType;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
netWorkType = telephonyManager.getDataNetworkType();
} else {
netWorkType = telephonyManager.getNetworkType();
}
return convert2CusNetType(netWorkType);
}
/**
* CnPeng:1/22/21 4:51 PM 将系统的网络 Type 转换成我们需要的标识
*
* GPRS : 2G(2.5) General Packet Radia Service 114kbps
* EDGE : 2G(2.75G) Enhanced Data Rate for GSM Evolution 384kbps
* CDMA : 2G 电信 Code Division Multiple Access 码分多址
* 1xRTT : 2G CDMA2000 1xRTT (RTT - 无线电传输技术) 144kbps 2G的过渡,
* IDEN : 2G Integrated Dispatch Enhanced Networks 集成数字增强型网络 (属于2G,来自维基百科)
*
* UMTS : 3G WCDMA 联通3G Universal Mobile Telecommunication System 完整的3G移动通信技术标准
* EVDO_0 : 3G (EVDO 全程 CDMA2000 1xEV-DO) Evolution - Data Only (Data Optimized) 153.6kps - 2.4mbps 属于3G
* EVDO_A : 3G 1.8mbps - 3.1mbps 属于3G过渡,3.5G
* EVDO_B : 3G EV-DO Rev.B 14.7Mbps 下行 3.5G
* HSPA : 3G (分HSDPA,HSUPA) High Speed Packet Access
* HSPAP : 3G HSPAP 比 HSDPA 快些
* HSDPA : 3.5G 高速下行分组接入 3.5G WCDMA High Speed Downlink Packet Access 14.4mbps
* HSUPA : 3.5G High Speed Uplink Packet Access 高速上行链路分组接入 1.4 - 5.8 mbps
* EHRPD : 3G CDMA2000向LTE 4G的中间产物 Evolved High Rate Packet Data HRPD的升级
*
* LTE : 4G Long Term Evolution FDD-LTE 和 TDD-LTE , 3G过渡,升级版 LTE Advanced 才是4G
*/
private CpNetEnum convert2CusNetType(int netWorkType) {
switch (netWorkType) {
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
return CpNetEnum.TYPE_2G;
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_EHRPD:
return CpNetEnum.TYPE_3G;
case TelephonyManager.NETWORK_TYPE_LTE:
case 19: // 19 对应的是 NETWORK_TYPE_LTE_CA,被标记为 hide 了,所以直接使用 19 判断
return CpNetEnum.TYPE_4G;
case TelephonyManager.NETWORK_TYPE_NR:
return CpNetEnum.TYPE_5G;
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
default:
return CpNetEnum.TYPE_OTHER;
}
}
/**
* CnPeng:1/22/21 4:14 PM 判断是不是 Wifi
*/
private boolean isWifi(NetworkCapabilities capabilities) {
boolean hasWifiTrans = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
Log.d(TAG, "连接到 Wifi网络:" hasWifiTrans "| -------------------------");
return hasWifiTrans;
}
/**
* CnPeng:1/25/21 8:38 AM 是不是蜂窝网络(即移动数据网络)
* 注意:这个不准确,打开 Wifi 开关,但未连接到任意网络时,此处会返回 true
*/
private boolean isCellular(NetworkCapabilities capabilities) {
boolean isCellular = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
Log.d(TAG, "连接到的是移动数据网络:" isCellular);
return isCellular;
}
/**
* CnPeng:1/25/21 8:36 AM 是否可以进行网络访问
*/
@TargetApi(23)
private boolean isNetValidated(NetworkCapabilities capabilities) {
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
}
/**
* CnPeng:1/22/21 5:18 PM 是否已经连接到网络(连接上但不代表可以访问网络)
*/
private boolean isNetConnected(NetworkCapabilities capabilities) {
boolean hasCapability = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
Log.d(TAG, "是否已经连接到网络:" hasCapability);
return hasCapability;
}
/**
* CnPeng:1/22/21 4:15 PM 获取 IP 地址等信息
*/
private void getLinkProperties(ConnectivityManager connectManager, Network curNetObj) {
LinkProperties linkProperties = connectManager.getLinkProperties(curNetObj);
List<LinkAddress> linkAddresses = linkProperties.getLinkAddresses();
if (null != linkAddresses && !linkAddresses.isEmpty()) {
// 包含 IPV4 和 IPV6 两种地址
for (LinkAddress linkAddress : linkAddresses) {
String hostAddress = linkAddress.getAddress().getHostAddress();
Log.d(TAG, "主机地址:" hostAddress);
}
}
}
}
- CpNetEnum.java
/**
* CnPeng 1/22/21
* 功用:自定义的网络类型
* 其他:
*/
enum CpNetEnum {
//CnPeng:1/22/21 4:26 PM 无网络
TYPE_NONE(-1),
//CnPeng:1/22/21 4:26 PM 其他网络类型
TYPE_OTHER(0),
TYPE_WIFI(1),
TYPE_2G(2),
TYPE_3G(3),
TYPE_4G(4),
TYPE_5G(5);
private final int value;
CpNetEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
- MainActivity.java
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 666);
} else {
CpNetEnum netType = CpNetUtil.getInstance().getNetType(this);
Log.d("MainActivity", netType.name());
}
// 不确定是否已经申请权限时,需要做如下 try catch.
// try {
// GxtNetEnum netType = GxtNetUtil.getInstance().getNetType(this);
// Log.d("MainActivity", netType.name());
// } catch (SecurityException e) {
// e.printStackTrace();
// }
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 666 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@SuppressLint("MissingPermission")
CpNetEnum netType = CpNetUtil.getInstance().getNetType(this);
Log.d("MainActivity", netType.name());
} else {
Log.d("MainActivity", "权限被拒绝了");
}
}
}