二维码的妙用:通过Zxing实现wifi账号密码分享功能

二维码是搭载信息的一种载体,通过二维码可以传递名片、网址、商品信息等,本文讲到二维码的另外一种妙用:通过二维码实现wifi账号和密码分享。

关于二维码的基础知识,请访问:二维码的生成细节和原理

试想这样一种场景:一伙人去同一餐馆或者在一起开会,有的人之前去过且已经使用过那个场景的wifi账号,所以一去手机就能够直接连上那里的wifi,但有的同学是第一次去,也有连接wifi的需求,这时我们一般是通过别人告知wifi账号和密码然后手动登陆,但问题是有时候已经连上wifi的人也不记得wifi的密码了,本文结合这个需求场景,做了一个wifi账号和密码分享的小demo,前提是双方都需要安装这个app,并且分享wifi的一方需要有root权限(目前是,也可以将分享wifi的客户端作为热点,然后将热点分享给其他人,这个可以自行研究),这样减少了手动输入密码的麻烦。

本文主要介绍通过二维码实现wifi分享的两个核心功能:

1、获取本机已经连接上的wifi账号、密码和加密方式;

2、给定指定内容生成二维码,扫描二维码解析出其中搭载的信息。

1、获取本机已经连接上的wifi账号、密码和加密方式:

所有的事情都可以通过下面这个类搞定:

public class WifiAdmin {
    public WifiAdmin(Context context) {
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        mWifiInfo = mWifiManager.getConnectionInfo();
    }   

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

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

    // 检查当前WIFI状态
    public int checkState() {
        return mWifiManager.getWifiState();
    }   

    // 锁定WifiLock
    public void acquireWifiLock() {
        mWifiLock.acquire();
    }   

    // 解锁WifiLock
    public void releaseWifiLock() {
        // 判断时候锁定
        if (mWifiLock.isHeld()) {
            mWifiLock.acquire();
        }
    }   

    // 创建一个WifiLock
    public void creatWifiLock() {
        mWifiLock = mWifiManager.createWifiLock("Test");
    }   

    // 得到配置好的网络
    public List<WifiConfiguration> getConfiguration() {
        return mWifiConfiguration;
    }   

    // 指定配置好的网络进行连接
    public void connectConfiguration(int index) {
        // 索引大于配置好的网络索引返回
        if (index > mWifiConfiguration.size()) {
            return;
        }
        // 连接配置好的指定ID的网络
        mWifiManager.enableNetwork(mWifiConfiguration.get(index).networkId,
                true);
    }   

    public void startScan() {
        mWifiManager.startScan();
        // 得到扫描结果
        mWifiList = mWifiManager.getScanResults();
        // 得到配置好的网络连接
        mWifiConfiguration = mWifiManager.getConfiguredNetworks();
    }   

    // 得到网络列表
    public List<ScanResult> getWifiList() {
        return mWifiList;
    }   

