日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Android 獲取Wifi列表詳解(包含動態(tài)權(quán)限申請)

作者:柴華松 更新時間: 2023-09-17 編程語言

WLAN 掃描流程
掃描流程分為三步:

  1. 為 SCAN_RESULTS_AVAILABLE_ACTION 注冊一個廣播監(jiān)聽器,系統(tǒng)會在完成掃描請求時調(diào)用此監(jiān)聽器,提供其成功/失敗狀態(tài)。對于搭載 Android 10(API 級別 29)及更高版本的設(shè)備,系統(tǒng)將針對平臺或其他應(yīng)用在設(shè)備上執(zhí)行的所有完整 WLAN 掃描發(fā)送此廣播。應(yīng)用可以使用廣播被動監(jiān)聽設(shè)備上所有掃描的完成情況,無需發(fā)出自己的掃描。
  2. 使用 WifiManager.startScan() 請求掃描。請務(wù)必檢查方法的返回狀態(tài),因?yàn)檎{(diào)用可能因以下任一原因失敗:
    - 由于短時間掃描過多,掃描請求可能遭到節(jié)流。
    - 設(shè)備處于空閑狀態(tài),掃描已停用。
    - WLAN 硬件報告掃描失敗。
  3. 使用 WifiManager.getScanResults() 獲取掃描結(jié)果。系統(tǒng)返回的掃描結(jié)果為最近更新的結(jié)果,但如果當(dāng)前掃描尚未完成或成功,可能會返回以前掃描的結(jié)果。也就是說,如果在收到成功的 SCAN_RESULTS_AVAILABLE_ACTION 廣播前調(diào)用此方法,您可能會獲得較舊的掃描結(jié)果。

以下代碼提供了如何實(shí)現(xiàn)這些步驟的示例:

WifiManager wifiManager = (WifiManager)
                   context.getSystemService(Context.WIFI_SERVICE);

BroadcastReceiver wifiScanReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context c, Intent intent) {
    boolean success = intent.getBooleanExtra(
                       WifiManager.EXTRA_RESULTS_UPDATED, false);
    if (success) {
      scanSuccess();
    } else {
      // scan failure handling
      scanFailure();
    }
  }
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
context.registerReceiver(wifiScanReceiver, intentFilter);

boolean success = wifiManager.startScan();
if (!success) {
  // scan failure handling
  scanFailure();
}

....

private void scanSuccess() {
  List<ScanResult> results = wifiManager.getScanResults();
  ... use new scan results ...
}

private void scanFailure() {
  // handle failure: new scan did NOT succeed
  // consider using old scan results: these are the OLD results!
  List<ScanResult> results = wifiManager.getScanResults();
  ... potentially use older scan results ...
}

限制
Android 8.0(API 級別 26)引入了有關(guān)權(quán)限和 WLAN 掃描允許頻率的限制。

為了提高網(wǎng)絡(luò)性能和安全性,延長電池續(xù)航時間,Android 9(API 級別 28)收緊了權(quán)限要求,并進(jìn)一步限制 WLAN 掃描頻率。

權(quán)限
注意:在以下提到位置權(quán)限或位置收集邏輯的各個部分中,請記住,當(dāng)應(yīng)用在后臺運(yùn)行時,獲取位置信息訪問權(quán)限對于應(yīng)用的核心功能而言至關(guān)重要,同時需要向用戶提供適當(dāng)?shù)穆暶鳌?br>Android 8.0 和 Android 8.1:

成功調(diào)用 WifiManager.getScanResults() 需要以下任意一項(xiàng)權(quán)限:

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
CHANGE_WIFI_STATE

對于上述權(quán)限,如果調(diào)用應(yīng)用一項(xiàng)都不具備,調(diào)用將會失敗,并顯示 SecurityException。

或者,在搭載 Android 8.0(API 級別 26)及更高版本的設(shè)備上,您可以使用 CompanionDeviceManager 代表應(yīng)用對附近的配套設(shè)備執(zhí)行掃描,而不需要位置權(quán)限。如需詳細(xì)了解此選項(xiàng),請參閱配套設(shè)備配對。

Android 9:

