天天看點

Android6.0通過WiFi名稱密碼連接配接WiFi的方案

** 前言:早在去年,我曾寫過一個針對android6.0連接配接指定WiFi的文章。雖然能成功連接配接,但有好多不合理甚至錯誤的地方,是以現在對那篇文章進行重新編輯釋出**。

最近項目中有通過已知WiFi名稱和密碼連接配接傳感器WiFi,實作資料交換的需求。在網上找了許多資料發現都是複制黏貼,也有好多bug,現在我将其整理封裝并在項目中使用。

github位址:https://github.com/tangjiang24/WifiConnector

用法

step1

在根build.gradle中添加:

allprojects {
    repositories {
        maven { url "https://jitpack.io" }
    }
}      

在使用的子產品build.gradle中添加:

dependencies {
    implementation 'com.github.tangjiang24:WifiConnector:Tag'
}      

(請替換 Tag 為最新的版本号: img)

Step2

分兩種方法:

第一種:

1.将需要連接配接的activity繼承 庫中的 WifiActivity :

public class WifiConnectActivity extends WifiActivity{}      

2.直接調用父類中的 connectWifi(String ssid, String pwd, int type) 方法:

connectWifi(String ssid,String pwd,int type);      

3.重寫連接配接失敗成功的抽象方法即可:

@Override
    public void onConnectWifiSucess() {
        ToastUtil.showShortToast(this,"連接配接成功!!");
    }

    @Override
    public void onConnectWifiFail(String failMsg) {
        ToastUtil.showShortToast(this,failMsg);
    }      

第二種:

1.建構WifiConnector對象

WifiConnector connector = new WifiConnector(context);      

2.調用其connectWifi () 方法,并在回調中寫成功或者失敗後的邏輯

