最近发现Android8.0及以上的手机开启Wifi热点后不能正常使用,故研究了一下如何解决次问题。
Android 7.0 开启Wifi热点
在Android7.0及以前的版本开启Wifi热点的方式如下:
WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Method method = mWifiManager.getClass().getMethod("setWifiApEnabled",
WifiConfiguration.class, boolean.class);
//反射
method.invoke(mWifiManager, null, false);
Android 8.0 开启Wifi热点
对于Android8.0及以上的设备,通过WifiManager setWifiApEnabled,可以打开Wifi热点,但是会发现此热点连接不上,由于DHCP没有开启,所以不会分配ip地址,也就导致不能正常使用。
在Android8.0系统应用Settings,发现其开启热点的方式是通过ConnectivityManager的startTethering方法来开启的。
查看ConnectivityManager的方法
startTethering 是隐藏的方法,并且第三个参数OnStartTetheringCallback是ConnectivityManager内部抽象类,也是隐藏的。
/**
* Callback for use with {@link #startTethering} to find out whether tethering succeeded.
* @hide
*/
@SystemApi
public static abstract class OnStartTetheringCallback {
/**
* Called when tethering has been successfully started.
*/
public void onTetheringStarted() {};
/**
* Called when starting tethering failed.
*/
public void onTetheringFailed() {};
}
通过反射的方式并没有找到方式获取startTethering方法,以及创建OnStartTetheringCallback子对象。
后来通过另一种方式实现了。
配置jar包
首先修改ConnectivityManager源码,将TETHERING_WIFI字段、startTethering方法及OnStartTetheringCallback类中隐藏相关的标志去掉,然后单独编译一个jar包。
将jar包拷贝到工程中,如下所示:
该jar包会和官方sdk中的android.jar会有冲突,所以需要配置jar包的优先级。
在app的build.gradle中配置
provided files('src/main/libs/WifiAp8.jar')
在工程下的build.gradle中添加如下配置:
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
//设置jar相对包路径或绝对路径
options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/WifiAp8.jar')
}
}
}
编写代码
开启热点
if(getWifiAPState() != WIFI_AP_STATE_ENABLED){
//Android8.0及以上版本
if (Build.VERSION.SDK_INT >= 26) {
mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI,
true, new ONStartTetheringCallback());
}
}
在AS中上述代码会有红色显示,但是不影响编译使用。可以正常编译生成apk。使用该方法不需要提前关闭wifi。
ONStartTetheringCallback类继承了OnStartTetheringCallback抽象类。
class ONStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
}
关闭热点
if(getWifiAPState() != WIFI_AP_STATE_DISABLED){
//Android8.0及以上版本
if (Build.VERSION.SDK_INT >= 26) {
mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
}
}
权限
使用上述功能需要这三个权限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
还需要在代码中申请WRITE_SETTINGS权限,否则不能正常使用。
这样就可以了,不只是系统应用可以使用,平常的应用也可以正常使用。亲测:华为P20(Android 8.1.0)、华为mate10(Android 8.1.0)、华为V10(Android 8.0.0)、OnePlus 5T(Android8.1.0)都可以正常使用:。
Android 7.1 开启Wifi热点
对于Android7.1、Android7.1.1、Android7.1.2的手机,开启热点的方式比较乱,有的手机用老方法
可以正常打开,比如红米5 plus(Android7.1.2)、坚果pro2(Android7.1.1),有的手机用老方法就不能正常使用(Nexus 5x 7.1.1),可以尝试用8.0的方法打开试试。
由于Android手机版本和厂家太多,手头没有太多手机,并不能做到很好的适配,所以大家可以尝试使用上述两种方法来看看哪种方法适合你手上的手机开启热点,并且热点能正常使用。