如何在安卓系统中查看Wi-Fi是否已连接?

255

我不希望用户在没有连接Wi-Fi的情况下尝试下载任何东西。然而,我似乎只能判断Wi-Fi是否可用,但他们仍然可能有3G连接。

android.net.wifi.WifiManager m = (WifiManager) getSystemService(WIFI_SERVICE);
android.net.wifi.SupplicantState s = m.getConnectionInfo().getSupplicantState();
NetworkInfo.DetailedState state = WifiInfo.getDetailedStateOf(s);
if (state != NetworkInfo.DetailedState.CONNECTED) {
    return false;
}

然而状态并不如我所预期。即使Wi-Fi已连接,我仍然在获取IP地址时得到OBTAINING_IPADDR的状态。


1
2021年工作解决方案:https://stackoverflow.com/questions/66573565/android-get-status-of-wifi-connection/66648761 - Sam Chen
24个回答

482

您可以使用ConnectivityManager来获取Wi-Fi适配器的状态。从那里,您可以检查它是否已连接或可用

ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

if (mWifi.isConnected()) {
    // Do whatever
}

注意: 需要注意的是,对于我们这些新手来说,你需要添加

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

为使其正常工作,需要在AndroidManifest.xml中进行配置。

注意2public NetworkInfo getNetworkInfo (int networkType)现已过时:

此方法在API级别23中已过时。该方法不支持相同类型的多个连接网络。请改用getAllNetworks()和getNetworkInfo(android.net.Network)。

注意3public static final int TYPE_WIFI现已过时:

此常量在API级别28中已过时。应用程序应使用NetworkCapabilities.hasTransport(int)或requestNetwork(NetworkRequest,NetworkCallback)请求适当的网络。对于受支持的传输方式。


75
需要注意的是(特别是对于我们这些新手),为了使其正常工作,您需要将 android.permission.ACCESS_NETWORK_STATE 添加到您的 AndroidManifest.xml 文件中。 - mgalgs
10
在最近的Android版本中,您需要检查mWiFi是否为NULL......您所编写的代码可能会抛出空指针错误。请参见http://developer.android.com/training/basics/network-ops/managing.html,特别是“The method getActiveNetworkInfo()返回NetworkInfo......” - eb80
1
它对我使用以太网接口也有效。我只是更改为ConnectivityManager.TYPE_ETHERNET - MBH
3
方法 NetworkInfo.isConnected() 在 API-23 中已被弃用。 我在下面发布了一个解决方案。 - revolutionary
4
API 28中已经弃用了NetworkInfo.getType()ConnectivityManager.TYPE_WIFI。为了避免lint警告,你应该使用类似于connectivityManager.getNetworkCapabilities(network).hasTransport(NetworkCapabilities.TRANSPORT_WIFI)的东西。 - Vadik Sirekanyan
显示剩余5条评论

92

由于方法NetworkInfo.isConnected()API-23已被弃用,因此这里提供了一种使用WifiManager检测Wi-Fi适配器是否打开并连接到访问点的方法:

private boolean checkWifiOnAndConnected() {
    WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);

    if (wifiMgr.isWifiEnabled()) { // Wi-Fi adapter is ON

        WifiInfo wifiInfo = wifiMgr.getConnectionInfo();

        if( wifiInfo.getNetworkId() == -1 ){
            return false; // Not connected to an access point
        }
        return true; // Connected to an access point
    }
    else {
        return false; // Wi-Fi adapter is OFF
    }
}

5
值得提及的是,wifiInfo可能为空,所以在获取网络ID之前,应该先检查是否为null。 - Nonos
2
NetworkInfo.isConnected() 对我来说看起来并没有被弃用。 - EricRobertBrewer
2
不要忘记添加权限:android.permission.ACCESS_WIFI_STATE - Ton Snoei
1
在Android Q中,如果没有开启位置权限和位置模式,此功能将无法使用,请参见https://issuetracker.google.com/issues/136021574。 - Konsumierer
1
@EricRobertBrewer的评论已经过时了。现在它是被API 29+弃用的。 - nuKs

37

我只是简单地使用以下代码:

