iPhone은 개인 라이브러리없이 SSID를 얻습니다


154

네트워크의 SSID가 연결된 합법적 인 이유가있는 상용 앱이 있습니다. 타사 하드웨어 장치의 Adhoc 네트워크에 연결되어있는 경우 다른 방식으로 작동해야합니다. 인터넷에 연결되어 있습니다.

SSID를 얻는 것에 대해 내가 본 모든 것은 개인 라이브러리라는 것을 이해하는 Apple80211을 사용해야한다고 말합니다. 또한 개인 라이브러리를 사용하는 경우 Apple은 앱을 승인하지 않습니다.

나는 사과와 힘든 곳 사이에 갇혀 있습니까, 아니면 여기에 빠진 것이 있습니까?


답변:


186

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가 지원되지 않습니다. 장치에서 테스트하십시오.

iOS 12

기능에서 wifi 정보에 액세스 할 수 있어야합니다.

중요 iOS 12 이상에서이 기능을 사용하려면 Xcode에서 앱의 WiFi 정보 액세스 기능을 활성화하십시오. 이 기능을 활성화하면 Xcode는 자동으로 Access WiFi Information 권한을 자격 파일 및 앱 ID에 추가합니다. 설명서 링크

스위프트 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

}

8
감사! ARC를 사용하는 경우 다음과 같이 표시됩니다.-(id) fetchSSIDInfo {NSArray * ifs = ( bridge_transfer id) CNCopySupportedInterfaces (); NSLog (@ "% s : 지원되는 인터페이스 : % @", _func , ifs); 아이디 정보 = nil; for (NSString * ifnam의 경우 ifnam) {info = ( bridge_transfer id) CNCopyCurrentNetworkInfo (( _bridge CFStringRef) ifnam); NSLog (@ "% s : % @ => % @", __func , ifnam, 정보); if (info && [info count]) {break; }} 리턴 정보; }
elsurudo

1
+1 잘 작동합니다! [+] 프레임 워크를 프로젝트에 추가 / 링크하는 것을 잊지 마십시오. 이 방법을 사용할 때 이상한 컴파일 오류가 발생하면 문제 일 수 있습니다. 예를 들어 반환 된 사전에서 SSID를 가져 오려면 // iPhone이 NSDictionary에 연결된 네트워크 정보를 포함하는 사전 객체 가져 오기 * networkDict = [self fetchSSIDInfo]; // 네트워크 정보에서 SSID를 선택합니다. NSString * iPhoneNetworkSSID = [networkDict objectForKey : @ "SSID"];
Groot

BSSID가 무엇인지 아는 사람이 있습니까? 라우터의 MAC 주소처럼 보이지만 실제로는 그렇지 않습니다. 장치의 MAC 주소도 아닙니다.
peetonn

1
@Filip 업데이트 된 ARC 호환 코드는 모듈 식 포함 ( @import대신 #import) 을 사용하여이 문제를 해결합니다 . Clang은 헤더가 아닌 모듈을 가져올 때 필요한 프레임 워크에서 자동으로 연결됩니다.
Jeremy W. Sherman

1
iOS 13 베타에는 CNCopyCurrentNetworkInfo유용한 정보를 반환 할 수있는 기능 외에도 위치 권한이 필요합니다 . 그렇지 않으면를 반환합니다 nil. 참조 : stackoverflow.com/questions/56583650/...
RedMatt

61

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

1
ARC를 사용하기 때문에 이것이 가장 선호되는 답변이어야합니다. 나는 그것이 적절한 대답이 아니기 때문에 처음부터 이것을 놓쳤다.
Johan Karlsson

@mindbomb은 여기, 바로입니다 문제에 대한 질문은 다음과 같습니다 stackoverflow.com/questions/31555640/...
newenglander

애플은 iOS9 베타 버전에서 더 이상 사용되지 않고 CaptiveNetwork API를 다시 활성화했습니다.
mindbomb

@mindbomb 이것은 여전히 ​​그렇습니까? 이것을 구현하는 데 문제가 있습니다.
SamYoungNY

@SamYoungNY 이것은 장치에서만 작동합니다. 시뮬레이터에서는 빈 값이 반환됩니다
esad

60

iOS 10 이상 업데이트

CNCopySupportedInterfaces는 iOS 10에서 더 이상 사용되지 않습니다. ( API Reference )

당신은 가져와야 에서 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 ( source ) 를 사용하는 것이 좋습니다.

networkextension@apple.com으로 Apple에게 이메일을 보내고 자격을 요청해야합니다. ( 소스 )

샘플 코드 ( 내 코드 아님. 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 네트워킹 엔지니어와 대화를 나 and을 때 많은 사람들이 레이더를 제출하고 Apple Developer 포럼에서 문제에 대해 이야기했습니다.


Apple에서 네트워크 확장을 사용하도록 승인을 받았지만 [NEHotspotHelper supportedNetworkInterfaces]에서 빈 배열을 얻었습니다. 가능한 이유를 알고 있습니까?
JZAU

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

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

}


1
완벽하게 작동했습니다.
Yomo

9

iOS 12를 실행중인 경우 추가 단계를 수행해야합니다. 이 코드를 작동시키기 위해 고군분투하고 마침내 Apple 사이트에서 이것을 발견했습니다. "중요 iOS 12 이상에서이 기능을 사용하려면 Xcode에서 앱의 WiFi 정보 액세스 기능을 활성화하십시오.이 기능을 활성화하면 Xcode가 자동으로 활성화됩니다 권한 파일 및 앱 ID에 Access WiFi Information 권한을 추가합니다. " https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo


감사합니다. 문제가 해결되었습니다.
david72


5

짧고 달콤한 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을 반환하므로 옵션입니다.


2

iOS 13의 경우

iOS 13부터 현재 네트워크를 구성하거나 VPN 구성이없는 한이 CNCopyCurrentNetworkInfo 기능 을 사용하려면 앱에 코어 위치 액세스가 필요 합니다.
https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc에서 발췌

이 그래서 당신이 (볼 필요가 무엇을 사과 설명서 )
- 링크합니다 CoreLocation.framework라이브러리
- 추가 location-servicesA와 UIRequiredDeviceCapabilities의 키 / 값 의 Info.plist
- 추가 NSLocationWhenInUseUsageDescription에 키 / 값 의 Info.plist 앱이 핵심 위치를 필요로 이유를 설명하는
"액세스 와이파이 추가 - 앱의 정보 "자격

이제 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 (
프란츠 왕

@Sugar 예 실제로 iOS13 - 내 대답의 첫 번째 줄 참조
프랑소와 B
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.