前言: WiFi热点设置页面的安全性选项在Android 4.x上有“无”、“WPA PSK”、“WPA2 PSK”三个选项,在Android 5.0(含)之后去掉了WPA PSK选项(部分手机厂家会修改ROM,有些手机4.4就没有这个选项了,安全性选项下拉选项是在packages/apps/Settings/res/values/arrays.xml这个文件的wifi_ap_security数组中定义的),当安全性为“无”时连接热点不需要密码,其他两种都是要输入密码才能连接的。本文将讲解用代码自动创建、跳转系统热点设置页手动创建两种方式创建热点,以及当targetSdkVersion设为23以上时如何处理权限问题。

热点的安全性选项对应的Java类是在WifiConfiguration.java中定义的(源码路径:/frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.java,API 25,不同的API内容有差异)

 1     public static class KeyMgmt {
 2         private KeyMgmt() { }
 3
 4         /** WPA is not used; plaintext or static WEP could be used. */
 5         public static final int NONE = 0;
 6         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
 7         public static final int WPA_PSK = 1;
 8         /** WPA using EAP authentication. Generally used with an external authentication server. */
 9         public static final int WPA_EAP = 2;
10         /** IEEE 802.1X using EAP authentication and (optionally) dynamically
11          * generated WEP keys. */
12         public static final int IEEE8021X = 3;
13
14         /** WPA2 pre-shared key for use with soft access point
15           * (requires {@code preSharedKey} to be specified).
16           * @hide
17           */
18         @SystemApi
19         public static final int WPA2_PSK = 4;
20         /**
21          * Hotspot 2.0 r2 OSEN:
22          * @hide
23          */
24         public static final int OSEN = 5;
25
26         public static final String varName = "key_mgmt";
27
28         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
29                 "WPA2_PSK", "OSEN" };
30     }

可以看到,无、WPA PSK、WPA2 PSK这三个选项分别对应到KeyMgmt.NONE、KeyMgmt.WPA_PSK、KeyMgmt.WPA2_PSK,最后一个WPA2_PSK添加了@SystemApi标记,我们不可以直接访问的,怎么创建这三种形式的热点呢?

  • 编码实现

添加需要的权限

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

Android并没有公开创建WiFi热点的API,所以我们只能通过反射的方式实现,创建安全性为“无”的代码如下:

 1     /**
 2      * 自定义wifi热点
 3      *
 4      * @param enabled 开启or关闭
 5      * @return
 6      */
 7     private boolean setWifiApEnabled(boolean enabled) {
 8         boolean result = false;
 9         WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
10         if (enabled) {
11             //wifi和热点不能同时打开,所以打开热点的时候需要关闭wifi
12             if (wifiManager.isWifiEnabled()) {
13                 wifiManager.setWifiEnabled(false);
14             }
15         }
16         try {
17             //热点的配置类
18             WifiConfiguration apConfig = new WifiConfiguration();
19             //配置热点的名称
20             apConfig.SSID = "ap_test";
21             //配置热点的密码,至少八位
22             apConfig.preSharedKey = "";
23             //配置热点安全性选项
24             apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
25             //通过反射调用设置热点
26             Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
27             //返回热点打开状态
28             result = (Boolean) method.invoke(wifiManager, apConfig, enabled);
29             if (!result) {
30                 Toast.makeText(this, "热点创建失败,请手动创建!", Toast.LENGTH_SHORT).show();
31                 openAPUI();
32             }
33         } catch (Exception e) {
34             Toast.makeText(this, "热点创建失败,请手动创建!", Toast.LENGTH_SHORT).show();
35             openAPUI();
36         }
37         return result;
38     }

创建安全性为“WPA PSK”的热点需要修改22、24行,需要注意的是:创建热点后,在不支持WPA_PSK的手机上(Android 4.3以上版本)打开系统热点页面,“安全性”将显示为“无”,看不到密码文本框,但是连接此类热点还是需要输入密码的。

