我有一个商业应用程序有完全合法的理由看到它所连接的网络的SSID:如果它连接到第三方硬件设备的Adhoc网络,它需要以不同于如果它连接到互联网。
我看到的关于获取SSID的所有内容都告诉我必须使用Apple80211,我理解这是一个私有库。我还读到,如果我使用私人图书馆,Apple将不会批准该应用程序。
我被困在苹果和硬地之间,还是我在这里缺少什么?
答案 0 :(得分:182)
从iOS 7或8开始,你可以这样做,它利用了ARC和模块,它们将自动链接到所需的框架中:
@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;
}
(这是为iOS 4.1+编写的代码示例的现代化。唯一的变化是引入更清晰的变量名称并采用ARC和模块。)
示例输出:
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>;
}
请注意,模拟器上不支持ifs。在您的设备上进行测试。
在4.1之前,您可能会通过系统配置字典获得一些运气。例如,在我的Mac上使用scutil
:
$ scutil
> show State:/Network/Interface/en1/AirPort
<dictionary> {
Power Status : 1
SecureIBSSEnabled : FALSE
BSSID : <data> 0xcafecafecafe
SSID_STR : XXXX
SSID : <data> 0x012345670123456701234567
Busy : FALSE
CHANNEL : <dictionary> {
CHANNEL : 1
CHANNEL_FLAGS : 10
}
}
> exit
您必须从功能启用访问wifi信息。
重要 要在iOS 12及更高版本中使用此功能,请在Xcode中为您的应用启用Access WiFi信息功能。启用此功能后,Xcode会自动将Access WiFi信息权利添加到您的权利文件和应用程序ID中。 Documentation link
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
}
答案 1 :(得分:60)
这是清理过的ARC版本,基于@ elsurudo的代码:
- (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;
}
答案 2 :(得分:58)
在iOS 10中不再弃用CNCopySupportedInterfaces。(API Reference)
您需要导入 SystemConfiguration / CaptiveNetwork.h 并将 SystemConfiguration.framework 添加到目标的链接库(在构建阶段)。
以下是swift (RikiRiocma's Answer)中的代码段:
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在模拟器上返回nil。)
对于Objective-c,请参阅Esad's answer here and below
+ (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;
}
自iOS 9起,Captive Network已被弃用*。 (source)
*不再在iOS 10中弃用,请参阅上文。
建议您使用NEHotspotHelper(source)
您需要通过networkextension@apple.com向Apple发送电子邮件并申请权利。 (source)
示例代码(Not my code. See Pablo A's answer):
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;
}
旁注:是的,他们弃用了iOS 9中的CNCopySupportedInterfaces并改变了他们在iOS 10中的位置。我与一位Apple网络工程师进行了交谈,并且在很多人提交Radars并在Apple Developer论坛上谈到这个问题之后发生了逆转。 。
答案 3 :(得分:28)
这适用于我的设备(不是模拟器)。确保添加系统配置框架。
#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;
}
答案 4 :(得分:10)
此代码可以很好地获取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>;
}
答案 5 :(得分:9)
如果您运行的是iOS 12,则需要执行额外的步骤。 我一直在努力使此代码起作用,并最终在Apple网站上找到了它: “重要 要在iOS 12及更高版本中使用此功能,请在Xcode中为您的应用启用访问WiFi信息功能。启用此功能后,Xcode会自动将Access WiFi Information授权添加到您的授权文件和App ID中。” https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo
答案 6 :(得分:7)
请参阅CaptiveNetwork中的CNCopyCurrentNetworkInfo:http://developer.apple.com/library/ios/#documentation/SystemConfiguration/Reference/CaptiveNetworkRef/Reference/reference.html。
答案 7 :(得分:5)
这是短片&amp;甜蜜的Swift版本。
请记住链接并导入框架:
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 - 因此是可选的。
答案 8 :(得分:2)
从iOS 13开始,您的应用还需要访问核心位置才能使用CNCopyCurrentNetworkInfo
function,除非它配置了当前网络或具有VPN配置:
这就是您所需要的(请参见apple documentation):
-链接CoreLocation.framework
库
-在 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];
}
}
}
...
...
}