最近在写一个小工具,需要判断用户是否开启了便携式热点(Wi-Fi 热点),发现 Android 系统并没有提供直接的公开 API 来判断热点状态,遂调研了一下实现方案并记录。
WifiManager 反射调用
虽然 Android 没有提供公开 API 来判断热点状态,但可以通过反射调用 WifiManager 的隐藏方法来实现。
fun isHotspotEnabled(context: Context): Boolean {
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
return try {
val method: Method = wifiManager.javaClass.getDeclaredMethod("isWifiApEnabled")
method.isAccessible = true
method.invoke(wifiManager) as Boolean
} catch (e: Exception) {
e.printStackTrace()
false
}
}
isWifiApEnabled 被标记为 @hide,它内部是调用 getWifiApState 方法来判断热点状态的。
@SystemService(Context.WIFI_SERVICE)
public class WifiManager {
...
/**
* Return whether tethered Wi-Fi AP is enabled or disabled.
* @return {@code true} if tethered Wi-Fi AP is enabled
* @see #getWifiApState()
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public boolean isWifiApEnabled() {
return getWifiApState() == WIFI_AP_STATE_ENABLED;
}
}
如果我们需要区分热点状态值,也可以通过反射调用 getWifiApState 方法来获取,返回值为 int 类型,定义如下:
@SystemService(Context.WIFI_SERVICE)
public class WifiManager {
...
@SystemApi
public static final int WIFI_AP_STATE_DISABLING = 10;
@SystemApi
public static final int WIFI_AP_STATE_DISABLED = 11;
@SystemApi
public static final int WIFI_AP_STATE_ENABLING = 12;
@SystemApi
public static final int WIFI_AP_STATE_ENABLED = 13;
@SystemApi
public static final int WIFI_AP_STATE_FAILED = 14;
}
望文生义,不用过多解释了。
TetheringManager 监听
Android 16 TetheringManager 提供了更规范的 API 来监控热点状态。
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun registerTetheringCallback(context: Context, onHotspotStateChanged: (Boolean) -> Unit) {
val tetheringManager = context.getSystemService(Context.TETHERING_SERVICE) as TetheringManager
tetheringManager.registerTetheringEventCallback(
Runnable::run,
object : TetheringManager.TetheringEventCallback {
override fun onTetheredInterfacesChanged(interfaces: MutableSet<TetheringInterface>) {
onHotspotStateChanged(interfaces.isNotEmpty())
}
}
)
}
它相比上面的反射调用更加灵活,但需要更新的设备支持,目前来说应用较少。
