您的位置:首页 > 移动开发 > Android开发

Android扫描wifi二维码自动连接wifi

2016-08-15 21:37 851 查看
现在二维码的用处越来越多,微信扫二维码加好友,商场扫二维码关注公众号、得优惠券,就连一些小餐馆吃个饭,扫码自动跳转到线上(饿了么,百度外卖)的店铺.....而这些地方因为人多,担心用户等待时间过长就会走掉,怎么办?得有空调、wifi、西瓜,这样才能留住一部分客人,而wifi密码一般是直接问店里服务员获取,但是时间一长,人一多,店里老板和员工也烦了,干脆直接把wifi密码贴出来。但是这些都不够,我认为未来微信、QQ得加入(扩展)这个功能,扫描这个wifi二维码,询问用户是否连接上此wifi。
不说了,看源码吧,还是挺简单的。
原理是 基础的扫描二维码功能,识别二维码后,解析其内容,打开我们的wifi管理器,加入此wifi。
一般标准的wifi二维码的格式是这样的:

 WIFI:S:arg1;P:arg2;T:arg3; 其中 arg1是wifi名(也就是SSID);arg2是密码,当然也可以为空,就是没有密码;arg3是网络的加密类型,一般有3种,无密码、Wpa/wap2、Wep。
二维码扫描的部分就不说了,可以参考我前一篇的文章Android二维码识别与生成,或者嫌前一篇麻烦的,后面我会给出此Demo的源码。
当我们扫描到二维码后,会在handleDecode中去处理扫描结果,处理完毕后会通过setResult方式,将Intent和结果传回MainActivty的onActivityResult中,然后通过requestCode和resultCode去判断来自于哪个activity的Intent,接着取出值。
其解析处理结果
switch (requestCode) {
case SCANNIN_GREQUEST_CODE:
if(resultCode == RESULT_OK){
Bundle bundle = data.getExtras();
//显示扫描到的内容
mTextView.setText(bundle.getString("result"));
//显示
//mImageView.setImageBitmap((Bitmap) data.getParcelableExtra("bitmap"));

String strResult = bundle.getString("result");
if (strResult.contains("P:") && strResult.contains("T:")) {// 自动连接wifi
Log.e("扫描返回的结果----->", strResult);// 还是要判断
String passwordTemp = strResult.substring(strResult
.indexOf("P:"));
password = passwordTemp.substring(2,
passwordTemp.indexOf(";"));
String netWorkTypeTemp = strResult.substring(strResult
.indexOf("T:"));
netWorkType = netWorkTypeTemp.substring(2,
netWorkTypeTemp.indexOf(";"));
String netWorkNameTemp = strResult.substring(strResult
.indexOf("S:"));
netWorkName = netWorkNameTemp.substring(2,
netWorkNameTemp.indexOf(";"));

if (!wifiAdmin.mWifiManager.isWifiEnabled()) {
Toast.makeText(this, "开启wifi设置", Toast.LENGTH_LONG)
.show();
wifiAdmin.openWifi();
}
Dialog alertDialog = new AlertDialog.Builder(this)
.setTitle("扫描到可用wifi")
.setIcon(R.drawable.ic_launcher)
.setMessage("wifi名:" + netWorkName)
.setNegativeButton("取消",
new DialogInterface.OnClickListener() {

@Override
public void onClick(
DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
}
})
.setPositiveButton("加入此wifi ",
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog,
int which) {
int net_type = 0x13;
if (netWorkType
.compareToIgnoreCase("wpa") == 0) {
net_type = WifiAdmin.TYPE_WPA;// wpa
} else if (netWorkType
.compareToIgnoreCase("wep") == 0) {
net_type = WifiAdmin.TYPE_WEP;// wep
} else {
net_type = WifiAdmin.TYPE_NO_PASSWD;// 无加密
}
wifiAdmin.addNetwork(netWorkName,
password,
net_type);
Log.e("解析的数据----->",
"networkname: "
+ netWorkName + " "
+ "password: "
+ password
+ " netWorkType: "
+ net_type);
}
}).create();
alertDialog.show();

}
break;
}
}
WifiAdmin.java的代码如下
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;

import java.util.List;

