Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Quét và hiển thị danh sách WiFi khả dụng trên Android

Android cung cấp WifiManager và BroadcastReceiver để quét mạng WiFi xung quanh. Từ Android 6.0 (Marshmallow), cần quyền ACCESS_COARSE_LOCATION hoặc ACCESS_FINE_LOCATION mới quét được.

Yêu cầu quyền (Manifest)

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Android 13+ cần thêm -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />

Bước 1: Layout chính (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="16dp"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/wifiList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/scanBtn" />

    <Button
        android:id="@+id/scanBtn"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_margin="15dp"
        android:text="Quét WiFi" />
</RelativeLayout>

Bước 2: BroadcastReceiver xử lý kết quả quét

package com.example.wifiscanner;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

public class WifiReceiver extends BroadcastReceiver {
    private final WifiManager wifiManager;
    private final ListView listView;

    public WifiReceiver(WifiManager wifiManager, ListView listView) {
        this.wifiManager = wifiManager;
        this.listView = listView;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) {
            List<ScanResult> results = wifiManager.getScanResults();
            ArrayList<String> displayList = new ArrayList<>();

            for (ScanResult result : results) {
                String item = result.SSID + " | " + result.capabilities + " | Level: " + result.level + " dBm";
                displayList.add(item);
            }

            ArrayAdapter<String> adapter = new ArrayAdapter<>(
                context, android.R.layout.simple_list_item_1, displayList);
            listView.setAdapter(adapter);

            Toast.makeText(context, "Tìm thấy " + results.size() + " mạng", Toast.LENGTH_SHORT).show();
        }
    }
}

Bước 3: MainActivity.java - Quản lý vòng đời, quyền, quét

package com.example.wifiscanner;

import android.Manifest;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class MainActivity extends AppCompatActivity {
    private static final int REQ_LOCATION_PERM = 1001;

    private ListView wifiListView;
    private Button scanButton;
    private WifiManager wifiManager;
    private WifiReceiver wifiReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        wifiListView = findViewById(R.id.wifiList);
        scanButton = findViewById(R.id.scanBtn);
        wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

        // Bật WiFi nếu tắt
        if (wifiManager != null && !wifiManager.isWifiEnabled()) {
            wifiManager.setWifiEnabled(true);
            Toast.makeText(this, "Đang bật WiFi...", Toast.LENGTH_LONG).show();
        }

        scanButton.setOnClickListener(v -> requestPermissionAndScan());
    }

    private void requestPermissionAndScan() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // Android 13+ dùng NEARBY_WIFI_DEVICES
            String perm = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
                ? Manifest.permission.NEARBY_WIFI_DEVICES
                : Manifest.permission.ACCESS_COARSE_LOCATION;

            if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{perm}, REQ_LOCATION_PERM);
            } else {
                startScan();
            }
        } else {
            startScan();
        }
    }

    private void startScan() {
        if (wifiManager != null) {
            boolean started = wifiManager.startScan();
            Toast.makeText(this, started ? "Đang quét..." : "Quét thất bại", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        // Đăng ký receiver khi resume
        wifiReceiver = new WifiReceiver(wifiManager, wifiListView);
        IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        registerReceiver(wifiReceiver, filter);
        requestPermissionAndScan(); // Tự động quét khi mở app
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Hủy đăng ký tránh leak
        if (wifiReceiver != null) {
            try { unregisterReceiver(wifiReceiver); } catch (Exception ignored) {}
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQ_LOCATION_PERM) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startScan();
            } else {
                Toast.makeText(this, "Cần cấp quyền vị trí để quét WiFi", Toast.LENGTH_LONG).show();
            }
        }
    }
}

Lưu ý quan trọng theo phiên bản Android

Android Version Quyền bắt buộc Ghi chú
6.0 - 12 (M - S)ACCESS_COARSE_LOCATION hoặc ACCESS_FINE_LOCATIONRuntime permission bắt buộc
13+ (Tiramisu+)NEARBY_WIFI_DEVICESKhông cần Location, nhưng cần khai báo uses-permission
Tất cảACCESS_WIFI_STATE, CHANGE_WIFI_STATEKhai báo Manifest

ScanResult thông tin hữu ích

  • SSID: Tên mạng (có thể bị ẩn)
  • BSSID: MAC address AP
  • capabilities: Bảo mật (WPA2, WEP, OPEN...)
  • level: Độ mạnh tín hiệu (dBm, âm, càng gần 0 càng mạnh)
  • frequency: Tần số (2.4GHz / 5GHz)
  • timestamp: Thời điểm quét

Tối ưu hóa

  • Dùng RecyclerView thay ListView cho danh sách lớn.
  • Lọc trùng SSID, sắp xếp theo level giảm dần.
  • Throttle quét: không gọi startScan() liên tục, dùng Handler delay 5-10s.
  • Android 10+ hạn chế quét nền, chỉ quét khi app foreground.

Chạy thử

Cấp quyền vị trí khi hộp thoại hiện ra. Nhấn "Quét WiFi", ListView hiển thị các mạng xung quanh kèm cường độ tín hiệu.