我有一个商业应用程序,它具有完全合法的理由来查看其连接到的网络的SSID:如果将其连接到第三方硬件设备的Adhoc网络,则它的工作方式必须不同于连接到Internet。

我所看到的有关获取SSID的所有信息都告诉我必须使用Apple80211,据我了解这是一个私有库。我还读到如果我使用私有库,Apple不会批准该应用。

我被困在Apple和困难的地方之间,还是这里缺少东西?

评论

相关:stackoverflow.com/questions/351954/…

#1 楼

从iOS 7或8开始,您可以执行此操作(如下所示,需要iOS 12+的授权):

@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>;
}


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

iOS 12

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


重要
要在iOS 12及更高版本中使用此功能,请在Xcode中为您的应用启用访问WiFi信息功能。启用此功能后,Xcode会自动将Access WiFi Information授权添加到您的授权文件和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,则其外观应为:-(id)fetchSSIDInfo {NSArray * ifs =(bridge_transfer id)CNCopySupportedInterfaces(); NSLog(@“%s:支持的接口:%@”,_func,ifs); id info = nil;对于(NSString * ifnam ins ifs){info =(bridge_transfer id)CNCopyCurrentNetworkInfo((_ bridge CFStringRef)ifnam); NSLog(@“%s:%@ =>%@”,__func,ifnam,info); if(info && [info count]){break;返回信息; }

– elsurudo
2012年5月5日19:31

+1很棒!不要忘记将[+]框架添加/链接到您的项目。如果使用此方法时看到奇怪的编译错误,则可能是您的问题。到从返回的字典中获取SSID使用// //获取包含iPhone连接到NSDictionary的网络信息的字典对象* networkDict = [self fetchSSIDInfo]; //从网络信息NSString中选择SSID * iPhoneNetworkSSID = [networkDict objectForKey:@“ SSID”];

– Groot
2012-12-17 13:13

有人知道BSSID是什么吗?它看起来像路由器的MAC地址,但实际上不是。既不是设备的MAC地址。

– Peetonn
13-10-30在5:58

@Filip通过使用模块化包含(@import而不是#import),更新了ARC友好代码。当导入模块而不只是头文件时,Clang将自动链接所需的框架。

–杰里米·谢尔曼(Jeremy W. Sherman)
15年1月22日在15:08



除了CNCopyCurrentNetworkInfo返回有用信息的功能之外,iOS 13 beta现在还需要位置许可。否则返回nil。请参阅:stackoverflow.com/questions/56583650/…

– RedMatt
19年7月3日在18:03



#2 楼

这是基于@elsurudo的代码的清理后的ARC版本:

- (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;
}


评论


@mindbomb是正确的,这是一个有关该问题的问题:stackoverflow.com/questions/31555640/…

– newenglander
15年8月28日在7:30

是的,Apple在iOS9 Beta中弃用后重新启用了CaptiveNetwork API。

– Mindbomb
2015年10月5日在21:16

@mindbomb还是这样吗?我在执行此问题。

–SamYoungNY
16 Mar 2 '16 at 21:19

@SamYoungNY请注意,这仅适用于设备,在Simulator上返回空

–esad
16 Mar 3 '16 at 0:19

#3 楼

iOS 10及更高版本的更新

iOS 10中不再弃用CNCopySupportedInterfaces(API参考)

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

这是一个快速的代码段(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在模拟器上返回nil。)

对于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;
}


iOS 9的更新
>
自iOS 9开始,Captive Network已弃用*。 (源)

* iOS 10中不再弃用,请参见上文。

建议您使用NEHotspotHelper(源)

您将需要向apple发送电子邮件至networkextension@apple.com并请求权利。 (源)

示例代码(不是我的代码。请参见Pablo 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;
}


旁注:是的,它们已弃用了CNCopySupportedInterfaces iOS 9并改变了它们在iOS 10中的位置。我与一位苹果网络工程师进行了交谈,而在许多人提交了Radars并在Apple Developer论坛上发表了有关该问题的演讲后,情况发生了逆转。

评论


我得到了苹果的批准,可以使用网络扩展,但是我仍然从[NEHotspotHelper supportNetworkInterfaces]获得空数组。你知道可能的原因吗?

– JZAU
16年11月4日在12:42

#4 楼

这对我在设备(而不是模拟器)上有效。确保添加系统配置框架。

#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;
}


#5 楼

此代码可以很好地获取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>;


}

#6 楼

如果您运行的是iOS 12,则需要执行额外的步骤。
我一直在努力使此代码起作用,并最终在Apple网站上找到了它:
“重要
要在iOS 12及更高版本中使用此功能,请为您的用户启用访问WiFi信息功能启用此功能后,Xcode会自动将访问WiFi信息权利添加到您的权利文件和应用ID。“
https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo

#7 楼

请参阅CaptiveNetwork中的CNCopyCurrentNetworkInfo:http://developer.apple.com/library/ios/#documentation/SystemConfiguration/Reference/CaptiveNetworkRef/Reference/reference.html。

#8 楼

这是简短而可爱的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 –因此是可选的。

#9 楼

对于iOS 13

从iOS 13开始,您的应用还需要访问核心位置才能使用CNCopyCurrentNetworkInfo功能,除非它配置了当前网络或具有VPN配置:

所以这就是您所需要的(请参阅Apple文档):
-链接CoreLocation.framework
-在Info.plist中添加location-services作为UIRequiredDeviceCapabilities键/值
-在Info中添加NSLocationWhenInUseUsageDescription键/值.plist描述了您的应用为何需要核心位置的原因
-为您的应用添加“访​​问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];
            }
        }
    }        
        ...
    ...
}


评论


这在iOS13上是必需的,否则您的CNCopyCurrentNetworkInfo()无效。

–弗朗兹·王(Franz Wang)
19-10-16在7:43



@Sugar是的,确实是iOS13-参见我的答案的第一行

– Francois B
19-10-16在11:44