이 튜토리얼에서는 안드로이드 앱에서 프로그래밍 방식으로 주변의 Wi-Fi 네트워크를 스캔하고, 검색된 네트워크 목록을 화면에 표시하는 방법을 단계별로 알아봅니다. Wi-Fi 스캔은 WifiManager.startScan()으로 스캔을 시작하고, 스캔이 완료되면 발생하는 SCAN_RESULTS_AVAILABLE_ACTION 브로드캐스트를 BroadcastReceiver에서 받아 처리하는 구조로 동작합니다.
1단계 — 새 프로젝트 만들기
Android Studio를 실행한 뒤 File ⇒ New Project를 선택하고, 새 프로젝트 생성에 필요한 모든 정보를 입력하여 프로젝트를 만듭니다.
2단계 — 레이아웃 작성 (res/layout/activity_main.xml)
스캔된 Wi-Fi 네트워크 목록을 보여줄 ListView와, 스캔을 시작하는 Button을 배치한 레이아웃입니다.
<?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"
android:orientation = "vertical"
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_gravity = "bottom"
android:layout_margin = "15dp"
android:text = "Scan WiFi" />
</RelativeLayout>3단계 — MainActivity.java 작성
앱 시작 시 Wi-Fi가 꺼져 있으면 자동으로 켜고, 버튼을 누르면 위치 권한(ACCESS_COARSE_LOCATION)을 확인한 후 스캔을 시작하는 메인 액티비티 코드입니다. Android 6.0(마시멜로) 이상에서는 위치 권한이 승인되어야만 스캔 결과를 가져올 수 있습니다.
package com.example.myapplication;
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.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private ListView wifiList;
private WifiManager wifiManager;
private final int MY_PERMISSIONS_ACCESS_COARSE_LOCATION = 1;
WifiReceiver receiverWifi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wifiList = findViewById(R.id.wifiList);
Button buttonScan = findViewById(R.id.scanBtn);
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (!wifiManager.isWifiEnabled()) {
Toast.makeText(getApplicationContext(), "Turning WiFi ON...", Toast.LENGTH_LONG).show();
wifiManager.setWifiEnabled(true);
}
buttonScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_ACCESS_COARSE_LOCATION);
} else {
wifiManager.startScan();
}
}
});
}
@Override
protected void onPostResume() {
super.onPostResume();
receiverWifi = new WifiReceiver(wifiManager, wifiList);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(receiverWifi, intentFilter);
getWifi();
}
private void getWifi() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Toast.makeText(MainActivity.this, "version >= marshmallow", Toast.LENGTH_SHORT).show();
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "location turned off", Toast.LENGTH_SHORT).show();
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_ACCESS_COARSE_LOCATION);
} else {
Toast.makeText(MainActivity.this, "location turned on", Toast.LENGTH_SHORT).show();
wifiManager.startScan();
}
} else {
Toast.makeText(MainActivity.this, "scanning", Toast.LENGTH_SHORT).show();
wifiManager.startScan();
}
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiverWifi);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSIONS_ACCESS_COARSE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "permission granted", Toast.LENGTH_SHORT).show();
wifiManager.startScan();
} else {
Toast.makeText(MainActivity.this, "permission not granted", Toast.LENGTH_SHORT).show();
return;
}
break;
}
}
}4단계 — WifiReceiver 구현
스캔 완료 브로드캐스트를 수신하면 getScanResults()로 결과 목록을 가져오고, 각 네트워크의 SSID와 보안 방식(capabilities)을 ListView에 표시하는 리시버 클래스입니다.
package com.example.myapplication;
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;
class WifiReceiver extends BroadcastReceiver {
WifiManager wifiManager;
StringBuilder sb;
ListView wifiDeviceList;
public WifiReceiver(WifiManager wifiManager, ListView wifiDeviceList) {
this.wifiManager = wifiManager;
this.wifiDeviceList = wifiDeviceList;
}
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
sb = new StringBuilder();
List<ScanResult> wifiList = wifiManager.getScanResults();
ArrayList<String> deviceList = new ArrayList<>();
for (ScanResult scanResult : wifiList) {
sb.append("\n").append(scanResult.SSID).append(" - ").append(scanResult.capabilities);
deviceList.add(scanResult.SSID + " - " + scanResult.capabilities);
}
Toast.makeText(context, sb, Toast.LENGTH_SHORT).show();
ArrayAdapter arrayAdapter = new ArrayAdapter(context, android.R.layout.simple_list_item_1, deviceList.toArray());
wifiDeviceList.setAdapter(arrayAdapter);
}
}
}5단계 — AndroidManifest.xml 권한 설정
Wi-Fi 스캔을 위해서는 위치 권한과 함께 Wi-Fi 상태 확인 및 변경 권한을 매니페스트에 반드시 선언해야 합니다.
<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
package = "com.example.myapplication">
<uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name = "android.permission.CHANGE_WIFI_STATE" />
<application
android:allowBackup = "true"
android:icon = "@mipmap/ic_launcher"
android:label = "@string/app_name"
android:roundIcon = "@mipmap/ic_launcher_round"
android:supportsRtl = "true"
android:theme = "@style/AppTheme">
<activity android:name = "com.example.myapplication.MainActivity">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>앱 실행 및 결과 확인
이제 애플리케이션을 실행해 보겠습니다. 실제 Android 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 다음, 툴바에서 Run
아이콘을 클릭합니다. 옵션 목록에서 자신의 모바일 기기를 선택하면, 기기 화면에 아래와 같은 기본 화면이 표시됩니다.

참고 사항
Android 6.0 이상에서는 Wi-Fi 스캔 결과를 얻으려면 위치 권한뿐 아니라 기기의 위치 서비스(GPS)도 켜져 있어야 합니다. 또한 Android 9(API 28)부터는 백그라운드 앱의 스캔이 2분당 최대 4회로 제한되므로, 짧은 시간에 연속으로 스캔을 호출할 때는 이러한 제한(throttling)을 고려해 설계하는 것이 좋습니다.