Android热点的开启和关闭以及监听

最近在研究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

这行代码的意思是选择热点的加密方式。给大家看一下源码

Android热点的开启和关闭以及监听_第1张图片

这里可以看到大家很熟悉的东西 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);
}

 

到这基本就可以了,大家有什么疑问的话欢迎留言。写的不好,希望大家多多包涵。

你可能感兴趣的:(Android热点的开启和关闭以及监听)