/**
* Created by cmos.
*/
public class WifiAdmin {
private static String TAG="WifiManger";
public static final int TYPE_NO_PASSWD = 0x11;
public static final int TYPE_WEP = 0x12;
public static final int TYPE_WPA = 0x13;
public WifiManager mWifiManager;
private WifiInfo mWifiInfo;
public WifiAdmin(Context context){
mWifiManager= (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// mWifiInfo = mWifiManager.getConnectionInfo();
}

// 添加一个网络并连接
public void addNetwork(WifiConfiguration wifi){
int netId=mWifiManager.addNetwork(wifi);
mWifiManager.enableNetwork(netId,true);

}
public void addNetwork(String ssid, String passwd, int type) {
if (ssid == null || passwd == null || ssid.equals("")) {
Log.e(TAG, "addNetwork() ## nullpointer error!");
return;
}

if (type != TYPE_NO_PASSWD && type != TYPE_WEP && type != TYPE_WPA) {
Log.e(TAG, "addNetwork() ## unknown type = " + type);
}

addNetwork(createWifiInfo(ssid, passwd, type));
}

public WifiConfiguration createWifiInfo(String SSID, String password, int type) {

Log.e(TAG, "SSID = " + SSID + "## Password = " + password + "## Type = " + type);

WifiConfiguration config = new WifiConfiguration();
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
config.SSID = "\"" + SSID + "\"";

WifiConfiguration tempConfig = this.IsExsits(SSID);
if (tempConfig != null) {
//如果已存在该SSID的wifi
mWifiManager.removeNetwork(tempConfig.networkId);
}

// 分为三种情况:1没有密码2用wep加密3用wpa加密
if (type == TYPE_NO_PASSWD) {// 没有密码
config.wepKeys[0] = "";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;

} else if (type == TYPE_WEP) { // wep加密
config.hiddenSSID = true;
config.wepKeys[0] = "\"" + password + "\"";
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers
.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
} else if (type == TYPE_WPA) { // WPA加密
config.preSharedKey = "\"" + password + "\"";
config.hiddenSSID = true;
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.TKIP);
// config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.CCMP);
config.status = WifiConfiguration.Status.ENABLED;
}

return config;
}

//检测该SSID是否已存在
private WifiConfiguration IsExsits(String SSID) {
List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
for (WifiConfiguration existingConfig : existingConfigs) {
if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
return existingConfig;
}
}
return null;
}

// 打开WIFI
public void openWifi() {
if (!mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(true);
}
}

// 关闭WIFI
public void closeWifi() {
if (mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(false);
}
}
}


最后,我们得加上处理wifi相应的权限。

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
好了,是不是很简单。demo下载地址  点我下载。
最后的思考:

其实我也在想这么一个需求,既然能识别,那也得加上一键生成我的wifi二维码功能啊,结合前篇的二维码生成,这样就实现wifi共享了,免得别人问我密码。但是,但是这个目前实现不了,准确的说是在非root功能上的手机实现不了,因为这就等效于“怎么获取连接wifi的密码”的问题了,假如我们可以通过代码能获取到密码的话,那么按照格式就可以自动生成了。但是通过收集资料,发现这个实现不了,想一下,目前市场上存在的wifi万能钥匙一类的app在使用时,如果要显示密码的话,就得获取root权限,所以说这个是暂时没有办法解决的。当然如果你有好的、通用的解决方法,欢迎留言给个思路。

======2018.1.18更新=====
最近回过头来,看这些问题,突然发现有部分人反应6.0以上系统,这个方法就有时不行,经过我这2天的初步了解,算找到了一部分的原因。原来是Android系统在6.0以上的系统对wifi模块做了修改。以下是官方的原文:
Wi-Fi and Networking Changes
1、This release introduces the following behavior changes to the Wi-Fi and networking APIs.
Your apps can now change the state of WifiConfiguration objects only if you created these objects. You are not permitted to modify or delete WifiConfiguration objects created by the user or by other apps.
2、Previously, if an app forced the device to connect to a specific Wi-Fi network by using enableNetwork() with the disableAllOthers=true setting, the device disconnected from other networks such as cellular data. 
In This release, the device no longer disconnects from such other networks. If your app’s targetSdkVersion is “20” or lower, it is pinned to the selected Wi-Fi network. If your app’s targetSdkVersion is “21” or higher, 
use the multinetwork APIs (such as openConnection(), bindSocket(), and the new bindProcessToNetwork() method) to ensure that its network traffic is sent on the selected network.

