提问人:moonlightcheese 提问时间:11/17/2023 更新时间:11/17/2023 访问量:12
如果启用了 VPN,如何获取 WiFi 的 SSID?
How to get SSID of WiFi if VPN is enabled?
问:
我已注册 .手机已打开并连接了 WiFi,但是当我调用它时,它会给出一个类名,而该类名在我可以找到的 Android SDK 文档中不存在。如果设备通过 VPN 连接,如何获取 SSID?为什么这个类不在文档中?NetworkCallback
connectivityManager.registerDefaultNetworkCallback(networkCallback)
capabilities.transportInfo!!::class.qualifiedName
android.net.VpnTransportInfo
初始化:
private val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build()
init {
//upon register, callback will be called, so no need to initialize
//registerDefaultNetworkCallback does not call back with a WifiInfo when using VPN
//connectivityManager.registerDefaultNetworkCallback(networkCallback)
//should return only WifiInfo as TransportInfo since networkRequest only requests Wifi transport type
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
}
NetworkCallback 实现:
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
logger.warn("NETWORK AVAILABLE: $network")
_connectivityState.update {
getConnectivityState()
}
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
logger.warn("NETWORK CAPABILITIES CHANGED: $network")
_connectivityState.update {
getConnectivityState()
}
}
override fun onLost(network: Network) {
super.onLost(network)
logger.warn("NETWORK LOST: $network")
_connectivityState.update {
getConnectivityState()
}
}
}
getConnectivity 实现:
fun getConnectivityState(
network: Network? = connectivityManager.getActiveNetwork()
): ConnectivityState {
//these objects represent information about the currently active network
val capabilities = connectivityManager.getNetworkCapabilities(network)
val linkProperties = connectivityManager.getLinkProperties(network)
val connectivityState = ConnectivityState()
if(wifiManager.isWifiEnabled) {
//if wifi is enabled, it should be the current active network
val isWifi = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
if(isWifi != null) {
if(isWifi) {
//the current active link is a WiFi connection
logger.info("Network is WiFi.")
connectivityState.source = ConnectivitySource.WIFI
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
logger.info("Version code: ${Build.VERSION.SDK_INT} >= ${Build.VERSION_CODES.S}, using capabilities.getTransportInfo()")
val transportInfo = capabilities.transportInfo
logger.info("Got TransportInfo")
if(transportInfo is WifiInfo) {
logger.info("TransportInfo 'is' WifiInfo")
connectivityState.ssid = transportInfo.ssid
logger.info("WifiInfo SSID" + connectivityState.ssid)
} else {
logger.info("TransportInfo 'is NOT' WifiInfo (" + transportInfo!!::class.qualifiedName + ")")
}
} else {
logger.info("Version code: ${Build.VERSION.SDK_INT} < ${Build.VERSION_CODES.S}, using wifiManager.connectionInfo")
//old method of obtaining WifiInfo through ConnectivityManager
val wifiInfo = wifiManager.connectionInfo
connectivityState.ssid = wifiInfo.ssid
logger.info("WifiInfo SSID" + connectivityState.ssid)
}
} else {
//the current link does not have the WiFi transport classification
logger.info("WiFi is enabled but network link is NOT WiFi!")
}
} else {
//can't get information about wifi?
logger.error("Unable to discover if network is WiFi! Transport == WiFi returned null.")
}
} else {
//wifi is disabled, but should probably be enabled for the app to connect
logger.warn("WiFi is disabled!")
}
val isCellular = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
if(isCellular != null) {
if(isCellular) {
logger.info("Network is cellular data.")
connectivityState.source = ConnectivitySource.CELLULAR
} else {
logger.info("Network is NOT cellular data.")
}
} else {
logger.error("Unable to discover if network is cellular! Transport == cellular returned null.")
}
return connectivityState
}
相关日志行,为便于阅读而缩写:
NETWORK CAPABILITIES CHANGED: 272
Network is WiFi.
Version code: 34 >= 31, using capabilities.getTransportInfo()
Got TransportInfo
TransportInfo 'is NOT' WifiInfo (android.net.VpnTransportInfo)
Network is NOT cellular data.
答:
0赞
LPanic
11/25/2023
#1
类 android.net.VpnTransportInfo 未记录在公共 SDK 中,它似乎是一个内部类或隐藏 API 的一部分。这可能就是您在官方 Android 文档中找不到有关它的信息的原因。
要在设备通过 VPN 连接时获取 SSID,可以考虑使用替代方法。您可以使用 ConnectivityManager.getNetworkInfo(network) 方法获取有关网络的信息,然后将其强制转换为 WifiInfo 以获取 SSID,而不是依赖于 capabilities.transportInfo 属性。
我已经修改了您的代码,您可能想尝试一下:
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
super.onCapabilitiesChanged(network, networkCapabilities)
logger.warn("NETWORK CAPABILITIES CHANGED: $network")
_connectivityState.update {
getConnectivityState(network)
}
}
// Modify getConnectivityState to take a network parameter
fun getConnectivityState(network: Network?): ConnectivityState {
val capabilities = connectivityManager.getNetworkCapabilities(network)
val linkProperties = connectivityManager.getLinkProperties(network)
val connectivityState = ConnectivityState()
if (wifiManager.isWifiEnabled) {
val isWifi = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
if (isWifi != null && isWifi) {
val networkInfo = connectivityManager.getNetworkInfo(network)
if (networkInfo != null && networkInfo.type == ConnectivityManager.TYPE_WIFI) {
// Cast to WifiInfo and get the SSID
val wifiInfo = networkInfo.extraInfo as? WifiInfo
if (wifiInfo != null) {
connectivityState.ssid = wifiInfo.ssid
logger.info("WifiInfo SSID: ${connectivityState.ssid}")
} else {
logger.error("Failed to cast extraInfo to WifiInfo")
}
}
}
}
// ... (remaining code)
return connectivityState
}
In this modified code, getNetworkInfo(network) is used to obtain a NetworkInfo object, and extraInfo is then cast to WifiInfo to get the SSID. This approach should be more reliable and should work whether the device is connected through a VPN or not.
请注意,此方法假定 Wi-Fi 网络的网络类型ConnectivityManager.TYPE_WIFI。
评论
0赞
moonlightcheese
11/27/2023
你提到的方法在 API 29 中已弃用。我正在使用 minSDK = 28 进行编译,但想使用未弃用的方法来获取 SSID 信息。似乎 Android 团队忽略了在 VPN 后面获取 SSID 的这种范式,因为我没有找到有关如何使用新类来实现此效果的信息。Network
评论