Android创建WiFi热点研究(安全性为:无-WPA PSK-WPA2 PSK,Android6.0适配)

前言: 系统热点设置页面的安全性选项在在Android 4.3上有“无”、“WPA PSK”、“WPA2 PSK”三个选项,在Android 4.3之后去掉了WPA PSK选项,当安全性为“无”时连接热点不需要密码,其他两种都是要输入密码才能连接的。本文将讲解用代码自动创建、跳转系统热点设置页手动创建两种方式创建热点,以及当targetSdkVersion设为23以上时如何处理权限问题。

热点的安全性选项是在WifiConfiguration.java这个类中定义的

 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标记,我们不可以直接访问的,怎么创建这三种形式的热点呢?

  • 编码实现

添加需要的权限

    
    

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 (final IOException e) {
18             return false;
19         }
20     }
apConfig.allowedKeyManagement.set(isMIUI() ? 6 : 4);

至于MIUI为什么设为6就无从得知了,我尝试在MIUI论坛发帖询问原因,帖子一直没有审核通过。由此可见使用系统非公开API是有一定风险的,如果自动创建热点失败,我们也可以跳转系统设置页让用户手动创建。 

 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);
    }
  • Android 6.0权限适配

如果APP的targetSdkVersion为23以上,需要android.permission.WRITE_SETTINGS权限,并在运行时申请,跳转系统设置页由用户开启。所以开启热点的调用代码为:

 1                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 2                     if (!Settings.System.canWrite(this)) {
 3                         Toast.makeText(this, "打开热点需要启用“修改系统设置”权限,请手动开启", Toast.LENGTH_SHORT).show();
 4 
 5                         //清单文件中需要android.permission.WRITE_SETTINGS,否则打开的设置页面开关是灰色的
 6                         Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
 7                         intent.setData(Uri.parse("package:" + this.getPackageName()));
 8                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 9                         startActivity(intent);
10                     } else {
11                         setWifiApEnabled(true);
12                     }
13                 } else {
14                     setWifiApEnabled(true);
15                 }

 

你可能感兴趣的:(Android创建WiFi热点研究(安全性为:无-WPA PSK-WPA2 PSK,Android6.0适配))