没有私有库的 iPhone 获得 SSID

我有一个商业应用程序,它有一个完全合法的理由来查看它所连接的网络的 SSID: 如果它连接到一个第三方硬件设备的 Adhoc 网络,它需要以不同于连接到互联网的方式运行。

我所看到的关于获得 SSID 的一切都告诉我,我必须使用 Apple80211,据我所知,它是一个私有库。我还读到,如果我使用一个私人图书馆苹果将不会批准的应用程序。

我是被困在一个苹果和一个困难的地方,还是我错过了什么?

104232 次浏览

从 iOS7或8开始,你可以这样做(需要 iOS12 + 的授权,如下所示) :

@import SystemConfiguration.CaptiveNetwork;


/** Returns first non-empty SSID network info dictionary.
*  @see CNCopyCurrentNetworkInfo */
- (NSDictionary *)fetchSSIDInfo {
NSArray *interfaceNames = CFBridgingRelease(CNCopySupportedInterfaces());
NSLog(@"%s: Supported interfaces: %@", __func__, interfaceNames);


NSDictionary *SSIDInfo;
for (NSString *interfaceName in interfaceNames) {
SSIDInfo = CFBridgingRelease(
CNCopyCurrentNetworkInfo((__bridge CFStringRef)interfaceName));
NSLog(@"%s: %@ => %@", __func__, interfaceName, SSIDInfo);


BOOL isNotEmpty = (SSIDInfo.count > 0);
if (isNotEmpty) {
break;
}
}
return SSIDInfo;
}

输出示例:

2011-03-04 15:32:00.669 ShowSSID[4857:307] -[ShowSSIDAppDelegate fetchSSIDInfo]: Supported interfaces: (
en0
)
2011-03-04 15:32:00.693 ShowSSID[4857:307] -[ShowSSIDAppDelegate fetchSSIDInfo]: en0 => {
BSSID = "ca:fe:ca:fe:ca:fe";
SSID = XXXX;
SSIDDATA = <01234567 01234567 01234567>;
}

请注意,模拟器上不支持 if。请在设备上进行测试。

IOS12

您必须从功能中启用访问 wifi 信息。

很重要 要在 ios12及更高版本中使用此功能,请在 Xcode 为您的应用程序启用 Access WiFi 信息功能。当您启用此功能时,Xcode 会自动将 Access WiFi 信息权限添加到您的权限文件和 App ID 中。文档链接

Swift 4.2

func getConnectedWifiInfo() -> [AnyHashable: Any]? {


if let ifs = CFBridgingRetain( CNCopySupportedInterfaces()) as? [String],
let ifName = ifs.first as CFString?,
let info = CFBridgingRetain( CNCopyCurrentNetworkInfo((ifName))) as? [AnyHashable: Any] {


return info
}
return nil


}

下面是经过清理的 ARC 版本,基于@elsuruto 的代码:

- (id)fetchSSIDInfo {
NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces();
NSLog(@"Supported interfaces: %@", ifs);
NSDictionary *info;
for (NSString *ifnam in ifs) {
info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
NSLog(@"%@ => %@", ifnam, info);
if (info && [info count]) { break; }
}
return info;
}

这对我的设备(而不是模拟器)很有用。请确保添加了系统配置框架。

#import <SystemConfiguration/CaptiveNetwork.h>


+ (NSString *)currentWifiSSID {
// Does not work on the simulator.
NSString *ssid = nil;
NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
for (NSString *ifnam in ifs) {
NSDictionary *info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
if (info[@"SSID"]) {
ssid = info[@"SSID"];
}
}
return ssid;
}

为了获得 SSID,这段代码工作得很好。

#import <SystemConfiguration/CaptiveNetwork.h>


@implementation IODAppDelegate


@synthesize window = _window;


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{




CFArrayRef myArray = CNCopySupportedInterfaces();
CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
NSLog(@"Connected at:%@",myDict);
NSDictionary *myDictionary = (__bridge_transfer NSDictionary*)myDict;
NSString * BSSID = [myDictionary objectForKey:@"BSSID"];
NSLog(@"bssid is %@",BSSID);
// Override point for customization after application launch.
return YES;
}

这就是结果:

Connected at:{
BSSID = 0;
SSID = "Eqra'aOrange";
SSIDDATA = <45717261 27614f72 616e6765>;

}

这里是简短和甜蜜的斯威夫特版本。

记住链接和导入框架:

import UIKit
import SystemConfiguration.CaptiveNetwork

定义方法:

func fetchSSIDInfo() -> CFDictionary? {
if let
ifs = CNCopySupportedInterfaces().takeUnretainedValue() as? [String],
ifName = ifs.first,
info = CNCopyCurrentNetworkInfo((ifName as CFStringRef))
{
return info.takeUnretainedValue()
}
return nil
}

