启用VPN时如何获取WiFi的SSID?Android VpnTransportInfo文档疑问
一、VpnTransportInfo未出现在SDK文档的原因
android.net.VpnTransportInfo是Android系统的隐藏内部类,属于框架层私有实现,并未对外公开到官方SDK中。这类内部类用于系统底层处理VPN传输逻辑,Google不对外暴露是为了避免应用依赖系统内部细节,防止后续系统版本更新时因内部实现变更导致应用兼容性问题。所以你只能在运行时通过类型判断看到它,但官方文档不会收录,也不建议直接依赖它。
二、VPN连接时获取WiFi SSID的方法
当设备通过VPN连接时,当前活跃网络是VPN网络(因此getActiveNetwork()返回的是VPN网络,对应的transportInfo是VpnTransportInfo),但WiFi本身仍处于连接状态,你可以通过以下两种方式获取WiFi的SSID:
方法1:直接通过WifiManager获取
只要WiFi处于连接状态,不管当前活跃网络是不是VPN,WifiManager都能直接返回当前连接的WiFi信息:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val wifiInfo = wifiManager.connectionInfo if (wifiInfo.ssid != WifiManager.UNKNOWN_SSID) { connectivityState.ssid = wifiInfo.ssid } } else { val wifiInfo = wifiManager.connectionInfo connectivityState.ssid = wifiInfo.ssid }
注意权限:从Android 10开始,获取WiFi SSID需要申请ACCESS_FINE_LOCATION权限,且用户必须授予该权限,同时设备的位置服务需要处于开启状态(部分厂商可能有额外限制)。
方法2:遍历所有网络,筛选出WiFi类型的网络
系统中同时存在WiFi网络和VPN网络,你可以遍历ConnectivityManager管理的所有网络,找到标记为TRANSPORT_WIFI的网络,再获取它的WifiInfo:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { connectivityManager.allNetworks.forEach { network -> val caps = connectivityManager.getNetworkCapabilities(network) if (caps?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true) { val transportInfo = caps.transportInfo if (transportInfo is WifiInfo) { connectivityState.ssid = transportInfo.ssid return@forEach // 找到第一个WiFi网络就退出遍历 } } } }
这种方法不依赖活跃网络,直接定位到WiFi网络本身,能更准确获取WiFi的SSID。
针对你代码的修改建议
你当前的getConnectivityState方法依赖getActiveNetwork(),而VPN激活时活跃网络是VPN,所以拿到的是VpnTransportInfo。可以修改逻辑:
- 优先尝试通过
WifiManager.connectionInfo获取SSID; - 如果失败,再遍历所有网络找WiFi网络的
TransportInfo。
修改后的getConnectivityState关键部分示例:
if(wifiManager.isWifiEnabled) { val isWifi = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) if(isWifi != null && isWifi) { connectivityState.source = ConnectivitySource.WIFI // 优先用WifiManager获取SSID val wifiInfo = wifiManager.connectionInfo if (wifiInfo.ssid != WifiManager.UNKNOWN_SSID) { connectivityState.ssid = wifiInfo.ssid logger.info("WifiInfo SSID: ${connectivityState.ssid}") } else { // 备选:遍历所有网络找WiFi网络 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { connectivityManager.allNetworks.forEach { network -> val caps = connectivityManager.getNetworkCapabilities(network) if (caps?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true) { val transportInfo = caps.transportInfo if (transportInfo is WifiInfo) { connectivityState.ssid = transportInfo.ssid logger.info("WifiInfo SSID from network list: ${connectivityState.ssid}") return@forEach } } } } } } }
内容的提问来源于stack exchange,提问作者moonlightcheese