    // 查看扫描结果
    @SuppressLint("UseValueOf")
	public StringBuilder lookUpScan() {
    	StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < mWifiList.size(); i++) {
        	stringBuilder.append("Index_" + new Integer(i + 1).toString() + ":");
            // 将ScanResult信息转换成一个字符串包 其中把包括:BSSID、SSID、capabilities、frequency、level
            stringBuilder.append((mWifiList.get(i)).toString());
            stringBuilder.append("/n");
        }
        return stringBuilder;
    }  

    // 得到MAC地址
    public String getMacAddress() {
        return (mWifiInfo == null) ? "NULL" : mWifiInfo.getMacAddress();
    }   

    // 得到接入点的BSSID
    public String getBSSID() {
        return (mWifiInfo == null) ? "NULL" : mWifiInfo.getBSSID();
    }   

    // 得到IP地址
    public int getIPAddress() {
        return (mWifiInfo == null) ? 0 : mWifiInfo.getIpAddress();
    }   

    // 得到连接的ID
    public int getNetworkId() {
        return (mWifiInfo == null) ? 0 : mWifiInfo.getNetworkId();
    }   

    // 得到WifiInfo的所有信息包
    public WifiInfo getWifiInfo() {
        return mWifiInfo;
    }

    // 添加一个网络并连接
    public void addNetwork(WifiConfiguration wcg) {
     int wcgID = mWifiManager.addNetwork(wcg);
     boolean b =  mWifiManager.enableNetwork(wcgID, true);
     System.out.println("a--" + wcgID);
     System.out.println("b--" + b);
    }   

    // 断开指定ID的网络
    public void disconnectWifi(int netId) {
        mWifiManager.disableNetwork(netId);
        mWifiManager.disconnect();
    }   

	// 然后是一个实际应用方法,只验证过没有密码的情况:
	// 分为三种情况:1没有密码2用wep加密3用wpa加密
	public WifiConfiguration CreateWifiInfo(String SSID, String password, int 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) {
			mWifiManager.removeNetwork(tempConfig.networkId);
		}

		if (type == 1) {
			// WIFICIPHER_NOPASS
			config.wepKeys[0] = "";
			config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
			config.wepTxKeyIndex = 0;
		}
		if (type == 2) {
			// WIFICIPHER_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;
		}
		if (type == 3) {
			// 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;
	} 

	private WifiConfiguration IsExsits(String SSID) {
		List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
		if (null == existingConfigs) {
			return null;
		}
		for (WifiConfiguration existingConfig : existingConfigs) {
			System.out.println("existingConfig == " + existingConfig.toString());
			if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
				System.out.println("existingConfig.SSID == " + existingConfig.SSID + " SSID == " + SSID);
				return existingConfig;
			}
		}

		return null;
	}

    public List<UserWifiInfo> getUserWifiInfoList( ) throws Exception {
        List<UserWifiInfo> wifiInfos=new ArrayList<UserWifiInfo>();  

        Process process = null;
        DataOutputStream dataOutputStream = null;
        DataInputStream dataInputStream = null;
        StringBuffer wifiConf = new StringBuffer();
        try {
            process = Runtime.getRuntime().exec("su");
            dataOutputStream = new DataOutputStream(process.getOutputStream());
            dataInputStream = new DataInputStream(process.getInputStream());
            dataOutputStream.writeBytes("cat /data/misc/wifi/*.conf\n");
            dataOutputStream.writeBytes("exit\n");
            dataOutputStream.flush();
            InputStreamReader inputStreamReader = new InputStreamReader(
                    dataInputStream, "UTF-8");
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                wifiConf.append(line);
            }
            bufferedReader.close();
            inputStreamReader.close();
            process.waitFor();
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (dataOutputStream != null) {
                    dataOutputStream.close();
                }
                if (dataInputStream != null) {
                    dataInputStream.close();
                }
                process.destroy();
            } catch (Exception e) {
                throw e;
            }
        }     

        Pattern network = Pattern.compile("network=\\{([^\\}]+)\\}", Pattern.DOTALL);
        Matcher networkMatcher = network.matcher(wifiConf.toString() );
        while (networkMatcher.find() ) {
            String networkBlock = networkMatcher.group();
            Pattern ssid = Pattern.compile("ssid=\"([^\"]+)\"");
            Matcher ssidMatcher = ssid.matcher(networkBlock);  

            if (ssidMatcher.find() ) {
                UserWifiInfo wifiInfo=new UserWifiInfo();
                wifiInfo.Ssid=ssidMatcher.group(1);
                Pattern psk = Pattern.compile("psk=\"([^\"]+)\"");
                Matcher pskMatcher = psk.matcher(networkBlock);
                if (pskMatcher.find() ) {
                    wifiInfo.Password=pskMatcher.group(1);
                } else {
                    wifiInfo.Password="无密码";
                }
                wifiInfos.add(wifiInfo);
            }  

        }  

        return wifiInfos;
    }

    private WifiManager mWifiManager = null;
    private WifiInfo mWifiInfo = null;
    private List<ScanResult> mWifiList = null;
    private List<WifiConfiguration> mWifiConfiguration = null;
    private WifiLock mWifiLock = null;
}

使用到wifi的各种功能,记得增加相应地权限:

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" >
    </uses-permission>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >
    </uses-permission>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
    </uses-permission>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >
    </uses-permission>

2、给定指定内容生成二维码,扫描二维码解析出其中搭载的信息:

本文使用到了开源二维码项目zxing,关于zxing的更多介绍请参看:二维码、条形码扫描——使用Google ZXing

(1)将指定内容生成二维码的方法如下:

