背景

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

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


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中配置

    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及以上版本//需改为7.1
        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及以上版本//需改为7.1
        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权限,否则不能正常使用。

  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地址,也就导致不能正常使用。

参考