iOS NEHotspotConfiguration WiFi 연결 가이드
iOS 앱에서 외부 Wi-Fi 네트워크에 프로그래밍 방식으로 접근하고 연결을 자동화하려면 NetworkExtension 프레임워크의 NEHotspotConfiguration 및 NEHotspotConfigurationManager를 활용해야 합니다. 사물인터넷(IoT) 기기 초기 설정(SoftAP 온보딩)이나 특정 전용 액세스 포인트 연결 시 핵심적으로 사용되는 기술입니다.
1. NEHotspotConfiguration 개요 및 주요 용도
NEHotspotConfiguration은 iOS 11.0부터 도입된 Apple의 공식 API로, 사용자가 기기의 '설정 > Wi-Fi' 화면으로 직접 이동하지 않고도 앱 내부에서 특정 Wi-Fi 네트워크 접속 프로파일을 등록하고 즉각 연결을 시도할 수 있도록 지원합니다.
[NEHotspotConfiguration 동작 흐름]
1. 앱: NEHotspotConfiguration(ssid:passphrase:) 객체 생성 (joinOnce 등 옵션 지정)
2. 앱: NEHotspotConfigurationManager.shared.apply(config) 호출
3. iOS 시스템: 시스템 보안 다이얼로그 팝업 노출 ("'앱이름'이 Wi-Fi 네트워크에 연결하려고 합니다")
4. 사용자 승인: iOS가 지정된 AP로 Wi-Fi 연결 전환
5. 앱: completionHandler 콜백 수신 및 후속 통신(기기 데이터 전송 등) 수행
주요 실무 적용 용도 (Use Cases)
- IoT 기기 초기 온보딩 (SoftAP 프로비저닝):
공기청정기, 스마트 전구, 홈 카메라, 로봇 청소기 등 무선랜 인터페이스만 가진 IoT 기기는 초기 설정 시 자체 임시 Wi-Fi(SoftAP)를 브로드캐스팅합니다. 스마트폰 앱이 기기의 임시 Wi-Fi에 자동으로 접속한 뒤, 가정 내 공유기(SSID/비밀번호) 정보를 전달하는 과정에 표준적으로 사용됩니다. - 매장 및 행사 전용 Wi-Fi 원클릭 연결:
호텔, 카페, 전시회 등의 전용 앱에서 복잡한 영문/숫자 비밀번호를 수동 입력할 필요 없이 앱 내 버튼 터치 한 번으로 Wi-Fi에 접속시킬 때 활용됩니다. - WPA3 / WPA2 Enterprise (802.1X) 기업 네트워크 자동 프로파일링:
EAP-TLS, PEAP 등의 인증서나 사용자 계정 기반 엔터프라이즈 보안 Wi-Fi 프로파일(NEHotspotEAPSettings)을 프로그래밍 방식으로 배포할 때 사용됩니다.
2. 필수 사전 요구사항 (Capabilities & 보안 정책)
NEHotspotConfiguration을 사용하기 위해서는 프로젝트 설정과 Apple의 시스템 보안 정책을 충족해야 합니다.
1) Xcode Capability 추가
- Xcode 프로젝트 타깃을 선택합니다.
- Signing & Capabilities 탭으로 이동합니다.
- + Capability 버튼을 클릭하고 Hotspot Configuration을 검색하여 추가합니다.
- 추가가 완료되면 프로젝트 내 .entitlements 파일에 com.apple.developer.networking.HotspotConfiguration 키(Boolean: YES)가 자동으로 생성됩니다.
2) 시스템 동의 팝업 (System Confirmation Dialog)
Apple의 개인정보 보호 및 보안 규정에 따라, apply(_:) 메서드가 호출되면 iOS 시스템이 강제로 확인 팝업을 표시합니다.
- 시스템 메시지: "'앱 이름'이(가) Wi-Fi 네트워크 '[SSID]'에 연결하려고 합니다."
- 앱 개발자가 이 팝업을 숨기거나 기본 버튼 텍스트를 임의로 변경할 수 없습니다.
- 사용자가 [취소]를 누르면 NEHotspotConfigurationError.userDenied 에러가 반환됩니다.
- 앱이 반드시 포그라운드(Active) 상태일 때만 호출 가능하며, 백그라운드 상태에서 호출 시 NEHotspotConfigurationError.applicationIsNotInForeground 에러가 발생합니다.
Wi-Fi 관련 권한 및 Capability 비교
| 구분 | Hotspot Configuration | Access WiFi Information | CoreLocation (위치 권한) |
| 주요 역할 | 특정 Wi-Fi에 프로그래밍 방식으로 연결/등록/제거 | 현재 연결된 Wi-Fi의 SSID/BSSID 정보 조회 | Wi-Fi 정보 조회를 위한 사용자 위치 허용 |
| 필요 API | NEHotspotConfigurationManager | NEHotspotNetwork.fetchCurrent | CLLocationManager.requestWhenInUseAuthorization |
| 시스템 팝업 | 연결 시마다 시스템 연결 확인 다이얼로그 표시 | 팝업 없음 (권한 승인 시 백그라운드 판독) | 위치 정보 사용 허용 다이얼로그 1회 표시 |
3. 핵심 프로퍼티 및 동작 옵션
NEHotspotConfiguration 인스턴스를 초기화할 때 네트워크 종류와 수명 주기를 제어할 수 있습니다.
- 네트워크 초기화 생성자:
- 공개(Open) 네트워크: NEHotspotConfiguration(ssid: ssid)
- WPA/WPA2/WPA3 Personal: NEHotspotConfiguration(ssid: ssid, passphrase: password, isWEP: false)
- WEP 네트워크: NEHotspotConfiguration(ssid: ssid, passphrase: password, isWEP: true)
- joinOnce (Bool, 기본값: false):
- true: 앱이 실행 중인 동안에만 해당 Wi-Fi 연결을 유지합니다. 앱이 종료되거나 사용자가 다른 네트워크로 이동하면 시스템 Wi-Fi 목록에서 설정이 자동으로 제거됩니다. IoT 온보딩 시 필수 설정입니다.
- false: 시스템 설정에 프로파일이 영구적으로 보관되며, 향후 해당 AP 주변에 접근하면 iOS가 자동으로 다시 연결합니다.
- lifeTimeInDays (NSNumber, iOS 13.0+):
- Wi-Fi 구성 프로파일이 유지되는 유효 기간을 일(Day) 단위로 지정합니다. (최대 14일)
- 임시 이벤트 매장이나 단기 행사용 네트워크 구성에 적합합니다.
4. 실무 코드 구현 예제 (Swift)
실제 프로덕션 환경에서 활용할 수 있는 Swift 기반 구현 예제입니다.
1) 기본 연결 및 IoT 온보딩 구현
import Foundation
import NetworkExtension
final class WiFiManager {
static let shared = WiFiManager()
private init() {}
/// 특정 Wi-Fi 네트워크에 연결을 요청합니다.
/// - Parameters:
/// - ssid: 접속 대상 AP 이름
/// - password: 비밀번호
/// - isTemporary: 임시 연결(joinOnce) 여부 (IoT 기기 연동 시 true 권장)
/// - completion: 결과 콜백 (성공 여부 및 발생 에러)
func connectToWiFi(
ssid: String,
password: String,
isTemporary: Bool = true,
completion: @escaping (Result<Void, Error>) -> Void
) {
// 1. WPA/WPA2/WPA3 네트워크 설정 객체 생성
let configuration = NEHotspotConfiguration(ssid: ssid, passphrase: password, isWEP: false)
// 2. 임시 연결 여부 지정
configuration.joinOnce = isTemporary
// 3. 시스템 매니저를 통해 프로파일 적용
NEHotspotConfigurationManager.shared.apply(configuration) { error in
if let error = error {
completion(.failure(error))
return
}
completion(.success(()))
}
}
}
2) Modern Swift Concurrency (async/await) 래퍼
Swift Concurrency 환경에서 깔끔하게 비동기 호출을 처리할 수 있는 패턴입니다.
import Foundation
import NetworkExtension
extension WiFiManager {
/// async/await 기반 Wi-Fi 연결 메서드
func connect(ssid: String, password: String, isTemporary: Bool = true) async throws {
let configuration = NEHotspotConfiguration(ssid: ssid, passphrase: password, isWEP: false)
configuration.joinOnce = isTemporary
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
NEHotspotConfigurationManager.shared.apply(configuration) { error in
if let error = error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: ())
}
}
}
}
}
3) 구성 프로파일 삭제 및 목록 조회
임시 연결이 아니었거나 연동 작업이 끝난 후 네트워크 프로파일을 정리할 때 사용합니다.
import Foundation
import NetworkExtension
extension WiFiManager {
/// 특정 SSID의 Wi-Fi 구성 프로파일을 시스템에서 삭제합니다.
func removeWiFiConfiguration(for ssid: String) {
NEHotspotConfigurationManager.shared.removeConfiguration(forSSID: ssid)
}
/// 현재 앱을 통해 등록되어 있는 SSID 목록을 조회합니다.
func fetchConfiguredSSIDs() async -> [String] {
await withCheckedContinuation { continuation in
NEHotspotConfigurationManager.shared.getConfiguredSSIDs { ssids in
continuation.resume(returning: ssids)
}
}
}
}
5. 실무 에러 처리 및 주의사항 (Constraints & Troubleshooting)
apply(_:) 메서드가 반환하는 에러는 NEHotspotConfigurationErrorDomain에 정의되어 있으며, 코드별 예외 처리가 필요합니다.
1) 주요 NEHotspotConfigurationError 케이스
| 에러 케이스 | 코드값 | 원인 및 대응 방안 |
| userDenied | 7 | 사용자가 시스템 확인 팝업에서 [취소]를 선택함. 안내 문구 노출 후 재시도 유도. |
| systemConfiguration | 8 | Wi-Fi 하드웨어가 꺼져 있거나 시스템 내부 설정 오류. Wi-Fi 활성화 여부 확인 필요. |
| alreadyAssociated | 13 | 기기가 이미 해당 Wi-Fi에 정상 연결되어 있음. 에러가 아닌 성공 케이스로 간주하여 후속 처리 진행. |
| pending | 14 | 이전 연결 요청이 아직 진행 중임. 연속 호출을 차단하고 딜레이 후 재시도 처리. |
| applicationIsNotInForeground | 15 | 앱이 백그라운드 상태에서 API를 호출함. 포그라운드 진입 시점에만 실행되도록 수명주기 제어. |
| invalidSSID / invalidWPAPassphrase | 1, 2 | SSID 이름이 비어 있거나 비밀번호 규칙(WPA 규격 미충족) 위반. 입력값 유효성 사전 검증 필요. |
2) error == nil의 정확한 의미와 한계
apply(_:)의 콜백에서 error가 nil이라고 해서 "기기가 Wi-Fi 연결을 최종 완료했다"는 뜻이 아닙니다.
- error == nil은 "시스템이 해당 설정을 정상적으로 수락하여 연결 프로세스를 개시했다"는 의미입니다.
- 만약 실제 AP가 전원이 꺼져 있거나 패스워드가 틀렸더라도 apply 콜백 시점에는 error == nil이 반환될 수 있습니다.
- 실무 검증 방법: apply 완료 후 약 1~2초 간격을 두고 로컬 IoT 기기의 엔드포인트(예: http://192.168.4.1/status)로 HTTP 핑을 보내거나 소켓 통신을 연결하여 실제 통신 가능 여부를 검증해야 합니다.
6. 결론
NEHotspotConfiguration은 iOS 앱에서 사용자의 수동 조작 없이 Wi-Fi 연결을 수행할 수 있는 공식 프레임워크 컴포넌트이며, IoT 기기 온보딩 및 전용 네트워크 연동 시 joinOnce 옵션과 시스템 에러 핸들링을 명확히 구현하는 것이 실무 안정성의 핵심입니다.
'개발 > iOS' 카테고리의 다른 글
| iOS CoreBluetooth 완벽 가이드: 권한 설정부터 데이터 송수신 구현까지 (0) | 2026.09.15 |
|---|---|
| MDM 프로파일 생성 및 서명·수명주기 관리 가이드 (0) | 2026.09.04 |
| Xcode 시뮬레이터 먹통으로 마우스 및 키보드 입력 불가 (0) | 2026.08.10 |
| iOS AppIntents 아키텍쳐: 온디바이스 AI 및 Siri에 앱 로직 연동하기 (0) | 2026.08.06 |
| 아이폰(iPhone) 개발자 모드(Developer Mode) 활성화 방법 정리 (0) | 2025.12.24 |
| iOS 개발자가 많이 하는 실수 - DispatchQueue main/global 큐 혼동과 sync/async 잘못 사용으로 인한 데드락·성능 저하 (0) | 2025.12.04 |
| iOS 개발자가 많이 하는 실수 - KVO(Key-Value Observing) 사용 시 removeObserver 누락 및 Strong Reference Cycle 실수 (0) | 2025.12.04 |
| iOS 개발자가 많이 하는 실수 - @escaping / non-escaping 클로저 차이를 잘못 이해해 크래시·경고가 발생하는 실수 (0) | 2025.12.04 |


