我有一个商业应用程序,它有完全合法的理由查看连接的网络的SSID:如果连接到第三方硬件设备的Adhoc网络,则需要以不同的方式运行。
我看到的所有关于获取SSID的信息都告诉我必须使用Apple80211,这是一个私有库。 我也读到过,如果使用私有库,苹果将不会批准此应用程序。
我是否处于进退两难的境地,或者我这里还有什么遗漏吗?
从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>;
}
请注意,在模拟器上不支持任何if条件语句。请在您的设备上测试。
您必须从能力中启用WiFi访问信息。
重要提示 要在iOS 12及更高版本中使用此功能,请在Xcode中为您的应用程序启用Access WiFi Information功能。启用此功能时,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
}
@import
而不是 #import
)来解决这个问题。当导入一个模块而不仅仅是头文件时,Clang 会自动链接所需的框架。 - Jeremy W. ShermanCNCopyCurrentNetworkInfo
功能;否则它将返回nil
。
参见:https://dev59.com/X1MI5IYBdhLWcg3wS5cv - RedMattCNCopySupportedInterfaces在iOS 10中不再被弃用。(API参考)
您需要导入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在此处及以下的解答
+ (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*。(来源)
*在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;
}
旁注:是的,在iOS 9中他们弃用了CNCopySupportedInterfaces,并在iOS 10中扭转了他们的立场。我与一位苹果网络工程师交谈,这种扭转是在很多人在Apple开发者论坛上提交Radar并发表意见之后发生的。
这是基于 @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;
}
#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>;
如果您正在运行iOS 12,您需要额外执行一步操作。我一直在努力使这个代码工作,最终在苹果的网站上找到了答案:
https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo重要提示: 为了在iOS 12及以上版本中使用此函数,请在Xcode中为您的应用程序启用Access WiFi Information功能。当您启用此功能时,Xcode会自动将Access WiFi Information权限添加到您的权限文件和App ID。
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")
}
从iOS 13开始,如果你的应用没有配置当前网络或没有VPN配置,那么需要访问Core Location才能使用CNCopyCurrentNetworkInfo
函数:
下面是需要做的事情(参见苹果文档):
- 链接CoreLocation.framework
库
- 将location-services
作为Info.plist中的UIRequiredDeviceCapabilities
关键字和值添加
- 在Info.plist中添加一个NSLocationWhenInUseUsageDescription
关键字和值以说明您的应用程序需要 Core Location 的原因
- 为您的应用程序添加“访问 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];
}
}
}
...
...
}