最近想学习下Android上打开热点的方法,在网上找了好多篇相关的博客,代码基本上都是一个样子,都是几年前的老代码了,现在根本行不通。好在爬坑了一下午,终于给爬出来了。
1.下面先说一下Android开启wifi热点的基本套路。
首先需要获取到WifiManager系统服务类,获取方式如下
WifiManager mWifiManager = (WifiManager) context.getApplicationContext().getSystemService(context.WIFI_SERVICE);
由于目前安卓系统上开启wifi热点的api方法不稳定,谷歌没有向开发者开放这个方法,将其隐藏了,也就是下面这个。
setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled)
因此我们需要利用java的反射机制来调用这个方法,解释下上面的两个参数。
WifiConfiguration :配置wifi热点的一些参数,包括热点名称,密码,加密方式等
boolean :是否开启热点
public void createWifitHot(String name, String password) {
try {
//wifi和热点不能同时打开,所以先判断wifi是否打开,打开则关闭
if (mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(false);
}
//java反射机制得到Method
Method method = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
//配置热点信息
WifiConfiguration config = new WifiConfiguration();
config.SSID = name;
config.preSharedKey = password;
config.hiddenSSID = true;
config.status = WifiConfiguration.Status.ENABLED;
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedKeyManagement.set(4);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
//通过java反射调用WifiManager的setWifiApEnabled方法
method.invoke(mWifiManager, config, true);
} catch (Exception e) {
e.printStackTrace();
}
}
注意:
1. password这个参数,密码至少要包含8个字符,否则热点创建失败。
2. config.allowedKeyManagement.set(4)这个方法是用来设置热点的加密方式,这个4代表什么意思呢,谷歌向开发者暴露的参数只有下面这4个。
public static final int NONE = 0;
public static final int WPA_PSK = 1;
public static final int WPA_EAP = 2;
public static final int IEEE8021X = 3
网上找的一些代码这里填的就是WifiConfiguration.KeyMgmt.WPA_PSK,如果你在6.0以上的手机上运行你会发现代码上设置了wifi密码,但开启热点后并没有加密,而是开放的。因为6.0后的手机只有WPA2_PSK这种加密方式,但是这种加密方式谷歌没有暴露给开发者,好在通过WifiConfiguration的源码得知WPA2_PSK这种加密方式的int值为4,所以就明白这里的4是怎么来的了。
补充:在小米MiUi系统上测试时会出现加密安全性为无的情况,原因是小米系统对WPA2_PSK值做了更改,(官方值为4,小米为6,如果指定为4,小米会变为无密码热点)。请使用下面代码来创建加密热点。
int indexOfWPA2_PSK = 4;
//从WifiConfiguration.KeyMgmt数组中查找WPA2_PSK的值
for (int i = 0; i < WifiConfiguration.KeyMgmt.strings.length; i++) {
if (WifiConfiguration.KeyMgmt.strings[i].equals("WPA2_PSK")) {
indexOfWPA2_PSK = i;
break;
}
}
apConfig.allowedKeyManagement.set(indexOfWPA2_PSK);
2 关闭热点就比较简单了,利用java反射机制把setWifiApEnabled方法的boolean参数设为false即可。
public void closeWifiHot() {
try {
Method method = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method.invoke(mWifiManager, null, false);
} catch (Exception e) {
e.printStackTrace();
}
}
最后别忘了在Manifest文件里添加相应权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
//允许修改系统设置
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
注意,别得意的太早。此处还有坑,在6.0以上的系统,由于安全机制,修改系统的设置还需要在Manifest文件里添加允许修改系统设置权限,并在java代码里申请。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 判断是否有WRITE_SETTINGS权限if(!Settings.System.canWrite(this))
if (!Settings.System.canWrite(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1);
} else {
//创建热点
...
...
}
}
然后重写onActivityResult方法处理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 判断是否有WRITE_SETTINGS权限
if (Settings.System.canWrite(this)) {
//创建热点
...
...
} else {
//没有权限
...
...
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
最后附上监听热点状态方法,监听系统发出的广播即可。
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("android.net.wifi.WIFI_AP_STATE_CHANGED".equals(action)) {
//state状态为:10---正在关闭;11---已关闭;12---正在开启;13---已开启
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
switch (state) {
case int:
...
...
break;
}
}
}
};
IntentFilter mIntentFilter = new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED");
registerReceiver(mReceiver, mIntentFilter);
至此,所有的坑就爬完了。感谢阅读!