Android Wi-Fi網(wǎng)絡(luò)連接API

一、背景
從Android Q開始,原WiFi操作API部分被廢棄,eg: enableNetwork、getConfiguredNetworks等。取而代之的是WifiNetworkSpecifier,WifiNetworkSuggestion等新API(主要從安全和用戶體驗(yàn)的角度出發(fā),廢棄了之前太過底層的API)。
二、新版API簡介
Android Q增加了對點(diǎn)對等連接的支持。此功能使您的應(yīng)用可以通過使用WifiNetworkSpecifier 描述所請求網(wǎng)絡(luò)的屬性來提示用戶更改設(shè)備所連接的接入點(diǎn)。對等連接用于非網(wǎng)絡(luò)提供目的,例如Chromecast和Google Home硬件等輔助設(shè)備的引導(dǎo)配置。

使用此API時,您將使用以下流程:

  1. 使用創(chuàng)建Wi-Fi網(wǎng)絡(luò)說明符 WifiNetworkSpecifier.Builder

  2. 設(shè)置網(wǎng)絡(luò)過濾器以匹配要連接的網(wǎng)絡(luò)以及所需的憑據(jù)。

  3. 決定的組合SSIDSSID patternBSSID,和BSSID pattern 設(shè)置在每個請求之后,網(wǎng)絡(luò)過濾器,必須符合以下要求:

    • 每個請求應(yīng)當(dāng)提供的至少一個SSIDSSID patternBSSID,或BSSID pattern
    • 每個請求只能設(shè)置一個SSIDSSID pattern
    • 每個請求只能設(shè)置一個BSSIDBSSID pattern
  4. 將說明符與NetworkCallback 實(shí)例一起添加到網(wǎng)絡(luò)請求中 以跟蹤請求的狀態(tài)。

    如果用戶接受請求并且與網(wǎng)絡(luò)的連接成功, NetworkCallback.onAvailable() 則在回調(diào)對象上調(diào)用。如果用戶拒絕請求或者與網(wǎng)絡(luò)的連接不成功, NetworkCallback.onUnavailable() 則在回調(diào)對象上調(diào)用。

點(diǎn)對點(diǎn)連接不需要位置或Wi-Fi權(quán)限。發(fā)起連接到對等設(shè)備的請求會在同一設(shè)備上啟動一個對話框,該設(shè)備的用戶可以從該對話框接受連接請求。

繞過用戶批準(zhǔn)

一旦用戶批準(zhǔn)網(wǎng)絡(luò)連接以響應(yīng)來自特定應(yīng)用的請求,該設(shè)備就存儲對特定接入點(diǎn)的批準(zhǔn)。如果應(yīng)用程序再次發(fā)出連接到該訪問點(diǎn)的特定請求,則設(shè)備將跳過用戶批準(zhǔn)階段并自動連接到網(wǎng)絡(luò)。如果用戶選擇在連接到API請求的網(wǎng)絡(luò)時忘記網(wǎng)絡(luò),則會刪除此應(yīng)用程序和網(wǎng)絡(luò)組合的存儲批準(zhǔn),并且應(yīng)用程序的任何將來請求都需要再次由用戶批準(zhǔn)。如果應(yīng)用程序發(fā)出非特定(例如使用SSID或BSSID模式)請求,則用戶將需要批準(zhǔn)該請求。
三、實(shí)現(xiàn)方式
官方適用于對等連接的 WLAN 網(wǎng)絡(luò)請求 API | Android Developers (google.cn)
但試過沒有成功,其他較多的實(shí)現(xiàn)方式主要有兩種:
一、手機(jī)WIFI設(shè)置界面

          startActivity(new Intent( android.provider.Settings.ACTION_WIFI_SETTINGS));
         //或者
          startActivity(new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY));

第二種方式就是降低API為28

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.zyd.androidwifi"
        minSdk 26
        targetSdk 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

java實(shí)現(xiàn)示例:

public void wifiBeforeQ(String wifiName, String wifiPwd) {
    if (mWifiManager == null) {
        Log.i(TAG, " ***** init first ***** ");
        return;
    }

    String mWifiName = "\"" + wifiName + "\"";

    /**
     * 判斷定位權(quán)限
     */
    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        return;
    }
    //獲取wifi列表
    List wifiList = mWifiManager.getConfiguredNetworks();
    boolean bFindInList = false;
    for (int i = 0; i < wifiList.size(); ++i) {
        WifiConfiguration wifiInfo0 = (WifiConfiguration) wifiList.get(i);

        // 先找到對應(yīng)的wifi
        if (mWifiName.equals(wifiInfo0.SSID) || wifiName.equals(wifiInfo0.SSID)) {
            // 1、 先啟動,可能已經(jīng)輸入過密碼,可以直接啟動
            Log.i(TAG, " set wifi 1 = " + wifiInfo0.SSID);
            doChange2Wifi(wifiInfo0.networkId);
            return;
        }
    }

    // 2、如果wifi還沒有輸入過密碼,嘗試輸入密碼,啟動wifi
    if (!bFindInList) {
        WifiConfiguration wifiNewConfiguration = createWifiInfo(wifiName, wifiPwd);//使用wpa2的wifi加密方式
        int newNetworkId = mWifiManager.addNetwork(wifiNewConfiguration);
        if (newNetworkId == -1) {
            Log.e(TAG, "操作失敗,需要您到手機(jī)wifi列表中取消對設(shè)備連接的保存");
        } else {
            doChange2Wifi(newNetworkId);
        }
    }
}

