依赖
implementation 'com.linkedin.dexmaker:dexmaker:2.28.1'
权限
public abstract class MyOnStartTetheringCallback {
public abstract void onTetheringStarted();
public abstract void onTetheringFailed();
}
import android.content.Context
import android.net.ConnectivityManager
import android.net.wifi.SoftApConfiguration
import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiManager
import android.os.Build
import android.os.Handler
import android.text.TextUtils
import android.util.Log
import com.android.dx.stock.ProxyBuilder
import java.io.File
import java.lang.reflect.InvocationHandler
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.util.*
class WifiApUtil {
var wifiManager: WifiManager? = null
private var mConnectivityManager: ConnectivityManager? = null
private var startTetheringCallback: MyOnStartTetheringCallback? = null
var isHotSpotApOpen: Boolean = false
private val BAND_5GHZ = 1 shl 1
fun startWifiApBySoftApCfg(name: String?, pwd: String?,context: Context) {
val wifiManager = context.let {
it.getSystemService(Context.WIFI_SERVICE) as WifiManager
}
try {
val softApCfgBuilderClz = Class.forName("android.net.wifi.SoftApConfiguration\$Builder")
val softApCfgBuilder = softApCfgBuilderClz.newInstance()
val setSsidMethod = softApCfgBuilderClz.getMethod(
"setSsid",
String::class.java
)
setSsidMethod.invoke(softApCfgBuilder, name)
val setPassphraseMethod = softApCfgBuilderClz.getMethod(
"setPassphrase",
String::class.java,
Int::class.javaPrimitiveType
)
setPassphraseMethod.invoke(
softApCfgBuilder,
pwd,
SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
)
val setBandMethod =
softApCfgBuilderClz.getMethod("setBand", Int::class.javaPrimitiveType)
setBandMethod.invoke(softApCfgBuilder, BAND_5GHZ)
val setAutoShutdownEnabledMethod =
softApCfgBuilderClz.getMethod("setAutoShutdownEnabled", Boolean::class.javaPrimitiveType)
setAutoShutdownEnabledMethod.invoke(softApCfgBuilder, false)
// val setChannelMethod =
// softApCfgBuilderClz.getMethod("setChannel", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType)
// setChannelMethod.invoke(softApCfgBuilder, 130, BAND_5GHZ)
val buildMethod = softApCfgBuilderClz.getMethod("build")
val softApCfg = buildMethod.invoke(softApCfgBuilder)
val softApCfgClass = Class.forName("android.net.wifi.SoftApConfiguration")
val setSoftApConfiguration =
wifiManager?.javaClass?.getMethod("setSoftApConfiguration", softApCfgClass)
setSoftApConfiguration?.invoke(wifiManager, softApCfg)
} catch (e: ClassNotFoundException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InstantiationException) {
e.printStackTrace()
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
}
fun startWifiAp(name: String, password: String,context: Context) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
startWifiApBySoftApCfg(name, password,context)
} else {
startWifiApByWifiApCfg(name, password,context)
}
}
fun startWifiApByWifiApCfg(name: String, password: String,context: Context) {
try {
val wifiManager = context.applicationContext
?.getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiConfiguration = WifiConfiguration()
if (!TextUtils.isEmpty(name)) {
wifiConfiguration.SSID = name
}
wifiConfiguration.allowedKeyManagement.set(4)
wifiConfiguration.allowedAuthAlgorithms.set(0)
if (!TextUtils.isEmpty(password)) {
wifiConfiguration.preSharedKey = password
}
val wifiManagerClass: Class = wifiManager.javaClass
val setWifiApConfigurationMethod = wifiManagerClass.getMethod(
"setWifiApConfiguration",
WifiConfiguration::class.java
)
val res = setWifiApConfigurationMethod.invoke(wifiManager, wifiConfiguration)
Log.d(TAG, "startWifiAp: res = $res")
} catch (e: java.lang.Exception) {
Log.d(TAG, "EnableAp: Exception")
e.printStackTrace()
}
}
companion object {
private const val TAG = "WifiApConnector"
private var wifiApUtil: WifiApUtil? = null
fun getInstance(context: Context): WifiApUtil? {
if (wifiApUtil == null) {
wifiApUtil = WifiApUtil()
wifiApUtil!!.wifiManager =
context.applicationContext!!
.getSystemService(Context.WIFI_SERVICE) as WifiManager
wifiApUtil!!.mConnectivityManager =
context.applicationContext!!
.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
return wifiApUtil
}
}
fun isTetherActive(): Boolean {
try {
val method: Method? =
mConnectivityManager?.javaClass?.getDeclaredMethod("getTetheredIfaces")
if (method == null) {
Log.e(TAG, "getTetheredIfaces is null")
} else {
val res = method.invoke(mConnectivityManager) as Array
Log.d(TAG, "getTetheredIfaces invoked")
Log.d(TAG, Arrays.toString(res))
if (res.isNotEmpty()) {
return true
}
}
} catch (e: java.lang.Exception) {
Log.e(TAG, "Error in getTetheredIfaces")
e.printStackTrace()
}
return false
}
fun startTethering(callback: MyOnStartTetheringCallback, isFirst: Boolean = false,context: Context): Boolean {
this.startTetheringCallback = callback
if (isHotSpotApOpen && !isFirst) {
Log.d(TAG, "Tether already active, returning")
callback.onTetheringStarted()
return false
}
val outputDir: File = context!!.codeCacheDir
val proxy: Any = try {
ProxyBuilder.forClass(onStartTetheringCallbackClass())
.dexCache(outputDir).handler(InvocationHandler { proxy, method, args ->
when (method.name) {
"onTetheringStarted" -> callback.onTetheringStarted()
"onTetheringFailed" -> callback.onTetheringFailed()
else -> ProxyBuilder.callSuper(proxy, method, args)
}
null
}).build()
} catch (e: java.lang.Exception) {
Log.e(
TAG,
"Error in enableTethering ProxyBuilder"
)
e.printStackTrace()
return false
}
var method: Method? = null
try {
method = mConnectivityManager!!.javaClass.getDeclaredMethod(
"startTethering",
Int::class.javaPrimitiveType,
Boolean::class.javaPrimitiveType,
onStartTetheringCallbackClass(),
Handler::class.java
)
if (method == null) {
Log.e(TAG, "startTetheringMethod is null")
} else {
method.invoke(
mConnectivityManager,
ConnectivityManager.TYPE_MOBILE,
false,
proxy,
null
)
Log.d(TAG, "startTethering invoked")
}
return true
} catch (e: java.lang.Exception) {
Log.e(TAG, "Error in enableTethering")
e.printStackTrace()
}
return false
}
private fun onStartTetheringCallbackClass(): Class<*>? {
try {
return Class.forName("android.net.ConnectivityManager\$OnStartTetheringCallback")
} catch (e: ClassNotFoundException) {
Log.e(
TAG,
"OnStartTetheringCallbackClass error: $e"
)
e.printStackTrace()
}
return null
}
fun stopTethering() {
try {
val method = mConnectivityManager?.javaClass?.getDeclaredMethod(
"stopTethering",
Int::class.javaPrimitiveType
)
if (method == null) {
Log.e(TAG, "stopTetheringMethod is null")
} else {
method.invoke(mConnectivityManager, ConnectivityManager.TYPE_MOBILE)
Log.d(TAG, "stopTethering invoked")
}
} catch (e: java.lang.Exception) {
Log.e(TAG, "stopTethering error: $e")
e.printStackTrace()
}
}
/**
* 获取ap名称
*/
fun getSsid(): String? {
val wifiApInfo = getWifiApConfiguration()
if (wifiApInfo == null) return ""
val ssid = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
(wifiApInfo as SoftApConfiguration).ssid
} else {
(wifiApInfo as WifiConfiguration).SSID
}
return ssid
}
/**
* 获取Ap密码
*/
fun getPassphrase(): String? {
val wifiApInfo = getWifiApConfiguration()
if (wifiApInfo == null) return ""
val passphrase = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
(wifiApInfo as SoftApConfiguration).passphrase
} else {
(wifiApInfo as WifiConfiguration).preSharedKey
}
return passphrase
}
private fun getWifiApConfiguration(): Any? {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
return try {
val method = wifiManager?.javaClass?.getMethod("getSoftApConfiguration")
method?.isAccessible = true
method?.invoke(wifiManager) as SoftApConfiguration
} catch (e: java.lang.Exception) {
e.message?.let { Log.e(TAG, it) }
null
}
} else {
return try {
val method = wifiManager?.javaClass?.getMethod("getWifiApConfiguration")
method?.isAccessible = true
if (wifiManager != null) {
method?.invoke(wifiManager) as WifiConfiguration
} else {
null
}
} catch (e: java.lang.Exception) {
e.message?.let { Log.e(TAG, it) }
null
}
}
}
/**
* 热点是否打开
*/
fun isWifiApOn(): Boolean {
var method: Method? = null
var i = 0
try {
method = wifiManager?.javaClass?.getMethod("getWifiApState")
} catch (e: NoSuchMethodException) {
e.printStackTrace()
}
try {
i = method?.invoke(wifiManager) as Int
Log.d(TAG, "getWifiApState: $i")
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
return i == 13 // 13 为已打开
}
/**
* 热点是否失败
* SWIM-251947
* 20230826_1343中复现的应该是wifi fw crash的现象
* 后面启动ap失败后有改变状态,state 14代表ap异常(Wi-Fi AP is in a failed state. This state will occur when an error occurs during enabling or disabling)
* 08-26 13:36:26.748797 1535 10784 V WifiManager: SoftApCallbackProxy: onStateChanged: state=14, failureReason=0
* 根据上次语音沟通,ap启动异常时是能返回状态的,请app在收到,ap异常状态后延迟2秒再启动ap
*/
fun wifiApOpenFailed(): Boolean {
var method: Method? = null
var i = 0
try {
method = wifiManager?.javaClass?.getMethod("getWifiApState")
} catch (e: NoSuchMethodException) {
e.printStackTrace()
}
try {
i = method?.invoke(wifiManager) as Int
Log.d(TAG, "getWifiApState: $i")
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}
return i == 14 //state 14代表ap异常
}
fun removeTetheringCallback() {
Log.e("MainActivity", "removeTetheringCallback")
if (this.startTetheringCallback != null) {
this.startTetheringCallback = null
}
}
}
在此做个笔记