Android | 网络类型判断工具类

2021-02-03 15:12:30 浏览数 (1)

在 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
代码语言:javascript复制
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
代码语言:javascript复制
/**
 * 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
代码语言:javascript复制
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", "权限被拒绝了");
        }
    }
}

0 人点赞