最近在研究android手机开启热点的问题,很是让我头疼。在这里记录一下,让其他的小白们少走些弯路,也方便自己知识的积累。
开启热点:
首先要先创建一个WifiManager
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
这里先说明一下在6.0及其以下版本,在开启热点之前要先手动关闭wifi。以后版本就不需要了会自动关闭,热点关闭后也会自动打开。
if (wifiManager.isWifiEnabled()) { //如果wifi打开关闭wifi
wifiManager.setWifiEnabled(false);
}
然后进入正题:
能够开启热点的方式一共有三种。7.1及其以下版本有一种。8.0及其以上版本有两种。
第一种:7.1及其以下版本开启关闭热点
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
try {
WifiConfiguration apConfig = new WifiConfiguration();
//配置热点的名称
apConfig.SSID ="我是热点";
//配置热点的密码(至少8位)
apConfig.preSharedKey = "12345678";
apConfig.allowedKeyManagement.set(4);
//通过反射调用设置热点
Method method = wifiManager.getClass().getMethod(
"setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
Boolean rs = (Boolean) method.invoke(wifiManager, apConfig, true);//true开启热点 false关闭热点
Log.d("-------", "开启是否成功:" + rs);
} catch (Exception e) {
e.printStackTrace();
}
这里解释一下为什么apConfig.allowedKeyManagement.set(4)要放4
这行代码的意思是选择热点的加密方式。给大家看一下源码
这里可以看到大家很熟悉的东西 WPA2_PSK、WPA_PSK是加密的方式。由于我发现现在的设备绝大多数只有两种一种是不加密另一种就是WPA2_PSK了,由于这个参数被被标记为系统调用的了那就直接把数拿来用吧。
第二种:8.0版本开启热点。这种方法不用我们去设置账号密码,系统会随机产生,并且在回调方法中可以直接拿到。这里需要注意的是要在远程服务中去开启,否则会出现退出到后台热点关闭的情况。
Intent startApService = new Intent(); startApService.setPackage("com.example.testhotport"); startApService.setAction("com.example.testhotport.ApServer"); startService(startApService);
在server中开启热点:
WifiManager manager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
manager.startLocalOnlyHotspot(new WifiManager.LocalOnlyHotspotCallback() {
@Override
public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
super.onStarted(reservation);
ssid = reservation.getWifiConfiguration().SSID;
pwd = reservation.getWifiConfiguration().preSharedKey;
tv_text2.setText("app开启热点:"+"ssid:" + ssid + "pwd:" + pwd);
}
@Override
public void onStopped() {
super.onStopped();
tv_text2.setText("app开启热点:热点已关闭");
}
@Override
public void onFailed(int reason) {
super.onFailed(reason);
tv_text2.setText("app开启热点:热点开启失败");
}
}, null);
关闭热点:
try {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
Method method = wifiManager.getClass().getMethod("cancelLocalOnlyHotspotRequest");
method.setAccessible(true);
method.invoke(wifiManager);
tv_text2.setText("app开启热点:热点已关闭");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
或者:
reservation.close();
第三种:8.0版本开启关闭热点。这种方法开启的热点系统不会给我们随机产生账号密码,并且在app中也无法设置和获取账号密码,因为这里有个 android.permission.OVERRIDE_WIFI_CONFIG ,这个权限只有系统应用可以使用,所以app使用的话会报Security exception这个异常。
ConnectivityManager connManager = (ConnectivityManager) getApplicationContext().getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
Field iConnMgrField = null;
try {
iConnMgrField = connManager.getClass().getDeclaredField("mService");
iConnMgrField.setAccessible(true);
Object iConnMgr = iConnMgrField.get(connManager);
Class> iConnMgrClass = Class.forName(iConnMgr.getClass().getName());
if (isEnable) { //开启
Method startTethering = iConnMgrClass.getMethod("startTethering", int.class, ResultReceiver.class, boolean.class);
startTethering.invoke(iConnMgr, 0, null, true);
}else { //关闭
Method startTethering = iConnMgrClass.getMethod("stopTethering", int.class);
startTethering.invoke(iConnMgr, 0);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
获取热点的账号密码:这里获取的是7.1及其以下版本的,无论app内开启的和在系统设置开启的都可以获取到。8.0版本app开启的热点可以获取到(开启热点方法二),在系统设置开启的就不会获取到(也不是不可以,需要跟厂商进行沟通)。
Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");
method.setAccessible(true);
WifiConfiguration config = (WifiConfiguration) method.invoke(wifiManager);
Log.e(TAG, config.preSharedKey);
Field[] fields = config.getClass().getFields();
for (Field field : fields) {
if (field.getName().equals("SSID")) {
ssid = field.get(config).toString();
} else if (field.getName().equals("preSharedKey")) {
pwd = field.get(config).toString();
}
}
监听热点的状态
监听系统的广播就可以了
首先注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.wifi.WIFI_AP_STATE_CHANGED");
registerReceiver(new HotsspotReceiver(), intentFilter);
广播接收
class HotsspotReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.net.wifi.WIFI_AP_STATE_CHANGED")) {//便携式热点的状态为:10---正在关闭;11---已关闭;12---正在开启;13---已开启
int state = intent.getIntExtra("wifi_state", 0);
if (state == 10) {
tvState.setText("热点状态:正在关闭");
} else if (state == 11) {
tvState.setText("热点状态:已关闭");
hotState = false;
} else if (state == 12) {
tvState.setText("热点状态:正在开启");
} else if (state == 13) {
tvState.setText("热点状态:已开启");
hotState = true;
}
}
}
}
最后大家需要注意的是:
1.权限:
2.在Android6.0以上需要动态申请系统设置(这里可以把targetSdkVersion降为22就不用动态申请了),最好还有定位权限
//定位权限
if (ContextCompat.checkSelfPermission(HotspotActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//开启定位权限,200是标识码
ActivityCompat.requestPermissions(HotspotActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 200);
}
//定位权限的回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 200:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {//用户同意权限,执行我们的操作
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(this)) { // 系统设置权限
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1);
} else {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
createHotspot7(); // 7.1及其以下
} else {
createHotspot8(); // 8.0
}
}
}
} else {
Toast.makeText(HotspotActivity.this, "未开启定位权限,请手动到设置去开启权限", Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
}
// Activity的回调
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == 1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 判断是否有WRITE_SETTINGS权限
if (Settings.System.canWrite(this)) {
//创建热点
...
} else {
//没有权限
tvText.setText("暂未开通权限");
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
到这基本就可以了,大家有什么疑问的话欢迎留言。写的不好,希望大家多多包涵。