1. 程式人生 > 其它 >Android | 網路型別判斷工具類

Android | 網路型別判斷工具類

技術標籤:Androidandroid移動開發

歡迎關注我的公眾號:CnPeng ,工作日 8:08 準時更新。

在 Android 中獲取網路型別時,我們之前通常是先使用 ConnectivityManager.getActiveNetworkInfo() 判斷是不是 Wifi , 然後通過 TelephonyManager.getNetworkType() 判斷具體是 3G 還是 4G。

但是,這兩個函式分別在 API23(Android M)和 API24(Android N)中已經被標記為 @Deprecated

那麼,在更高版本的 Android 系統中,我們該如何判斷 Wifi 和 具體的行動網路型別呢?

1.1 Android M 以上版本判斷是不是 Wifi

先獲取網路連線管理器 ConnectivityManager 物件,

ConnectivityManager connectManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);

然後獲取當前活動的網路物件(Network)資訊:

Network network = connectManager.getActiveNetwork();

再獲取描述當前網路物件屬性(能力)的 NetworkCapabilities 物件:

NetworkCapabilities capabilities =
connectManager.getNetworkCapabilities(network);

通過 NetworkCapabilities.hasCapability() 中可以獲取某個網路屬性的狀態,下面程式碼判斷網路是否已經連線。需要注意,連線上並不代表能訪問網路,比如連線到的無線路由器沒有接入網際網路:

/**
 * 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; }

當網路已經連線上了,那麼我麼再通過 NetworkCapabilities.hasTransport() 來判斷當前連線網路型別:


/**
 * 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;
}

1.2 Android N 以上版本判斷行動網路型別

先獲取 TelephonyManager 物件,該物件提供了電話機本身的一些服務資訊:

TelephonyManager telephonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);

然後通過 TelephonyManager.getDataNetworkType() 可以獲取當前連線到的行動網路型別:

int netWorkType;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    netWorkType = telephonyManager.getDataNetworkType();
} 

獲取到網路型別之後,我們通常還需要區分是 2G 、3G、4G ,其對應關係如下:

NetworkType型別說明
GPRS2G(2.5)General Packet Radia Service 114kbps
EDGE2G(2.75G)Enhanced Data Rate for GSM Evolution 384kbps
CDMA2G 電信Code Division Multiple Access 分碼多重進接
1xRTT2G CDMA20001xRTT (RTT - 無線電傳輸技術) 144kbps 2G的過渡,
IDEN2GIntegrated Dispatch Enhanced Networks 整合數字增強型網路 (屬於2G,來自維基百科)
UMTS3G WCDMA 聯通3GUniversal Mobile Telecommunication System 完整的3G移動通訊技術標準
EVDO_03G (EVDO 全稱 CDMA2000 1xEV-DO)Evolution - Data Only (Data Optimized) 153.6kps - 2.4mbps 屬於3G
EVDO_A3G1.8mbps - 3.1mbps 屬於3G過渡,3.5G
EVDO_B3G EV-DORev.B 14.7Mbps 下行 3.5G
HSPA3G (分HSDPA,HSUPA)High Speed Packet Access
HSPAP3GHSPAP 比 HSDPA 快些
HSDPA3.5G高速下行分組接入 3.5G WCDMA High Speed Downlink Packet Access 14.4mbps
HSUPA3.5GHigh Speed Uplink Packet Access 高速上行鏈路分組接入 1.4 - 5.8 mbps
EHRPD3GCDMA2000向LTE 4G的中間產物 Evolved High Rate Packet Data HRPD的升級
LTE4GLong Term Evolution FDD-LTETDD-LTE , 3G過渡,升級版 LTE Advanced 才是4G

1.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", "許可權被拒絕了");
        }
    }
}

在這裡插入圖片描述