二維碼的妙用:通過Zxing實現wifi帳號密碼分享功能,zxingwifi
二維碼是搭載資訊的一種載體,通過二維碼可以傳遞名片、網址、商品資訊等,本文講到二維碼的另外一種妙用:通過二維碼實現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_NOPASSconfig.wepKeys[0] = "";config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);config.wepTxKeyIndex = 0;}if (type == 2) {// WIFICIPHER_WEPconfig.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_WPAconfig.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體驗。
怎利用zxing的二維碼編碼功可以將代碼(例如A,B,C)編碼成二維碼
www.apkbus.com/...139981
此處是一個網友分享的二維碼產生和識別的教程,附有Demo,你去瞭解一下吧,希望對你有協助!望採納!
我們自己開發的二維碼用戶端拍碼功可以用的Zxing
您這個自己解決的二維碼東東,恐怕沒人會跟您這邊說吧!現在都要花錢買的啊