检查 API 29 上的互联网连接
Posted
技术标签:
【中文标题】检查 API 29 上的互联网连接【英文标题】:Check for internet connectivity on API29 【发布时间】:2019-11-04 16:03:08 【问题描述】:我使用以下方法检查互联网连接:
public boolean isInternetConnected()
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
不过,我发现 NetworkInfo
、getActiveNetworkInfo()
和 isConnected()
现在都已弃用。我在 SO 上检查了几个线程:
ConnectivityManager getNetworkInfo(int) deprecated
activeNetworkInfo.type is deprecated in API level 28
不过,它们都提供了不推荐使用的方法的答案。我一直在环顾四周,没有任何运气。是否有任何简单的方法来检查互联网连接,或者我应该继续使用我的方法并忽略已弃用的方法,因为它适用于 API29?
谢谢。
【问题讨论】:
【参考方案1】:看看.hasTransport
val networkAvailability = cm.getNetworkCapabilities(cm.activeNetwork)
if(networkAvailability !=null && networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED))
//has network
if (networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) //wifi
else if (networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) //cellular
【讨论】:
非常感谢您提供这个出色的解决方案。我真的很感激。 现实世界中有更多的连接方式【参考方案2】:这是我对 SDK 29 的解决方案:一个名为 NetworkWatcher
的类,它观察网络的变化。它提供了诸如isWifiOn
之类的原始变量,以及通过Flow 和LiveData 观察网络随时间变化的选项。
@ExperimentalCoroutinesApi
class NetworkWatcher
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
private constructor(
application: Application
)
private val connectivityManager =
application.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE)
as ConnectivityManager
// general availability of Internet over any type
var isOnline = false
get()
updateFields()
return field
var isOverWifi = false
get()
updateFields()
return field
var isOverCellular = false
get()
updateFields()
return field
var isOverEthernet = false
get()
updateFields()
return field
companion object
@Volatile
private var INSTANCE: NetworkWatcher? = null
fun getInstance(application: Application): NetworkWatcher
synchronized(this)
if (INSTANCE == null)
INSTANCE = NetworkWatcher(application)
return INSTANCE!!
@Suppress("DEPRECATION")
private fun updateFields()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
val networkAvailability =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (networkAvailability != null &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkAvailability.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
)
//has network
isOnline = true
// wifi
isOverWifi =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
// cellular
isOverCellular =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
// ethernet
isOverEthernet =
networkAvailability.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
else
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
else
val info = connectivityManager.activeNetworkInfo
if (info != null && info.isConnected)
isOnline = true
val wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
isOverWifi = wifi != null && wifi.isConnected
val cellular = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
isOverCellular = cellular != null && cellular.isConnected
val ethernet = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET)
isOverEthernet = ethernet != null && ethernet.isConnected
else
isOnline = false
isOverWifi = false
isOverCellular = false
isOverEthernet = false
fun watchNetwork(): Flow<Boolean> = watchWifi()
.combine(watchCellular()) wifi, cellular -> wifi || cellular
.combine(watchEthernet()) wifiAndCellular, ethernet -> wifiAndCellular || ethernet
fun watchNetworkAsLiveData(): LiveData<Boolean> = watchNetwork().asLiveData()
fun watchWifi(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_WIFI)
fun watchWifiAsLiveData() = watchWifi().asLiveData()
fun watchCellular(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_CELLULAR)
fun watchCellularAsLiveData() = watchCellular().asLiveData()
fun watchEthernet(): Flow<Boolean> = callbackFlowForType(NetworkCapabilities.TRANSPORT_ETHERNET)
fun watchEthernetAsLiveData() = watchEthernet().asLiveData()
private fun callbackFlowForType(@IntRange(from = 0, to = 7) type: Int) = callbackFlow
offer(false)
val networkRequest = NetworkRequest.Builder()
.addTransportType(type)
.build()
val callback = object : ConnectivityManager.NetworkCallback()
override fun onLost(network: Network?)
offer(false)
override fun onUnavailable()
offer(false)
override fun onLosing(network: Network?, maxMsToLive: Int)
// do nothing
override fun onAvailable(network: Network?)
offer(true)
connectivityManager.registerNetworkCallback(networkRequest, callback)
awaitClose connectivityManager.unregisterNetworkCallback(callback)
例如,您可以在应用程序中订阅有关手机网络状态的更新,例如:
GlobalScope.launch
NetworkWatcher.getInstance(this@MyApplication).watchNetwork().collect connected ->
Log.d("TAG", "Network In App: $connected")
或者要回答您的问题,只需阅读 Wifi 值,例如:
if (NetworkWatcher.getInstance(this@BaseApp).isOverWifi)
// do stuff
旁注:我没有一直使用getInstance()
,而是使用Koin 等DI 框架将NetworkWatcher 注入到我需要的地方。
【讨论】:
【参考方案3】:在 AndroidManifest.xml 中添加:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
现在检查网络状态:
@IntRange(from = 0, to = 3)
fun getConnectionType(context: Context): Int
var result = 0 // Returns connection type. 0: none; 1: mobile data; 2: wifi
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
val capabilities =
cm.getNetworkCapabilities(cm.activeNetwork)
if (capabilities != null)
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
result = 2
else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
result = 1
else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_***))
result = 3
else
val activeNetwork = cm.activeNetworkInfo
if (activeNetwork != null)
// connected to the internet
if (activeNetwork.type === ConnectivityManager.TYPE_WIFI)
result = 2
else if (activeNetwork.type === ConnectivityManager.TYPE_MOBILE)
result = 1
else if (activeNetwork.type === ConnectivityManager.TYPE_***)
result = 3
return result
【讨论】:
【参考方案4】:我的答案很干净,在 Kotlin 中,还可以处理不同的 API 级别
fun isOnline(): Boolean
val connectivityManager =
ContextCompat.getSystemService(DreamPad.appContext, ConnectivityManager::class.java)
connectivityManager ?: return false
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
val nw = connectivityManager.activeNetwork ?: return false
val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false
when
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
//for other device how are able to connect with Ethernet
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
//for check internet over Bluetooth
actNw.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true
else -> false
else
@Suppress("DEPRECATION")
connectivityManager.activeNetworkInfo?.isConnected ?: false
【讨论】:
以上是关于检查 API 29 上的互联网连接的主要内容,如果未能解决你的问题,请参考以下文章