需要时调用该方法:

if let
ssidInfo = fetchSSIDInfo() as? [String:AnyObject],
ssID = ssidInfo["SSID"] as? String
{
println("SSID: \(ssID)")
} else {
println("SSID not found")
}

正如其他地方提到的,这只适用于您的 iDevice。当不在 WiFi 上时,该方法将返回 nil-因此是可选的。

更新 iOS10及以上版本

在 iOS10中,CNCopySupportedInterfaces 不再被弃用

您需要导入 SystemConfiguration/CaptiveNetwork.h并将 SystemConfiguration.Framework添加到目标的链接库(在构建阶段)。

以下是 Swift (RikiRiocma 的回答)中的一段代码:

import Foundation
import SystemConfiguration.CaptiveNetwork


public class SSID {
class func fetchSSIDInfo() -> String {
var currentSSID = ""
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces) {
let interfaceName: UnsafePointer<Void> = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)")
if unsafeInterfaceData != nil {
let interfaceData = unsafeInterfaceData! as Dictionary!
currentSSID = interfaceData["SSID"] as! String
}
}
}
return currentSSID
}
}

(模拟器上,重要提示: CNCopySupportedInterfaces 返回空值。)

有关 Objective-c,请参见 Esad 的回答在这里和下面

+ (NSString *)GetCurrentWifiHotSpotName {
NSString *wifiName = nil;
NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
for (NSString *ifnam in ifs) {
NSDictionary *info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
if (info[@"SSID"]) {
wifiName = info[@"SSID"];
}
}
return wifiName;
}

IOS9更新

从 iOS9开始,禁锢网络已被废弃 * 。(来源)

* 在 iOS10中不再被弃用,见上文。

建议您使用 NEHotspotHelper (来源)

你需要给苹果公司发电子邮件,电子邮件地址是 networkextension@apple.com,并申请应享权利(来源)

样本代码(不是我的原则,看看巴勃罗 A 的回答) :

for(NEHotspotNetwork *hotspotNetwork in [NEHotspotHelper supportedNetworkInterfaces]) {
NSString *ssid = hotspotNetwork.SSID;
NSString *bssid = hotspotNetwork.BSSID;
BOOL secure = hotspotNetwork.secure;
BOOL autoJoined = hotspotNetwork.autoJoined;
double signalStrength = hotspotNetwork.signalStrength;
}

边注: 是的,他们在 iOS9中不赞成 CNCopySupportedInterfaces,而在 iOS10中则反其道而行之。我和一位苹果网络工程师交谈过,很多人在苹果开发者论坛上发表了关于这个问题的意见,之后事情发生了逆转。

如果你正在运行 iOS12,你将需要做一个额外的步骤。 我一直在努力让这段代码工作,最终在苹果的网站上找到了这段代码: ”重要 要在 ios12及更高版本中使用此功能,请在 Xcode 为您的应用程序启用 Access WiFi 信息功能。当您启用此功能时,Xcode 会自动将 Access WiFi 信息权限添加到您的权限文件和应用程序 ID 中。” Https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo

为 iOS13设计

从 iOS 13开始,你的应用程序也需要核心位置访问,以便使用 CNCopyCurrentNetworkInfo 功能,除非它配置了当前的网络或有 VPN 配置:
excerpt from https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc

所以这就是你需要的(见 苹果文档) :
- 链接 CoreLocation.framework
- 在 < em > Info.plist 中添加 location-services作为 UIRequiredDeviceCapabilities键/值
- 在 Info.plist中添加一个 NSLocationWhenInUseUsageDescription键/值,说明为什么你的应用程序需要核心位置
- 为你的应用程式加入「接达 WiFi 资讯」功能

现在作为 Objective-C 的一个例子,在使用 CNCopyCurrentNetworkInfo读取网络信息之前,首先检查位置访问是否已被接受:

- (void)fetchSSIDInfo {
NSString *ssid = NSLocalizedString(@"not_found", nil);


if (@available(iOS 13.0, *)) {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
NSLog(@"User has explicitly denied authorization for this application, or location services are disabled in Settings.");
} else {
CLLocationManager* cllocation = [[CLLocationManager alloc] init];
if(![CLLocationManager locationServicesEnabled] || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){
[cllocation requestWhenInUseAuthorization];
usleep(500);
return [self fetchSSIDInfo];
}
}
}


NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
id info = nil;
for (NSString *ifnam in ifs) {
info = (__bridge_transfer id)CNCopyCurrentNetworkInfo(
(__bridge CFStringRef)ifnam);


NSDictionary *infoDict = (NSDictionary *)info;
for (NSString *key in infoDict.allKeys) {
if ([key isEqualToString:@"SSID"]) {
ssid = [infoDict objectForKey:key];
}
}
}
...
...
}