@SuppressWarnings("deprecation")
	private void generate( String result ){
		if( TextUtils.isEmpty( result ) ){
			return;
		}

		try{
            //判断result合法性
            if (result == null || "".equals(result) || result.length() < 1){
                return;
            }
            Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            //图像数据转换,使用了矩阵转换
            BitMatrix bitMatrix = new QRCodeWriter().encode(result, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);
            int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
            //下面这里按照二维码的算法,逐个生成二维码的图片,
            //两个for循环是图片横列扫描的结果
            for (int y = 0; y < QR_HEIGHT; y++){
                for (int x = 0; x < QR_WIDTH; x++){
                    if (bitMatrix.get(x, y)){
                        pixels[y * QR_WIDTH + x] = 0xff000000;
                    }else{
                        pixels[y * QR_WIDTH + x] = 0xffffffff;
                    }
                }
            }
            //生成二维码图片的格式,使用ARGB_8888
            Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
            //显示到一个ImageView上面
            mResultImg.setBackground( new BitmapDrawable( bitmap ) );

            decodeBitmap( bitmap );
        }catch (WriterException e) {
            e.printStackTrace();
        }
	}

	private String decodeBitmap( Bitmap bitmap ){
		MultiFormatReader multiFormatReader = new MultiFormatReader();
		// 解码的参数
		Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(2);
		// 可以解析的编码类型
		Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();
		if (decodeFormats == null || decodeFormats.isEmpty()) {
			decodeFormats = new Vector<BarcodeFormat>();

			// 这里设置可扫描的类型,我这里选择了都支持
			decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
			decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
			decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
		}
		hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);

		// 设置继续的字符编码格式为UTF8
		// hints.put(DecodeHintType.CHARACTER_SET, "UTF8");

		// 设置解析配置参数
		multiFormatReader.setHints(hints);

		// 开始对图像资源解码
		try {
			Result rawResult = multiFormatReader.decodeWithState(new BinaryBitmap(new HybridBinarizer( new com.uperone.zxing.decoding.BitmapLuminanceSource(bitmap))));
			mDecodeReslutTxt.setText(new StringBuilder().append("包括内容:")
					.append(rawResult.getText()).append("\n编码方式:")
					.append(rawResult.getBarcodeFormat()).toString());
		} catch (NotFoundException e) {
			e.printStackTrace();
		}

		return null;
	}

(2)解析出二维码中搭载的内容方法如下:

/**
   * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
   * reuse the same reader objects from one decode to the next.
   *
   * @param data   The YUV preview frame.
   * @param width  The width of the preview frame.
   * @param height The height of the preview frame.
   */
  private void decode(byte[] data, int width, int height) {
    long start = System.currentTimeMillis();
    Result rawResult = null;
    PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(data, width, height);
    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    try {
      rawResult = multiFormatReader.decodeWithState(bitmap);
    } catch (ReaderException re) {
      // continue
    } finally {
      multiFormatReader.reset();
    }

    if (rawResult != null) {
      long end = System.currentTimeMillis();
      Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
      Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);
      Bundle bundle = new Bundle();
      bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
      message.setData(bundle);
      //Log.d(TAG, "Sending decode succeeded message...");
      message.sendToTarget();
    } else {
      Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);
      message.sendToTarget();
    }
  }