1 //配置热点的密码,至少八位
2 apConfig.preSharedKey = "12345678";
3 //配置热点安全性
4 apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);

创建安全性选项为WPA2 PSK只需将上面代码中第4行改为

apConfig.allowedKeyManagement.set(4);

直接将值指定为4,原因上面讲过,这里还有另外一个坑:在MIUI系统上,WPA2 PSK这个值为6,如果在MIUI上运行需要设为6才可以,我们可以判断一下手机ROM的版本,根据不同的ROM设为4或6。(后面有另外一种判断方式)

 1     /**
 2      * 判断是否为MIUI系统,参考http://blog.csdn.net/xx326664162/article/details/52438706
 3      *
 4      * @return
 5      */
 6     public static boolean isMIUI() {
 7         try {
 8             String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
 9             String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
10             String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
11             Properties prop = new Properties();
12             prop.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
13
14             return prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null
15                     || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null
16                     || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null;
17         } catch (IOException e) {
18             return false;
19         }
20     }

apConfig.allowedKeyManagement.set(isMIUI() ? 6 : 4);

至于MIUI为什么设为6就无从得知了,我尝试在MIUI论坛发帖询问原因,帖子一直没有审核通过,由此可见使用系统非公开API是有一定风险的。

20170914更新

经过研究,可以从WifiConfiguration.KeyMgmt.strings这个数组中读取所有的安全性选项(MIUI的安全性选项为NONE, WPA_PSK, WPA_EAP, IEEE8021X, WAPI_PSK, WAPI_CERT, WPA2_PSK, OSEN,多了WAPI_PSK, WAPI_CERT这两个),我们只要从中找到WPA2_PSK的索引值就可以了,不需要根据ROM类型判断,所以上述代码可以修改为

1             int indexOfWPA2_PSK = 4;
2             //从WifiConfiguration.KeyMgmt数组中查找WPA2_PSK的值
3             for (int i = 0; i < WifiConfiguration.KeyMgmt.strings.length; i++) {
4                 if (WifiConfiguration.KeyMgmt.strings[i].equals("WPA2_PSK")) {
5                     indexOfWPA2_PSK = i;
6                     break;
7                 }
8             }
9             apConfig.allowedKeyManagement.set(indexOfWPA2_PSK);

