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_LOCATION | Runtime permission bắt buộc |
| 13+ (Tiramisu+) | NEARBY_WIFI_DEVICES | Không cần Location, nhưng cần khai báo uses-permission |
| Tất cả | ACCESS_WIFI_STATE, CHANGE_WIFI_STATE | Khai báo Manifest |
ScanResult thông tin hữu ích
SSID: Tên mạng (có thể bị ẩn)BSSID: MAC address APcapabilities: 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
RecyclerViewthay 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.