connector.connectWifi(ssid, pwd, WifiUtil.TYPE_WPA, new WifiConnector.WifiConnectCallBack() {
    @Override
    public void onConnectSucess() {
        Toast.makeText(WifiConnectActivity.this,"連接配接成功!!",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onConnectFail(String msg) {
        Toast.makeText(WifiConnectActivity.this,msg,Toast.LENGTH_SHORT).show();
    }
});      

參數說明:

參數名     類型     意義

ssid     String     WiFi名稱

pwd     String     WiFi 密碼

type     int     密碼類型

wifiConnectCallBack     WifiConnectCallBack     連接配接回調

三種密碼類型:

    WifiUtil.TYPE_NO_PWD(無密碼)

    WifiUtil.TYPE_WEB (WEB)

    WifiUtil.TYPE_WPA(WPA)

注意:由于Java的單繼承性,第一種方法有很大的局限,建議使用第二種方法。

​原理:

1.判斷目前手機wifi網絡是否開啟可用;

開啟WiFi代碼:

public boolean openWifi() {
        boolean sucess = true;
        if(!this.mWifiManager.isWifiEnabled()) {
            sucess = this.mWifiManager.setWifiEnabled(true);
        }

        return sucess;
    }      

開啟WiFi一般需要一定的時間,是以不能立馬去連接配接,需要等WiFi穩定可用,經測試一般2.5秒即可完成,是以我們每隔100毫秒就去判斷WiFi是否可用,代碼如下:

if(!this.openWifi()) {
            return false;
        } else {
            long timeMills = System.currentTimeMillis();

            while(this.mWifiManager.getWifiState() != 3) {
                try {
                    if(System.currentTimeMillis() - timeMills > 2500L) {
                        break;
                    }

                    Thread.sleep(100L);
                } catch (InterruptedException var8) {
                    var8.printStackTrace();
                }
            }      

2.根據WiFi名稱,擷取/建立WifiConfiguration;

首先我們需要判斷是否包含有目前WiFi名稱的WifiConfiguration,若包含則試着将其删除再添加。1.為什麼是試着删除?因為在android6.0以上,隻允許删除由本應用建立的wificonfiguratin,不能改變删除其他應用所建立的。 2.為什麼不直接連接配接而要删除再添加?因為wificonfiguratin不一定是連接配接成功後的wificonfiguratin,也有可能是手殘輸錯了密碼,這樣直接去連接配接會導緻一輩子也連接配接不上。

具體代碼如下:

private 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);
        List<WifiConfiguration> beforeConfig = this.mWifiManager.getConfiguredNetworks();
        if(tempConfig != null) {
            this.removeWifi(tempConfig.networkId);
        }

        List<WifiConfiguration> afterConfig = this.mWifiManager.getConfiguredNetworks();
        if(tempConfig != null && beforeConfig.size() == afterConfig.size()) {
            return tempConfig;
        } else {
            if(Type == 1) {
                config.allowedKeyManagement.set(0);
            }

            if(Type == 2) {
                config.hiddenSSID = true;
                config.wepKeys[0] = "\"" + Password + "\"";
                config.allowedAuthAlgorithms.set(1);
                config.allowedGroupCiphers.set(3);
                config.allowedGroupCiphers.set(2);
                config.allowedGroupCiphers.set(0);
                config.allowedGroupCiphers.set(1);
                config.allowedKeyManagement.set(0);
                config.wepTxKeyIndex = 0;
            }

            if(Type == 3) {
                config.preSharedKey = "\"" + Password + "\"";
                config.hiddenSSID = true;
                config.allowedAuthAlgorithms.set(0);
                config.allowedGroupCiphers.set(2);
                config.allowedKeyManagement.set(1);
                config.allowedPairwiseCiphers.set(1);
                config.allowedGroupCiphers.set(3);
                config.allowedPairwiseCiphers.set(2);
                config.status = 2;
            }

            return config;
        }
    }      

3.注冊網絡變化的廣播,當監聽到網絡連接配接上時,判斷目前WiFi網絡的名稱是否和目标WiFi的一緻;

廣播中主要代碼:

NetworkInfo info = (NetworkInfo)intent.getParcelableExtra("networkInfo");
        Log.i("wifi:", "接受到網絡連接配接變化的廣播,目前網絡狀态為:" + info.getState());
        if(info.getState().equals(State.CONNECTED)) {
            WifiManager wifiManager = (WifiManager)context.getSystemService("wifi");
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            String ssid = wifiInfo.getSSID();
            Log.i("wifi:", "接受到網絡連接配接變化的廣播,已連接配接的網絡的ssid=" + ssid);
            this.mListner.isConnectMyWifi(ssid);
        }
 
public void setOnWifiConnetListner(WifiConnectReceiver.onWifiConnectListner listner) {
        this.mListner = listner;
    }

    public interface onWifiConnectListner {
        void isConnectMyWifi(String var1);
    }      

activity中實作receiver中聲明的接口onWifiConnectListner,主要代碼:

public void isConnectMyWifi(String s) {
        if(!TextUtils.isEmpty(this.ssid)) {
            if(s.equals("\"" + this.ssid + "\"")) {
                this.handler.removeMessages(1);
                this.handler.removeMessages(2);
                this.handler.sendEmptyMessageDelayed(1, 1000L);
            } else {
                Log.i("wifi:", "未連接配接到指定網絡!");
                this.sendFailMessage("未連接配接到指定網絡!", 1L);
            }
        }

    }

    private void registWifiConnectReceiver() {
        if(!this.mReceiverTag) {
            this.wifiConnectReceiver = new WifiConnectReceiver();
            this.mReceiverTag = true;
            this.wifiConnectReceiver.setOnWifiConnetListner(this);
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("android.net.wifi.STATE_CHANGE");
            this.registerReceiver(this.wifiConnectReceiver, intentFilter);
        }      

總結及注意點:

1.開啟WiFi時需要時間的,必須等穩定後再去連接配接;

2.手機中儲存的wificonfiguratin不一定可用,連接配接時需要先删除再添加;

3.在6.0以後調用mWifiManager.removeNetwork(netId)隻對本應用添加的有效;

config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);