Android 10 上使用WifiNetworkSpecifier 连接WiFi后http请求失败 Connection failed

2,304 阅读1分钟

问题描述:在连接设备热点的开发中,使用WifiNetworkSpecifier连上设备热点,再切换回原网络后,http请求一直报SocketException: Connection failed (OS Error: Machine is not on the network, errno = 64)

Android 10 中需要使用新的网络连接api WifiNetworkSpecifier ---

val specifier = WifiNetworkSpecifier.Builder()
  .setSsidPattern(PatternMatcher(deviceid, PatternMatcher.PATTERN_LITERAL))
  .build()

val request = NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
  //.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  //.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)//网络不受限
  //.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)//信任网络,增加这个参数让设备连接wifi之后还联网。
  .setNetworkSpecifier(specifier)
  .build()

connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

networkCallback = object : ConnectivityManager.NetworkCallback() {
  override fun onAvailable(network: Network) {
    super.onAvailable(network)
    connectivityManager.bindProcessToNetwork(network)
    Log.i("wifi", "connect success")
  }

  override fun onUnavailable() {
    super.onUnavailable()
    Log.i("wifi", "connect faild")
  }
}
connectivityManager.registerNetworkCallback(request, networkCallback)
connectivityManager.requestNetwork(request, networkCallback)

分析:在使用WifiNetworkSpecifier 连接时修改了网络配置,导致切换回原网络时,环境发生了改变,但没有重置网络配置,导致请求失败。

原因:使用 WifiNetworkSpecifier请求连接目标network时,在requestNetwork绑定NetworkCallback中,我们需要使用bindProcessToNetwork将当前进程绑定到连接的网络上,确保所有的请求连接绑定在目标network上,才能在目标netwoek上正常请求网络,因此在切换回原网络后,如未重置配置,当前app进程的所有http请求都将继续在目标network上继续进行,即使断开了连接。如果network断开连接,以这种方式创建的所有Socket都将停止工作,并且所有主机名解析都将失败。这是设计使然,app认为仍绑定到特定Network. 所以要清除绑定,使用null重新绑定network

fun unregisterNetWork() {
  connectivityManager.bindProcessToNetwork(null)
  connectivityManager.unregisterNetworkCallback(networkCallback)
}