SupplicantState supState; 
wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
supState = wifiInfo.getSupplicantState();

调用getSupplicantState()方法时,将返回以下状态之一:

ASSOCIATED - 关联已完成。

ASSOCIATING - 正在尝试与接入点关联。

COMPLETED - 所有认证已完成。

DISCONNECTED - 此状态表示客户端未关联,但很可能会开始寻找接入点。

DORMANT - Android添加的状态,在客户端发出明确的DISCONNECT命令时报告。

FOUR_WAY_HANDSHAKE - WPA 4路握手正在进行中。

GROUP_HANDSHAKE - WPA组密钥握手正在进行中。

INACTIVE - 不活动状态。

INVALID - 一个伪状态,通常不应该被看到。

SCANNING - 正在扫描网络。

UNINITIALIZED - 没有连接。


嗨Donal,我已经使用同样的方法来获取我们的设备是否连接到WiFi。但是我还需要知道当前正在使用WiFi的应用程序名称。如何做到这一点? - AbhishekB
我对这个解决方案持怀疑态度,因为只有在使用WPA(或某种变体的WPA)时才会使用supplicant:如果用户连接到没有认证或WEP的AP,则不涉及supplicant。 - Tom
这确实是真的,如果不需要提供者信息,Jason Knight的解决方案更好。 - Donal Rafferty
2
即使我没有连接WiFi,它仍然显示为“已完成”。 - Evan Parsons
1
以上提到的状态是否有任何系统广播意图?@DonalRafferty - Rohit Singh
显示剩余2条评论

21

我在我的应用程序中使用以下代码来检查当前的网络是否为 Wi-Fi:

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI)
{

    // Do your work here

}

这是最佳答案,因为它确保“活动”网络(用于下载的网络)是WiFi。 - Gavriel
1
由于NetworkInfo#isConnected已被弃用,它也是目前最佳的答案。 - Tash Pemhiwa
无疑是今年(2017年)最佳答案。 - Daniel Nugent
最佳解决方案也适用于2020年,因为Android Q要求对本帖中某些解决方案进行位置权限请求。这种方法无需位置权限即可运行。 - JOSEMAFUEN

18

我看了几个类似的问题,得出了这个答案:

ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = connManager .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

if (wifi.isConnected()){
    // If Wi-Fi connected
}

if (mobile.isConnected()) {
    // If Internet connected
}

我在Root Toolbox PRO中使用if进行许可证检查,它看起来运行良好。


8
看起来不错,但我不确定为什么要获取第二个ConnectivityManager引用。在这个例子中,connManager和connManager1都是同一个对象。 - Nathan Schwermann
1
TYPE_MOBILE是指3G网络还是GPRS网络? - herbertD
1
TYPE_MOBILE表示使用您的运营商进行的任何数据-2G(GPRS ...),3G(HSDPA ...)或4G(LTE ...)。 - Eugen Pechanec
1
当将安卓设备连接到以太网时,添加 TYPE_ETHERNET 可以很好地工作。 - MBH
1
值得注意的是,如果网络不存在,则 getNetworkInfo() 将返回 null。因此,如果设备没有移动连接,这将抛出错误。在大多数情况下,由于大多数设备没有以太网连接,因此 TYPE_ETHERNET 在这种情况下会导致 null。 - Knossos

11

自 API 级别 29 开始,NetworkInfo 类和相关的访问方法ConnectivityManager#getNetworkInfo()ConnectivityManager#getActiveNetworkInfo() 已被弃用。

现在的文档建议使用ConnectivityManager.NetworkCallback API 来进行异步回调监控,或者使用ConnectivityManager#getNetworkCapabilitiesConnectivityManager#getLinkProperties 来实时获取网络信息。

呼叫者应改为使用 ConnectivityManager.NetworkCallback API 了解连接更改,或切换到使用 ConnectivityManager#getNetworkCapabilities 或 ConnectivityManager#getLinkProperties 来同步获取信息。


以下是我用来检查 WiFi 是否已连接的代码:

Kotlin:

val connMgr = applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
connMgr?: return false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val network: Network = connMgr.activeNetwork ?: return false
    val capabilities = connMgr.getNetworkCapabilities(network)
    return capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
} else {
    val networkInfo = connMgr.activeNetworkInfo ?: return false
    return networkInfo.isConnected && networkInfo.type == ConnectivityManager.TYPE_WIFI
}

Java:

ConnectivityManager connMgr = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connMgr == null) {
    return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    Network network = connMgr.getActiveNetwork();
    if (network == null) return false;
    NetworkCapabilities capabilities = connMgr.getNetworkCapabilities(network);
    return capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
} else {
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    return networkInfo.isConnected() && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
}

记得在您的清单文件中添加权限ACCESS_NETWORK_STATE


7

尽管Jason的回答是正确的,但现在getNetWorkInfo(int)是一个弃用的方法。因此,下一个函数将是一个不错的替代方案:

public static boolean isWifiAvailable (Context context)
{
    boolean br = false;
    ConnectivityManager cm = null;
    NetworkInfo ni = null;

    cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    ni = cm.getActiveNetworkInfo();
    br = ((null != ni) && (ni.isConnected()) && (ni.getType() == ConnectivityManager.TYPE_WIFI));

    return br;
}

4

这适用于Q之前和之后的Android设备

fun isWifiConnected(context: Context):Boolean {
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
             capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)==true
        } else {
            val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
            activeNetwork?.typeName?.contains("wifi",ignoreCase = true)?:false
        }
}

4
许多答案使用已弃用的代码或仅适用于更高的API版本。现在我使用类似以下的代码:
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if(connectivityManager != null) {
            for (Network net : connectivityManager.getAllNetworks()) {
                NetworkCapabilities nc = connectivityManager.getNetworkCapabilities(net);
                if (nc != null && nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                        && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET))
                    return true;
            }
        }
        return false;

4
以下 Kotlin 代码适用于 API 21 至至少当前 API 版本(API 29)。getWifiState() 函数返回 WiFi 网络状态的三个可能值之一:Disable、EnabledNotConnected 和 Connected,这些值在一个枚举类中定义。这允许进行更精细的决策,例如通知用户启用 WiFi 或者如果已经启用,则连接到可用网络之一。但如果只需要指示 WiFi 接口是否连接到网络的布尔值,则另一个函数 isWifiConnected() 将为您提供此信息。它使用前面的函数并将结果与 Connected 进行比较。 该代码受以前答案的启发,但试图解决 Android API 的演变或 IP V6 缓慢增加可用性所带来的问题。其诀窍是使用:
wifiManager.connectionInfo.bssid != null 

替代方式:

  1. getIpAddress() == 0 只适用于IP V4或
  2. getNetworkId() == -1 现在需要另一种特殊权限(位置)

根据文档:https://developer.android.com/reference/kotlin/android/net/wifi/WifiInfo.html#getbssid,如果未连接到网络,则返回null。即使我们没有权限获取真实值,如果我们已连接,则它仍会返回其他非null值。

还要注意以下内容:

在 android.os.Build.VERSION_CODES#N之前的版本中,此对象 应该只从 Context#getApplicationContext() 获取,而不应从任何其他派生上下文获取,以避免在调用进程内存泄漏。

在清单文件中,请不要忘记添加:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

提出的代码如下:

class MyViewModel(application: Application) : AndroidViewModel(application) {

   // Get application context
    private val myAppContext: Context = getApplication<Application>().applicationContext

   // Define the different possible states for the WiFi Connection
    internal enum class WifiState {
        Disabled,               // WiFi is not enabled
        EnabledNotConnected,    // WiFi is enabled but we are not connected to any WiFi network
        Connected,              // Connected to a WiFi network
    }

    // Get the current state of the WiFi network
    private fun getWifiState() : WifiState {

        val wifiManager : WifiManager = myAppContext.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

        return if (wifiManager.isWifiEnabled) {
                    if (wifiManager.connectionInfo.bssid != null)
                        WifiState.Connected
                    else
                        WifiState.EnabledNotConnected
               } else {
                    WifiState.Disabled
               }
    }

    // Returns true if we are connected to a WiFi network
    private fun isWiFiConnected() : Boolean {
        return (getWifiState() == WifiState.Connected)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接