成功調(diào)用 WifiManager.startScan() 需要滿足以下所有條件:

  • 應(yīng)用擁有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 權(quán)限。
  • 應(yīng)用擁有 CHANGE_WIFI_STATE 權(quán)限。
  • 設(shè)備已啟用位置信息服務(wù)(位于設(shè)置 > 位置信息下)。

Android 10(API 級別 29)及更高版本:

成功調(diào)用 WifiManager.startScan() 需要滿足以下所有條件:

  • 如果您的應(yīng)用以 Android 10(API 級別 29)SDK 或更高版本為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_FINE_LOCATION 權(quán)限。
  • 如果您的應(yīng)用以低于 Android 10(API 級別 29)的 SDK 為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 權(quán)限。
  • 應(yīng)用擁有 CHANGE_WIFI_STATE 權(quán)限。
  • 設(shè)備已啟用位置信息服務(wù)(位于設(shè)置 > 位置信息下)。

若要成功調(diào)用 WifiManager.getScanResults(),請確保滿足以下所有條件:

  • 如果您的應(yīng)用以 Android 10(API 級別 29)SDK 或更高版本為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_FINE_LOCATION 權(quán)限。
  • 如果您的應(yīng)用以低于 Android 10(API 級別 29)的 SDK 為目標(biāo)平臺,應(yīng)用需要擁有 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 權(quán)限。
  • 應(yīng)用擁有 ACCESS_WIFI_STATE 權(quán)限。
  • 設(shè)備已啟用位置信息服務(wù)(位于設(shè)置 > 位置信息下)。

如果調(diào)用應(yīng)用無法滿足上述所有要求,調(diào)用將失敗,并顯示 SecurityException。

節(jié)流
使用 WifiManager.startScan() 掃描的頻率適用以下限制。

Android 8.0 和 Android 8.1:

每個后臺應(yīng)用可以在 30 分鐘內(nèi)掃描一次。

Android 9:

每個前臺應(yīng)用可以在 2 分鐘內(nèi)掃描四次。這樣便可在短時間內(nèi)進(jìn)行多次掃描。

所有后臺應(yīng)用總共可以在 30 分鐘內(nèi)掃描一次。

Android 10 及更高版本:

適用 Android 9 的節(jié)流限制。新增一個開發(fā)者選項(xiàng),用戶可以關(guān)閉節(jié)流功能以便進(jìn)行本地測試(位于開發(fā)者選項(xiàng) > 網(wǎng)絡(luò) > WLAN 掃描調(diào)節(jié)下)。

實(shí)際調(diào)試代碼如下:

package com.mob.testwifi;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;

import java.util.List;

public class MainActivity extends AppCompatActivity {
	WifiManager wifiManager;
	TextView tv;

	@RequiresApi(api = Build.VERSION_CODES.M)
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tv = findViewById(R.id.result);
		if (ContextCompat.checkSelfPermission(
				MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) ==
				PackageManager.PERMISSION_GRANTED) {
			// You can use the API that requires the permission.
			wifiManager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);

			IntentFilter intentFilter = new IntentFilter();
			intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
			registerReceiver(wifiScanReceiver, intentFilter);
			boolean success = wifiManager.startScan();
			if (!success) {
				// scan failure handling
				scanFailure();
			}
		} else {
			// You can directly ask for the permission.
			requestPermissions(
					new String[] {
							Manifest.permission.ACCESS_COARSE_LOCATION,
							Manifest.permission.ACCESS_FINE_LOCATION,
					},
					1);
		}
	}


	BroadcastReceiver wifiScanReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context c, Intent intent) {
			boolean success = intent.getBooleanExtra(
					WifiManager.EXTRA_RESULTS_UPDATED, false);
			tv.setText("success:\n" + success);
			if (success) {
				scanSuccess();
			} else {
				// scan failure handling
				scanFailure();
			}
		}
	};
	private void scanSuccess() {
		List<ScanResult> results = wifiManager.getScanResults();
		tv.setText(results.toString());
	}

	private void scanFailure() {
		// handle failure: new scan did NOT succeed
		// consider using old scan results: these are the OLD results!
		List<ScanResult> results = wifiManager.getScanResults();
		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				tv.setText("scanFailure:\n" + results.toString());
			}
		});
	}
}

注:
本文參考Android官方開發(fā)文檔

原文鏈接:https://blog.csdn.net/chaihuasong/article/details/120281705

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新