@Override
  public void handleMessage(Message message) {
    switch (message.what) {
      case R.id.auto_focus:
        //Log.d(TAG, "Got auto-focus message");
        // When one auto focus pass finishes, start another. This is the closest thing to
        // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
        if (state == State.PREVIEW) {
          CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
        }
        break;
      case R.id.restart_preview:
        Log.d(TAG, "Got restart preview message");
        restartPreviewAndDecode();
        break;
      case R.id.decode_succeeded:
        Log.d(TAG, "Got decode succeeded message");
        state = State.SUCCESS;
        Bundle bundle = message.getData();
        Bitmap barcode = bundle == null ? null :
            (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
        activity.handleDecode((Result) message.obj, barcode);
        break;
      case R.id.decode_failed:
        // We're decoding as fast as possible, so when one decode fails, start another.
        state = State.PREVIEW;
        CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
        break;
      case R.id.return_scan_result:
        Log.d(TAG, "Got return scan result message");
        activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
        activity.finish();
        break;
      case R.id.launch_product_query:
        Log.d(TAG, "Got product query message");
        String url = (String) message.obj;
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        activity.startActivity(intent);
        break;
    }
  }
public void handleDecode(final Result obj, Bitmap barcode){
		inactivityTimer.onActivity();
		playBeepSoundAndVibrate();
		String result = obj.getText();
		if(!TextUtils.isEmpty( result ) ){
			System.out.println( "result == " + result );
			String[] results = result.split( "#" );
			String user = results[ 0 ];
			String password = results[ 1 ];
			int type = Integer.parseInt( results[ 2 ] );
			WifiAdmin wifiAdmin = new WifiAdmin(this);
	        wifiAdmin.openWifi();
	        wifiAdmin.addNetwork(wifiAdmin.CreateWifiInfo(user, password, type));

	        Toast.makeText( this, result, Toast.LENGTH_LONG ).show( );
		}
	}

本例在扫描二维码时使用到了相机功能,所以需要加上关于camera的一些权限:

<uses-permission android:name="android.permission.CAMERA" >
    </uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
    </uses-permission>

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.FLASHLIGHT" />

关于demo的详细功能和各功能的详细代码可到这里下载demo体验。

时间: 2024-10-08 20:48:07

二维码的妙用:通过Zxing实现wifi账号密码分享功能的相关文章

二维码开源库zbar、zxing使用心得

首先说明我的测试场景是“识别打印在纸上的二维码”,在扫描结果中寻找二维码并进行识别,而不是直接让摄像头对着二维码扫描. zbar和zxing用的都是自己从github上clone的c++源码/接口编译出来的dll,都是默认参数 再说结论:测了大概几千张图片,两个库的准确率差不多(由于图片场景的多样性,确切的准确率数字也没有什么意义),但是zbar的速度要快很多,大概是zxing的4-5倍.其实两个库的准确率都不太如人意,稍微模糊一点就无法识别,甚至有一些不模糊的图像也识别不出.相比之下,微信的识

提高zxing生成二维码的容错率及zxing生成二维码的边框设置

最近做了一个项目要生成二维码,跟几年前不同,最近大家都喜欢在二维码中间加logo. 加logo倒是不难,两个图片叠一起就是了,但是遇到一个新问题,logo加得太大的话,会导致二维码扫描不出来;加的太小则不怎么明显. 上网看看网上在线生成二维码的地方,发现都有容错率的设置,从7%-30%,容错率越高,二维码的有效像素点就越多. 由于我们使用的是zxing,所以我们需要看看怎么设置zxing的二维码容错率. 翻阅了zxing的源码,在QRCodeWriter.java中有这么一段: 1 ErrorC

Java二维码生成与解码工具Zxing使用

1 package com.csii.zxing.test; 2 3 import java.awt.image.BufferedImage; 4 import java.io.File; 5 import java.io.IOException; 6 import java.util.HashMap; 7 import java.util.Hashtable; 8 import java.util.Map; 9 10 import javax.imageio.ImageIO; 11 12 im

引用ZXing生成二维码

1.生成二维码 ZXing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的端口. Zxing可以实现使用手机的内置的摄像头完成条形码的扫描及解码.本文引用zxing.dll,生成二维码. using com.google.zxing.qrcode; using com.google.zxing; using com.google.zxing.common; using ByteMatrix = com.google.zxing.common.Byte

Java生成带小图标的二维码-google zxing 工具类

近期一直忙于开发微信商城项目,应客户要求,要开发个有图标的二维码.经过两次改版,终于实现了该功能(第一次没有小图标,这次才整合好的),如下是完整代码 . 该代码使用Java7开发,另外使用 core-2.2.jar jar[http://pan.baidu.com/s/1skTwHQ1] 包 . 1 package com.rick.common.utils; 2 3 4 import java.awt.Color; 5 import java.awt.Graphics2D; 6 import

【转】Android平台下利用zxing实现二维码开发

http://www.cnblogs.com/dolphin0520/p/3355728.html 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing进行二维码开发. 1.如何将zxing的Android源码导入工程. 在导入zxing的android源码之前,先去官方下载zxing的源码:http

c# 使用ZXing.dll库生成二维码

最近工作中有需要一个需求,就是把一个服务地址生成二维码,可以用来扫码分享,网上找了下方法也比较多,我这里po一下调用ZXing.dll库生成二维码的方法吧.先简单介绍一下 ZXing库,ZXing库是一个开源Java类库,可用于生成和解析多种格式的1D/2D条形码:zxing遵循Apache License 2.0,只是工具而已,是不收费哒. ZXing库的下载地址:http://zxingnet.codeplex.com/ 点击下载,下载后解压压缩包: 把Zxing加到工程应用中,以下为核心代

Android平台下利用zxing实现二维码开发

http://www.cnblogs.com/dolphin0520/p/3355728.html 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing进行二维码开发. 1.如何将zxing的Android源码导入工程. 在导入zxing的android源码之前,先去官方下载zxing的源码:http

(转)ZXing生成二维码和带logo的二维码,模仿微信生成二维码效果

场景:移动支付需要对二维码的生成与部署有所了解,掌握目前主流的二维码生成技术. 1 ZXing 生成二维码 首先说下,QRCode是日本人开发的,ZXing是google开发,barcode4j也是老美开发的,barcode4j对一维条形码处理的很好,而且支持的格式很多,当然也可以对二维码进行处理,效果个人感觉没有前两种好;ZXing对j2me,j2se,还有Android等支持也比较好,如果你是搞Android的或以后准备走Android,建议还是用zxing的比较好,毕竟都一个母亲(gool