如果自动创建热点失败,我们也可以跳转系统设置页让用户手动创建。 Android同样没有提供跳转热点设置页面的Intent,我们可以打开热点设置页面后,通过使用adb shell actives去查找相应的APP包名、类,打开系统热点设置页的代码如下:

    /*** 打开网络共享与热点设置页面*/private void openAPUI() {Intent intent = new Intent();intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//打开网络共享与热点设置页面ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$TetherSettingsActivity");intent.setComponent(comp);startActivity(intent);}

  • 读取热点配置信息

直接贴代码吧,判断热点是否打开可以参考源码中的isWifiApEnabled()方法

 1     /**
 2      * 读取热点配置信息
 3      */
 4     private void getWiFiAPConfig() {
 5         try {
 6             WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
 7             Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");
 8             WifiConfiguration apConfig = (WifiConfiguration) method.invoke(wifiManager);
 9             if (apConfig == null) {
10                 tvInfo.setText("未配置热点");
11                 return;
12             }
13             tvInfo.setText(String.format("热点名称:%s\r\n", apConfig.SSID));
14             tvInfo.append(String.format("密码:%s\n", apConfig.preSharedKey));
15             //使用apConfig.allowedKeyManagement.toString()返回{0}这样的格式,需要截取中间的具体数值
16             //下面几种写法都可以
17             //int index = Integer.valueOf(apConfig.allowedKeyManagement.toString().substring(1, 2));
18             //int index = Integer.valueOf(String.valueOf(apConfig.allowedKeyManagement.toString().charAt(1)));
19             //int index = Integer.valueOf(apConfig.allowedKeyManagement.toString().charAt(1)+"");
20             int index = apConfig.allowedKeyManagement.toString().charAt(1) - '0';
21             //从KeyMgmt数组中取出对应的文本
22             String apType = WifiConfiguration.KeyMgmt.strings[index];
23             tvInfo.append(String.format(Locale.getDefault(), "WifiConfiguration.KeyMgmt:%s\r\n", Arrays.toString(WifiConfiguration.KeyMgmt.strings)));
24             tvInfo.append(String.format(Locale.getDefault(), "安全性:%d,%s\r\n", index, apType));
25             isOpen = isWifiApEnabled();
26             tvInfo.append("是否已开启:" + isOpen);
27         } catch (NoSuchMethodException e) {
28             e.printStackTrace();
29         } catch (IllegalAccessException e) {
30             e.printStackTrace();
31         } catch (InvocationTargetException e) {
32             e.printStackTrace();
33         }
34     }

系统会自动创建一个默认的热点,如果我们不需要自定义热点参数的话,可以直接读取系统的热点参数,请参考源码中的switchWifiApEnabled(boolean enabled)方法

  • Android 6.0权限适配

如果APP的targetSdkVersion为23以上,需要在清单文件中添加android.permission.WRITE_SETTINGS权限,并在运行时申请,跳转系统设置页由用户开启。

 1     private boolean isHasPermissions() {
 2         boolean result = false;
 3         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 4             if (!Settings.System.canWrite(this)) {
 5                 Toast.makeText(this, "打开热点需要启用“修改系统设置”权限,请手动开启", Toast.LENGTH_SHORT).show();
 6
 7                 //清单文件中需要android.permission.WRITE_SETTINGS,否则打开的设置页面开关是灰色的
 8                 Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
 9                 intent.setData(Uri.parse("package:" + this.getPackageName()));
10                 //判断系统能否处理,部分ROM无此action,如魅族Flyme
11                 if (intent.resolveActivity(getPackageManager()) != null) {
12                     startActivity(intent);
13                 } else {
14                     //打开应用详情页
15                     intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
16                     intent.setData(Uri.parse("package:" + this.getPackageName()));
17                     if (intent.resolveActivity(getPackageManager()) != null) {
18                         startActivity(intent);
19                     }
20                 }
21             } else {
22                 result = true;
23             }
24         } else {
25             result = true;
26         }
27         return result;
28     }

项目源码:https://github.com/fly263/APDemo

PS:布局文件使用了ConstraintLayout,如果没有安装,需要在Android Studio中点击File-Settings-System Settings-Android SDK,切换到SDK Tools标签页,下载ConstraintLayout for Android、Solver for ConstraintLayout两个支持库

转载于:https://www.cnblogs.com/fly263/p/7341768.html

