Tổng quan về quét tìm Wi-Fi

Bạn có thể sử dụng tính năng quét tìm Wi-Fi do API WifiManager cung cấp để lấy danh sách các điểm truy cập Wi-Fi hiển thị trên thiết bị.

Quá trình quét tìm Wi-Fi

Quá trình quét có ba bước:

  1. Đăng ký một trình nghe truyền tin cho SCAN_RESULTS_AVAILABLE_ACTION. Tính năng này được gọi khi hoàn tất các yêu cầu quét, cung cấp trạng thái thành công/không thành công. Đối với các thiết bị chạy Android 10 (API cấp 29) trở lên, thông báo này sẽ được gửi cho mọi lượt quét tìm Wi-Fi đầy đủ mà nền tảng hoặc các ứng dụng khác thực hiện trên thiết bị. Các ứng dụng có thể thụ động theo dõi tất cả các lượt hoàn tất quá trình quét trên thiết bị bằng cách sử dụng thông báo truyền tin mà không tự quét.

  2. Yêu cầu quét bằng cách sử dụng WifiManager.startScan(). Hãy nhớ kiểm tra trạng thái trả về của phương thức, vì lệnh gọi có thể không thực hiện được vì bất kỳ lý do nào sau đây:

    • Yêu cầu quét có thể bị hạn chế do có quá nhiều lượt quét trong một thời gian ngắn.
    • Thiết bị ở trạng thái rảnh và tính năng quét đang tắt.
    • Phần cứng Wi-Fi báo cáo lỗi quét.
  3. Nhận kết quả quét bằng cách sử dụng WifiManager.getScanResults(). Kết quả quét được trả về là kết quả được cập nhật gần đây nhất. Kết quả này có thể là từ lần quét trước đó nếu lần quét hiện tại chưa hoàn tất hoặc không thành công. Điều này có nghĩa là bạn có thể nhận được các kết quả quét cũ hơn nếu gọi phương thức này trước khi nhận được thông báo SCAN_RESULTS_AVAILABLE_ACTION thành công.

Mã sau đây cung cấp ví dụ về cách triển khai các bước này:

Kotlin

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } else {
      scanFailure()
    }
  }
}

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

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

....

private fun scanSuccess() {
  val results = wifiManager.scanResults
  ... use new scan results ...
}

private fun scanFailure() {
  // handle failure: new scan did NOT succeed
  // consider using old scan results: these are the OLD results!
  val results = wifiManager.scanResults
  ... potentially use older scan results ...
}

Java

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 ...
}

Quy định hạn chế

Android 8.0 (API cấp 26) đã đưa ra các hạn chế về quyền và tần suất quét tìm Wi-Fi được cho phép.

Để cải thiện hiệu suất mạng, khả năng bảo mật và thời lượng pin, Android 9 (API cấp 28) đã thắt chặt các yêu cầu về quyền và giới hạn tần suất quét tìm Wi-Fi.

Quyền

Android 8.0 và Android 8.1:

Lệnh gọi thành công đến WifiManager.getScanResults() yêu cầu bất kỳ nào trong số các quyền sau đây:

Nếu ứng dụng gọi không có bất kỳ quyền nào trong số này, thì lệnh gọi sẽ không thực hiện được bằng SecurityException.

Ngoài ra, trên các thiết bị chạy Android 8.0 (API cấp 26) trở lên, bạn có thể dùng CompanionDeviceManager để thay ứng dụng của mình quét các thiết bị đồng hành ở gần mà không yêu cầu quyền truy cập thông tin vị trí. Để biết thêm thông tin về tuỳ chọn này, hãy xem bài viết Ghép nối thiết bị đồng hành.

Android 9:

Lệnh gọi thành công đến WifiManager.startScan() yêu cầu phải đáp ứng tất cả điều kiện sau đây:

Android 10 (API cấp 29) trở lên:

Lệnh gọi thành công đến WifiManager.startScan() yêu cầu phải đáp ứng tất cả điều kiện sau đây:

  • Nếu ứng dụng của bạn nhắm đến SDK Android 10 (API cấp 29) trở lên, thì ứng dụng đó sẽ có quyền ACCESS_FINE_LOCATION.
  • Nếu ứng dụng của bạn đang nhắm đến SDK thấp hơn Android 10 (API cấp 29), thì ứng dụng đó có quyền ACCESS_COARSE_LOCATION hoặc ACCESS_FINE_LOCATION.
  • Ứng dụng của bạn có quyền CHANGE_WIFI_STATE.
  • Dịch vụ vị trí được bật trên thiết bị (trong phần Cài đặt > Vị trí).

Để gọi thành công WifiManager.getScanResults(), hãy đảm bảo đáp ứng tất cả điều kiện sau:

  • Nếu ứng dụng của bạn nhắm đến SDK Android 10 (API cấp 29) trở lên, thì ứng dụng đó có quyền ACCESS_FINE_LOCATION.
  • Nếu ứng dụng của bạn đang nhắm đến SDK thấp hơn Android 10 (API cấp 29), thì ứng dụng đó có quyền ACCESS_COARSE_LOCATION hoặc ACCESS_FINE_LOCATION.
  • Ứng dụng của bạn có quyền ACCESS_WIFI_STATE.
  • Dịch vụ vị trí được bật trên thiết bị (trong phần Cài đặt > Vị trí).

Nếu ứng dụng gọi không đáp ứng tất cả các yêu cầu này thì lệnh gọi sẽ không thành công khi sử dụng SecurityException.

Điều tiết

Các giới hạn sau áp dụng cho tần suất quét bằng WifiManager.startScan().

Android 8.0 và Android 8.1:

Mỗi ứng dụng trong nền có thể quét một lần mỗi 30 phút.

Android 9:

Mỗi ứng dụng trên nền trước có thể quét 4 lần trong khoảng thời gian 2 phút. Tính năng này hỗ trợ nhiều lần quét trong thời gian ngắn.

Tất cả các ứng dụng nền kết hợp đều có thể quét một lần trong khoảng thời gian 30 phút.

Android 10 trở lên:

Các giới hạn điều tiết tương tự từ Android 9 cũng được áp dụng. Có một tuỳ chọn mới cho nhà phát triển để tắt chế độ điều tiết cho việc kiểm thử cục bộ (trong phần Tuỳ chọn cho nhà phát triển > Mạng > Điều tiết quét tìm Wi-Fi).