iOS 13之后,你的App还能拿到WiFi名字吗?手把手搞定WiFi信息授权(Swift版)
iOS 13 WiFi信息获取实战指南:从权限配置到代码实现
记得去年接手一个商场导航项目时,遇到个棘手问题——在iOS 13设备上突然无法获取WiFi名称了。原本运行良好的代码在新系统上返回了空值,这让室内定位功能直接瘫痪。经过一番排查才发现,原来苹果在iOS 13中悄悄收紧了隐私权限。本文将带你完整走通从权限配置到代码实现的整个流程,解决这个让不少开发者栽跟头的兼容性问题。
1. iOS 13权限变更的核心影响
苹果在2019年发布的iOS 13中引入了一系列隐私保护措施,其中对WiFi信息获取的权限控制让不少开发者措手不及。原先简单的几行代码就能获取SSID和BSSID的方式不再适用,这背后是苹果对用户位置隐私的进一步保护。
关键变更点 :
- 必须显式开启"Access WiFi Information"能力
- 需要用户授权位置权限(即使不直接使用GPS)
- CNCopyCurrentNetworkInfo API的行为发生变化
为什么获取WiFi信息需要位置权限?这其实与WiFi定位的原理有关。每个WiFi热点的BSSID(MAC地址)在全球范围内是唯一的,通过收集这些信息可以构建庞大的定位数据库。苹果为了防止应用绕过位置权限获取用户精确位置,因此将WiFi信息与位置权限绑定。
2. 项目配置:权限声明与能力开启
2.1 开启Access WiFi Information能力
- 在Xcode中打开项目,选择主Target
- 切换到"Signing & Capabilities"标签页
- 点击"+"按钮,搜索并添加"Access WiFi Information"能力
注意:如果项目中有多个Target(如主App和Extension),需要为每个Target单独配置此能力。
2.2 配置位置权限描述
在Info.plist中添加以下键值对(根据实际需求选择):
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要您的位置权限来获取当前连接的WiFi信息</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>需要您的位置权限来获取当前连接的WiFi信息</string>
权限类型选择建议 :
| 权限类型 | 适用场景 | 审核通过率 |
|---|---|---|
| WhenInUse | 仅前台使用WiFi信息 | 高 |
| Always | 需要后台持续获取 | 较低 |
实际项目中,除非确实需要后台持续获取WiFi信息,否则建议优先使用WhenInUse权限,这样更容易通过App Store审核。
3. 代码实现:安全获取WiFi信息
3.1 检查位置权限状态
在尝试获取WiFi信息前,应先检查位置权限状态:
import CoreLocation
func checkLocationAuthorization() -> CLAuthorizationStatus {
return CLLocationManager().authorizationStatus
}
3.2 获取当前WiFi信息的完整实现
import SystemConfiguration.CaptiveNetwork
import CoreLocation
class WiFiInfoManager: NSObject, CLLocationManagerDelegate {
private var locationManager = CLLocationManager()
private var completion: ((NSDictionary?) -> Void)?
override init() {
super.init()
locationManager.delegate = self
}
func fetchCurrentWiFiInfo(completion: @escaping (NSDictionary?) -> Void) {
self.completion = completion
switch checkLocationAuthorization() {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted, .denied:
completion(nil)
default:
fetchWiFiInfoDirectly()
}
}
private func fetchWiFiInfoDirectly() {
guard let interfaces = CNCopySupportedInterfaces() as? [String] else {
completion?(nil)
return
}
for interface in interfaces {
if let info = CNCopyCurrentNetworkInfo(interface as CFString) as? NSDictionary {
completion?(info)
return
}
}
completion?(nil)
}
// MARK: - CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse || status == .authorizedAlways {
fetchWiFiInfoDirectly()
} else {
completion?(nil)
}
}
}
3.3 使用示例
let wifiManager = WiFiInfoManager()
wifiManager.fetchCurrentWiFiInfo { info in
if let ssid = info?["SSID"] as? String {
print("当前连接WiFi: \(ssid)")
} else {
print("无法获取WiFi信息,请检查位置权限")
}
}
4. 常见问题与调试技巧
4.1 获取返回空值的可能原因
- 设备未连接WiFi(正在使用蜂窝网络)
- 位置权限被拒绝或受限
- 未正确开启Access WiFi Information能力
- 在模拟器上测试(部分网络接口行为与真机不同)
4.2 真机调试注意事项
- 每次修改Capabilities后,最好Clean Build Folder(Command+Shift+K)
- 测试权限流程时,建议先在设置中重置位置权限(设置 → 通用 → 重置 → 重置位置与隐私)
- 获取WiFi信息需要设备实际连接到一个网络,仅开启WiFi但未连接任何网络时也会返回nil
4.3 兼容性处理建议
func getWiFiSSID() -> String? {
if #available(iOS 13.0, *) {
return WiFiInfoManager().fetchCurrentWiFiInfo()?["SSID"] as? String
} else {
// iOS 12及以下的旧方法
guard let interfaces = CNCopySupportedInterfaces() as? [String] else { return nil }
for interface in interfaces {
guard let info = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any] else { continue }
return info["SSID"] as? String
}
return nil
}
}
5. 进阶应用场景
5.1 网络环境感知
通过持续监测WiFi变化,可以构建智能的网络环境感知功能:
import Network
class NetworkMonitor {
static let shared = NetworkMonitor()
private let monitor = NWPathMonitor()
private var currentSSID: String?
func startMonitoring() {
monitor.pathUpdateHandler = { [weak self] path in
if path.status == .satisfied {
self?.checkWiFiChange()
}
}
monitor.start(queue: DispatchQueue.global(qos: .background))
}
private func checkWiFiChange() {
let newSSID = getWiFiSSID()
if newSSID != currentSSID {
currentSSID = newSSID
NotificationCenter.default.post(name: .wifiChanged, object: newSSID)
}
}
}
extension Notification.Name {
static let wifiChanged = Notification.Name("wifiChangedNotification")
}
5.2 企业级应用中的WiFi认证
在企业内部应用中,常需要根据连接的WiFi自动决定是否需要进行二次认证:
func shouldPerformEnterpriseAuth() -> Bool {
guard let ssid = getWiFiSSID() else { return false }
let corporateWiFis = ["Corp-Guest", "Corp-Staff", "Internal-Dev"]
return corporateWiFis.contains(ssid)
}
5.3 用户行为分析中的环境标记
在合规的前提下,可以将WiFi信息作为用户环境上下文的一部分:
struct AnalyticsEvent {
let name: String
let parameters: [String: Any]
func enrichWithEnvironment() -> [String: Any] {
var enriched = parameters
if let ssid = getWiFiSSID() {
enriched["wifi_environment"] = ssid.sha256() // 哈希处理保护隐私
}
enriched["network_type"] = Reachability.isConnectedToWiFi() ? "wifi" : "cellular"
return enriched
}
}
在实现这些功能时,务���注意用户隐私保护,只在必要的情况下收集WiFi信息,并确保有明确的用户授权和隐私政策说明。
更多推荐

所有评论(0)