第三種不降A(chǔ)PI實(shí)現(xiàn)方式(不過沒有成功)

@RequiresApi(api = Build.VERSION_CODES.Q)
public void wifiAfterQ(String wifiName, String wifiPwd) {
    Log.i(TAG, " ***** changeToWifiAfterQ first ***** ");
    if (mWifiManager == null || connectivityManager == null) {
        Log.i(TAG, " ***** init first ***** ");
        return;
    }

    /**
     * 判斷定位權(quán)限
     */
    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        return;
    }
    //獲取wifi掃描列表
//        List<ScanResult> wifiList = mWifiManager.getScanResults();
//        ScanResult scan = null;
//        for (ScanResult scanResult : wifiList) {
//            if (wifiName.equals(scanResult.SSID)) {
//                scan = scanResult;
//                break;
//            }
//        }
    //掃描到了Wi-Fi
//        if (null != scan) {
    //setSsidPattern/setSsid/setBssidPattern/setBssid should be invoked for specifier
    NetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
//                        .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
            .setSsid(wifiName)
            .setWpa2Passphrase(wifiPwd)
//                .setBssid(MacAddress.fromString(scan.BSSID))
            .build();

    NetworkRequest request =
            new NetworkRequest.Builder()
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                    .setNetworkSpecifier(specifier)
                    .build();

    networkCallback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(@NonNull Network network) {
            super.onAvailable(network);
            Log.i(TAG, "onAvailable 切換到指定wifi成功"+network);
            connectivityManager.bindProcessToNetwork(network);
            connectivityManager.getNetworkInfo(network);
            NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
            boolean connected = networkInfo.isConnected();

            boolean available = networkInfo.isAvailable();
            NetworkInfo.DetailedState detailedState = networkInfo.getDetailedState();
            Log.i(TAG, "onAvailable connected= "+connected);
            Log.i(TAG, "onAvailable available= "+available);
            Log.i(TAG, "onAvailable detailedState= "+detailedState);

        }

        @Override
        public void onUnavailable() {
            super.onUnavailable();
            Log.i(TAG, "onUnavailable 切換到指定wifi失敗");
            connectivityManager.unregisterNetworkCallback(networkCallback);
        }
    };
 // connectivityManager.registerNetworkCallback(request, networkCallback);
    connectivityManager.requestNetwork(request, networkCallback);

//        }else{
//            Log.e(TAG, "未找到目標(biāo)Wi-Fi");
//        }

}

四、Wi-Fi Easy連接
通過Android Q,您可以使用Easy Connect為對等設(shè)備配置Wi-Fi憑據(jù),以替代已棄用的WPS。應(yīng)用可以使用ACTION_PROCESS_WIFI_EASY_CONNECT_URIintent 將Easy Connect集成到其設(shè)置和配置流程中 。此意圖需要URI。調(diào)用應(yīng)用程序可以通過各種方法檢索URI,包括從貼紙或顯示器掃描QR碼,或通過掃描藍(lán)牙LE或NFC廣告。

URI可用后,您可以使用ACTION_PROCESS_WIFI_EASY_CONNECT_URIintent 配置對等設(shè)備的Wi-Fi憑據(jù)。這允許用戶選擇要共享的Wi-Fi網(wǎng)絡(luò)并安全地傳輸憑證。

Easy Connect不需要位置或Wi-Fi權(quán)限。

注意:在使用此意圖之前,應(yīng)用程序必須通過調(diào)用驗(yàn)證設(shè)備是否支持Easy ConnectWifiManager.isEasyConnectSupported()

五、Wi-Fi Direct連接API
在WifiP2pConfig和WifiP2pManagerAPI類在Android Q的更新,以支持使用預(yù)定信息的快速連接建立功能的Wi-Fi直連。該信息通過側(cè)通道共享,例如藍(lán)牙或NFC。

以下代碼示例顯示如何使用預(yù)定信息創(chuàng)建組:
Kotlin語言寫法

val manager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
val channel = manager.initialize(this, mainLooper, null)

// prefer 5G band for this group
val config = WifiP2pConfig.Builder()
.setNetworkName("networkName")
.setPassphrase("passphrase")
.enablePersistentMode(false)
.setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_5GHZ)
.build()

// create a non-persistent group on 5GHz
manager.createGroup(channel, config, null)

Java語言寫法

WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
Channel channel = manager.initialize(this, getMainLooper(), null);

// prefer 5G band for this group
WifiP2pConfig config = new WifiP2pConfig.Builder()
.setNetworkName("networkName")
.setPassphrase("passphrase")
.enablePersistentMode(false)
.setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_5GHZ)
.build();

// create a non-persistent group on 5GHz
manager.createGroup(channel, config, null);

要使用憑據(jù)加入組,請使用manager.createGroup()以下內(nèi)容替換:

Kotlin語言寫法

manager.connect(channel, config, null)

Java語言寫法

manager.connect(channel, config, null);

參考Android Q(10.0)的新功能和API

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容