Android7.1之WIFI热点问题

背景

项目需求,需要在Android应用中打开关闭和配置WIFI热点,开始以为只需要简单地调用几下系统API就可以了,后来发现是个大坑。
不同的Android版本操作热点的方式还不一样

Android7.0及以前的版本是通过WifiManagersetWifiApEnabled,具体方式如下:

1
2
3
4
5
6

WifiManager mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Method method = mWifiManager.getClass().getMethod("setWifiApEnabled",
WifiConfiguration.class, boolean.class);
//反射
method.invoke(mWifiManager, null, false);

在Android7.1及后面的版本,主要是通过ConnectivityManagerstartTethering方法来操作的。

而且对于Android7.1比较奇葩!有的机型可以通过Wifimanager的方式进行开启,也能正常连接,但是有的能开启但是无法正常连接.

那么Android7.1的版本怎么用代码去操作WIFI热点呢?主要有以下3种方式:

  1. 通过编译修改源码的方式进行,把ConnectivityManager这个包下面的源码单独编译一个jar 然后导入jar包到项目中使用。
    源码路径:base/core/java/android/net/ConnectivityManager.java
    修改ConnectivityManager源码,将TETHERING_WIFI字段、startTethering方法及OnStartTetheringCallback类中隐藏相关的标志去掉,然后单独编译一个jar包.
    将jar包拷贝到工程中
    该jar包会和官方sdk中的android.jar会有冲突,所以需要配置jar包的优先级。
    在app的build.gradle中配置

    1
    provided files('src/main/libs/WifiAp8.jar')

    在工程下的build.gradle中添加如下配置:

    1
    2
    3
    4
    5
    6
    7
    8
    allprojects {
    gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
    //设置jar相对包路径或绝对路径
    options.compilerArgs.add('-Xbootclasspath/p:app/src/main/libs/WifiAp8.jar')
    }
    }
    }

    开启热点

    1
    2
    3
    4
    5
    6
    7
    if(getWifiAPState() != WIFI_AP_STATE_ENABLED){
    //Android8.0及以上版本//需改为7.1
    if (Build.VERSION.SDK_INT >= 26) {
    mConnectivityManager.startTethering(ConnectivityManager.TETHERING_WIFI,
    true, new ONStartTetheringCallback());
    }
    }

    在AS中上述代码会有红色显示,但是不影响编译使用。可以正常编译生成apk。使用该方法不需要提前关闭wifi。

    ONStartTetheringCallback类继承了OnStartTetheringCallback抽象类。

    1
    2
    3
    class ONStartTetheringCallback extends
    ConnectivityManager.OnStartTetheringCallback {
    }

    关闭热点

    1
    2
    3
    4
    5
    6
    if(getWifiAPState() != WIFI_AP_STATE_DISABLED){
    //Android8.0及以上版本//需改为7.1
    if (Build.VERSION.SDK_INT >= 26) {
    mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
    }
    }

    权限
    使用上述功能需要这三个权限:

    1
    2
    3
    <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权限,否则不能正常使用。

  2. 通过8.0的方式走ConnectivityManager 的startTethering方式进行开启热点,但是要注意的是7.1的startTethering 参数和8.0的startTethering参数有所不同注意修改。但是即使这样还是会报一个错误(need MANAGE_USERS or CREATE_USERS permission to: query user)没有权限调用这个Api同时还会出现一个Exec异常InvocationTargetException 就是说你这个app不是系统app需要权限,那我们就把他变成系统app,如何才能变成呢?使用系统签名就可以,具体操作就不在这说了。可参考链接(https://blog.csdn.net/u013340360/article/details/80341833)

  3. 这种主要针对有的机型可以通过Wifimanager的方式进行开启,无法正常连接的情况。之所以开启了wifi热点成功,但是却没有成功连接是因为DHCP没有给这个热点分配IP地址,也就导致不能正常使用。

参考

Donate comment here