翻译过来就是这样的(下图来自于这里



简单点说,就是android6.0 只允许操作自己创建的WifiConfiguration。
自己创建的:就是自己的app通过代码来创建的
用户或其他应用创建的:就是自己通过在系统设置里面选择ssid后,手动输入密码的;和其他应用通过代码来创建的
对wifi的操作 
用户或其他应用创建的wifi:虽然可以通过wifiManager的savedConfiguration方法获取到指定wifi对应的Configuration,但是并不能进行具体的操作,add该wifi,会直接返回-1(addNetwork(WifiConfigurationconfig)=-1),enableNetwork(config)时会导致app无响应,removeNetwork(config)=false,移除系统wifi也不会成功。

自己创建的:可以进行add、enable、remove操作。

下面上传一个,我测试通过的可以在6.0以上系统适配的代码:
import android.content.Context;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;

import java.util.List;

public class WifiAutoConnectManager {
private static final String TAG = WifiAutoConnectManager.class
.getSimpleName();

WifiManager wifiManager;

// 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况
public enum WifiCipherType {
WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
}

// 构造函数
public WifiAutoConnectManager(Context mContext) {
this.wifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}

// 提供一个外部接口,传入要连接的无线网
public void connect(String ssid, String password, WifiCipherType type) {
Thread thread = new Thread(new ConnectRunnable(ssid, password, type));
thread.start();
}

// 查看以前是否也配置过这个网络
private WifiConfiguration isExsits(String SSID) {
List<WifiConfiguration> existingConfigs = wifiManager
.getConfiguredNetworks();
for (WifiConfiguration existingConfig : existingConfigs) {
if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
return existingConfig;
}
}
return null;
}

private WifiConfiguration createWifiInfo(String SSID, String Password,
WifiCipherType Type) {
WifiConfiguration config = new WifiConfiguration();
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
config.SSID = "\"" + SSID + "\"";
// config.SSID = SSID;
// nopass
if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
// config.wepKeys[0] = "";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
// config.wepTxKeyIndex = 0;
}
// wep
if (Type == WifiCipherType.WIFICIPHER_WEP) {
if (!TextUtils.isEmpty(Password)) {
if (isHexWepKey(Password)) {
config.wepKeys[0] = Password;
} else {
config.wepKeys[0] = "\"" + Password + "\"";
}
}
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
}
// wpa
if (Type == WifiCipherType.WIFICIPHER_WPA) {
config.preSharedKey = "\"" + Password + "\"";
config.hiddenSSID = true;
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.TKIP);
// 此处需要修改否则不能自动重联
// config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedPairwiseCiphers
.set(WifiConfiguration.PairwiseCipher.CCMP);
config.status = WifiConfiguration.Status.ENABLED;

}
return config;
}

// 打开wifi功能
private boolean openWifi() {
boolean bRet = true;
if (!wifiManager.isWifiEnabled()) {
bRet = wifiManager.setWifiEnabled(true);
}
return bRet;
}

// 关闭WIFI
private void closeWifi() {
if (wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(false);
}
}

private class ConnectRunnable implements Runnable {
private String ssid;

private String password;

private WifiCipherType type;

public ConnectRunnable(String ssid, String password, WifiCipherType type) {
this.ssid = ssid;
this.password = password;
this.type = type;
}

@Override
public void run() {
// 打开wifi
openWifi();
// 开启wifi功能需要一段时间(一般需要1-3秒左右),所以要等到wifi
// 状态变成WIFI_STATE_ENABLED的时候才能执行下面的语句

while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
try {
// 为了避免程序一直while循环,让它睡个200毫秒检测……
Thread.sleep(200);

} catch (InterruptedException ie) {
Log.e(TAG, ie.toString());
}
}

WifiConfiguration tempConfig = isExsits(ssid);

if (tempConfig != null) {
// wifiManager.removeNetwork(tempConfig.networkId);此方法只能删除自己应用创建的wifi

wifiManager.enableNetwork(tempConfig.networkId,
true);
} else {
WifiConfiguration wifiConfig = createWifiInfo(ssid, password,
type);
//
if (wifiConfig == null) {
Log.d(TAG, "wifiConfig is null!");
return;
}

int netID = wifiManager.addNetwork(wifiConfig);
boolean enabled = wifiManager.enableNetwork(netID, true);
Log.d(TAG, "enableNetwork status enable=" + enabled);
boolean connected = wifiManager.reconnect();
Log.d(TAG, "enableNetwork connected=" + connected);
}

}
}

private static boolean isHexWepKey(String wepKey) {
final int len = wepKey.length();

// WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
if (len != 10 && len != 26 && len != 58) {
return false;
}

return isHex(wepKey);
}

private static boolean isHex(String key) {
for (int i = key.length() - 1; i >= 0; i--) {
final char c = key.charAt(i);
if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
&& c <= 'f')) {
return false;
}
}

return true;
}

// 获取ssid的加密方式

public static WifiCipherType getCipherType(Context context, String ssid) {
WifiManager wifiManager = (WifiManager) context.getApplicationContext()
.getSystemService(Context.WIFI_SERVICE);

List<ScanResult> list = wifiManager.getScanResults();

for (ScanResult scResult : list) {

if (!TextUtils.isEmpty(scResult.SSID) && scResult.SSID.equals(ssid)) {
String capabilities = scResult.capabilities;
// Log.i("hefeng","capabilities=" + capabilities);

if (!TextUtils.isEmpty(capabilities)) {

if (capabilities.contains("WPA")
|| capabilities.contains("wpa")) {
return WifiCipherType.WIFICIPHER_WPA;
} else if (capabilities.contains("WEP")
|| capabilities.contains("wep")) {
return WifiCipherType.WIFICIPHER_WEP;
} else {
return WifiCipherType.WIFICIPHER_NOPASS;
}
}
}
}
return WifiCipherType.WIFICIPHER_INVALID;
}
}
大家可以拿过去测试下,如果有问题的,欢迎留言讨论
======2018.1.18更新=====
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: