Android: Check network state and WiFi SSID

Some app may need to download large file and mobile data usually is charged. To avoid inducing extra fee to the user, it should check the network type before start to download. This post shows how to check the type (mobile or WiFi) of network connection. If WiFi network is used, we can also get the local network name (SSID).

Add Persmisions

First, we add below permission in the AndroidManifest.xml file
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Check the instant Network status

We get an instance of class ConnectivityManager from system service with Context.CONNECTIVITY_SERVICE. It provide the instant network state. We call ConnectivityManager.getActiveNetwork() to have the network of the system currently use. Then we check the network type from the object NetworkCapabilites.
fun updateActiveNetworkFlags(){
   val connectivityManager = getSystemService((Context.CONNECTIVITY_SERVICE)) as ConnectivityManager
   val currentNetwork: Network? = connectivityManager.activeNetwork
   val networkCapability: NetworkCapabilities? = connectivityManager.getNetworkCapabilities(currentNetwork)
   wifiConnected = networkCapability?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ?:false
   mobileConnected = networkCapability?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ?:false

   Log.d(TAG,"Wifi network is active: $wifiConnected")
   Log.d(TAG, "Mobile network is active: $mobileConnected")
}

Class Network represents one of the networks that the device connected to. When the network is disconnected, the Network object is invalid immediately. New Network object is created if the device later reconnects to the same appliance.

Listen to network events

ConnectivityManager.getActiveNetwork() only provide the network status at the instant time. To keep monitoring the connection, we need to register a callback with ConnectivityManager.

ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) and ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback) serve different purposes.

The default Network is determined by system, which would prefers unmetered and faster network. So the system may switch the default network when it connects to a better one (from mobile to Wi-Fi).

However, some apps may interest about other Network. Build NetworkRequest object matching the required properties and call ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {

      override fun onAvailable(network : Network) {
          Log.e(TAG, "The default network is now: " + network)

      }

 
      override fun onLost(network : Network) {
          Log.e(TAG, "The application no longer has a default network. The last default network was " + network)

      }

 

      override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) {

          Log.e(TAG, "The default network changed capabilities: " + networkCapabilities)

      }

 

      override fun onLinkPropertiesChanged(network : Network, linkProperties : LinkProperties) {
          Log.e(TAG, "The default network changed link properties: " + linkProperties)

      }

  })

If there is heavy work in callback, create a thread to handling the callback function with registerNetworkCallback(NetworkRequest, NetworkCallback, Handler)
Unregister the Network Callback when is not needed .


We can check the property of the network in NetworkCapabilities:
NET_CAPABILITY_INTERNET: The network is set up to access the internet but not actually able to reach public servers
NET_CAPABILITY_NOT_METERED: the network data transfer is not metered
NET_CAPABILITY_NOT_VPN: the network isn’t a virtual private network
NET_CAPABILITY_VALIDATED: The network has actual access to the public internet. But still it maybe blocked if the IP-based filtering is used on the connected appliance.
NET_CAPABILITY_CAPTIVE_PORTAL: The network has a captive portal when it is probed

Check Wifi SSID (name)

For Android 8

Permission Manifest.permission.ACCESS_WIFI_STATE is required to access information about wifi networks.

We get WiFiManager via system service and retrieve a WiFiInto instance from WiFiManager. Then we call WiFiInfo.getSSID(). The below code snippet show the SSID is obtained inside the method NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)

// Network capabilities have changed for the network
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
   val wiFiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
   val wifiInfo : WifiInfo? = wiFiManager.connectionInfo as WifiInfo?
   if(wifiInfo != null)
       Log.d(TAG, "onCapabilitiesChanged() Connected Wifi SSID: " + wifiInfo.ssid)
}

The Logical result:
14:12:45.750  D  oonCapabilitiesChanged() Connected Wifi SSID: "AndroidWifi"

For android 9 to 11

Apart from permission Manifest.permission.ACCESS_WIFI_STATE, we also need Manifest.permission.ACCESS_FINE_LOCATION. Otherwise WifiInfo.getSSID() will return WifiManager#UNKNOWN_SSID because WiFiInfo has location sensitive information

For android 12 or above

In addition to the permission request, the NetworkCallback must be created with the flag FLAG_INCLUDE_LOCATION_INFO. And the SSID only can be obtained from the WifiInfo object returned by the method transportInfo of NetworkCapabilities instance via NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)

val networkCallback = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
   object : ConnectivityManager.NetworkCallback(ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) {
       // Network capabilities have changed for the network
       override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
           //super.onCapabilitiesChanged(network, networkCapabilities)
           val wifiInfo: WifiInfo? = networkCapabilities.transportInfo as WifiInfo?
           if(wifiInfo != null) {
               Log.d(TAG, "onCapabilitiesChanged() Connected Wifi SSID: " + wifiInfo.ssid)
           }
       }
       ……
   }
}else{
   object : ConnectivityManager.NetworkCallback() {
       
       // Network capabilities have changed for the network
       override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
           
           val wiFiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
           val wifiInfo : WifiInfo? = wiFiManager.connectionInfo as WifiInfo?
           if(wifiInfo != null)
               Log.d(TAG, "onCapabilitiesChanged() Connected Wifi SSID: " + wifiInfo.ssid)
       }
       ……
   }
}

The full code can be found in GitHub here

Reference

[1] Read network state, Connectivity, Android developers, 

https://developer.android.com/develop/connectivity/network-ops/reading-network-state

[2] WifiManager, Android developers

https://developer.android.com/reference/android/net/wifi/WifiManager#getconnectioninfo

[3] WifiInfo, Android developers

https://developer.android.com/reference/android/net/wifi/WifiInfo


留言

此網誌的熱門文章

Use okhttp to download file and show progress bar

Download File into app specific storage with Retrofit

Unzipp file with Zip4j library