안드로이드 WiFi 스캐너 앱 개발 방법
이 글에서는 안드로이드 기기에서 주변의 WiFi 네트워크를 검색해 목록으로 보여주는 WiFi 스캐너 앱을 만드는 과정을 단계별로 살펴봅니다. 핵심 구성 요소는 WiFi 기능을 제어하는 WifiManager, 스캔 결과를 비동기적으로 수신하는 BroadcastReceiver, 그리고 결과를 화면에 출력하는 ListView입니다.
특히 안드로이드 6.0(마시멜로) 이상에서는 WiFi 스캔 시 위치 권한(ACCESS_COARSE_LOCATION)이 반드시 필요하므로, 런타임 권한 처리 로직까지 함께 구현하는 점이 이 예제의 핵심입니다.
1단계 – 새 프로젝트 만들기
Android Studio에서 File → New Project 메뉴로 이동한 후, 새 프로젝트 생성에 필요한 정보를 모두 입력해 프로젝트를 생성합니다.
2단계 – 레이아웃 작성 (res/layout/activity_main.xml)
화면 상단에는 스캔된 네트워크를 표시할 ListView를, 하단에는 스캔을 시작하는 Button을 배치합니다. 아래 코드를 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" 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 작성 (src/MainActivity.java)
MainActivity에서는 앱 시작 시 WiFi가 꺼져 있으면 자동으로 켜고, 스캔 버튼을 누르면 위치 권한을 확인한 뒤 스캔을 시작합니다. 또한 onPostResume()에서 브로드캐스트 리시버를 등록하고 onPause()에서 해제하여 액티비티 생명주기에 맞게 리소스를 관리합니다.
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 작성 (src/WifiReceiver.java)
WifiReceiver는 스캔 완료 시 발생하는 시스템 브로드캐스트(SCAN_RESULTS_AVAILABLE_ACTION)를 수신하면 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)
WiFi 스캔 기능을 사용하려면 아래 세 가지 권한이 필요합니다.
ACCESS_COARSE_LOCATION– 근처 네트워크 검색에 필요한 위치 권한 (안드로이드 6.0 이상 필수)ACCESS_WIFI_STATE– WiFi 상태 조회 권한CHANGE_WIFI_STATE– 스캔 시작 등 WiFi 상태 변경 권한
<?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 Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤, 툴바의 Run
아이콘을 클릭하세요. 목록에서 자신의 모바일 기기를 선택하면 기기에 아래와 같은 기본 화면이 표시됩니다.

개발 시 알아두면 좋은 팁
- 위치 서비스 확인: 안드로이드 6.0 이상에서는 기기의 위치 서비스가 꺼져 있으면 스캔 결과가 반환되지 않습니다. 결과가 비어 있다면 GPS(위치 서비스)가 켜져 있는지 먼저 확인하세요.
- 스캔 빈도 제한: 안드로이드 9(API 28)부터는 앱당 2분 동안 최대 4회로 스캔이 제한(throttling)되므로, 짧은 시간에 반복 호출하면 실패할 수 있습니다.
- WiFi 자동 켜기 제한: 최신 안드로이드 버전에서는
setWifiEnabled(true)가 타사 앱에서 더 이상 동작하지 않으므로, 사용자에게 설정 화면에서 직접 WiFi를 켜도록 안내하는 방식이 권장됩니다.