Android WiFi热点完全研究(自定义创建、跳转系统界面设置、读取配置、切换,Android6.0适配)...相关推荐

  1. Android -- Wifi热点的打开与关闭流程简介

    Android -- Wifi热点的打开与关闭流程简介 在Android手机中,热点也是一个较为常用的功能.对于framework开发者来说,要开发.维护SoftAp,了解framework中热点开关 ...

  2. android wifi热点的创建以及连接通信(华为T8951 Google GALAXY Nexus 测试通过)

                   参考网上的很多的资料,初步实现了wifi热点的创建.连接以及聊天通信,以下是网上广为流传的Wifi 三种配置: public WifiConfiguration crea ...

  3. android 代理 wifi热点,android wifi热点默认网关

    原贴:https://blog.csdn.net/jingzitakk66/article/details/89146696 项目需求,android端创建热点,电脑端连接此热点后用socket实现数 ...

  4. android wifi热点的连接不上,开启热点后160wifi连不上手机的解决方法汇总

    使用160WiFi最常出现的问题就是160wifi连不上手机,很多朋友在成功开启热点之后,手机却无法连接wifi网络.今天,绿茶小编就为大家介绍一下解决方法. 方法一.使用160WiFi成功开启热点后 ...

  5. android wifi热点广播,Android WiFi热点开发的示例代码

    上次写了Android连接匿名WiFi的内容.WiFI开发对于应用层开发是比较小众的知识点,不过既然用到了就在此记录下. 创建热点 1.根据加密类型.密码.是否隐藏等参数来创建热点 static Wi ...

  6. android wifi热点项目总结,高通Android wifi移植和wifi热点问题总结

    由于开发环境和系统的差异,wifi移植,包括wifi热点开启时有时还会出现其他问题,我这里先总结下: 1.netd问题 Netd 就是Network Daemon 的缩写,表示Network守护进程​ ...

  7. android wifi热点setting

    目录 一.wifi原生setting的入口在WifiTetherSettings.java 二.改热点Setting的时候可以直接只编译Settings.apk,并且替换, 三.wifi热点貌似官方支 ...

  8. android wifi热点默认名称,Android WIFI热点默认SSID的修改方法

    修改文件: frameworks/base/wifi/java/android/net/wifi/WifiApConfigStore.java 相关代码片段: private void setDefa ...

  9. android wifi热点设置密码,在手机中如何修改连接WiFi热点的密码?

    摘 要 在手机中如何修改连接WiFi热点的密码? 或许大家修改完路由器WiFi密码后,遇到手机无法连接wifi上网了.出现这种问题的原因,一般都是由于我们只修改了路由器WiFi密码,而没有修改WiFi ...

最新文章

  1. 使用 Python 和 OpenCV 构建 SET 求解器
  2. Centos 下 Nginx 信号控制
  3. mysql 查询 distinct_MYSQL查询数据(二)SELECT | DISTINCT
  4. 同时设置超时时间_刚入职的小菜鸡,设错了RPC超时,搞了个线上事故
  5. [云炬创业管理笔记]第一章讨论2
  6. 如何防止应用程序泄密?
  7. Redis作为缓存服务器
  8. UVA12190 Electric Bill【二分搜索】
  9. Relaxation step(Dijkstra's 最短路径算法)
  10. 群晖万兆文件服务器,NAS进阶 篇三:2019年最具性价比的NAS硬件是什么暨黑群晖万兆搭建经验介绍...
  11. matlab代码:考虑实时市场联动的电力零售商鲁棒定价策略
  12. 截止失真放大电路_每周经典电路分析:一个经典实际运放的内部电路分析(1)
  13. 统计思维(实例5)——变量之间的关系
  14. Tomcat启动报Exception in thread “main“ java.lang.UnsatisfiedLinkError: no secure-tomcat in java.library
  15. locale 国际化配置(springboot)
  16. 解决Gitlab的The remote end hung up unexpectedly错误
  17. springboot+英语在线学习系统 毕业设计-附源码211714
  18. Oracle(11g)数据库教程之十:Oracle操作题 (复习课)
  19. nova8se鸿蒙,挖东西:华为nova8SE标准版和高配版哪个好?解析有区别没有?主要的优势在哪里?...
  20. ARM架构SMMU驱动详解

热门文章

  1. 人脸识别技术有哪些新的发展_疫情下,旅游景区人脸识别技术可以应用在哪些场景?...
  2. 服务器对搜索引擎有哪些影响,实录:网站换服务器后对搜索引擎的影响
  3. 网站优化过度后会出现哪些“后遗症”?悠着点~
  4. 企业网络推广——企业网络推广中如何解决网站排名提升难题?
  5. 影响网站权重的关键性因素有哪些?
  6. java super extends_Java继承extends与super关键字
  7. python 爬取道客巴巴文档_Python常用的几个高效率的爬虫框架
  8. mysql 优化版_MySQL优化(超完整版)(一)
  9. vue怎么使用eval_Webpack 构建工具手把手教你怎么用
  10. Idea terminal:不是内部或外部命令,也不是可行的程序或批处理文件