iPhone nhận SSID mà không cần thư viện riêng


154

Tôi có một ứng dụng thương mại có lý do hoàn toàn chính đáng để xem SSID của mạng mà nó được kết nối với: Nếu được kết nối với mạng Adhoc cho thiết bị phần cứng của bên thứ 3, nó cần phải hoạt động theo cách khác so với nếu nó được Đa kêt nôi internet.

Mọi thứ tôi thấy về việc lấy SSID đều nói với tôi rằng tôi phải sử dụng Apple80211, mà tôi hiểu là một thư viện riêng. Tôi cũng đọc rằng nếu tôi sử dụng thư viện riêng Apple sẽ không phê duyệt ứng dụng.

Tôi có bị mắc kẹt giữa một Apple và một nơi khó khăn, hoặc có điều gì tôi đang thiếu ở đây không?


Câu trả lời:


186

Kể từ iOS 7 hoặc 8, bạn có thể thực hiện việc này (cần Quyền lợi cho iOS 12+ như bên dưới):

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

Ví dụ đầu ra:

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

Lưu ý rằng không có ifs được hỗ trợ trên trình giả lập. Kiểm tra trên thiết bị của bạn.

iOS 12

Bạn phải kích hoạt truy cập thông tin wifi từ các khả năng.

Quan trọng Để sử dụng chức năng này trong iOS 12 trở lên, hãy bật khả năng Truy cập thông tin WiFi cho ứng dụng của bạn trong Xcode. Khi bạn bật khả năng này, Xcode sẽ tự động thêm quyền truy cập Thông tin WiFi truy cập vào tệp quyền lợi và ID ứng dụng của bạn. Liên kết tài liệu

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

}

8
Cảm ơn! Nếu bạn đang sử dụng ARC, đây là giao diện: - (id) fetchSSIDInfo {NSArray * ifs = ( Bridge_transfer id) CNCopySupportedInterfaces (); NSLog (@ "% s: Giao diện được hỗ trợ:% @", _func , ifs); thông tin id = nil; for (NSString * ifnam in ifs) {info = ( Bridge_transfer id) CNCopyCienNetworkInfo (( _bridge CFStringRef) ifnam); NSLog (@ "% s:% @ =>% @", __func , ifnam, thông tin); if (thông tin && [đếm thông tin]) {break; }} thông tin trả về; }
elsurudo

1
+1 Hoạt động tuyệt vời! Đừng quên thêm / liên kết khung [+] với dự án của bạn. Nếu bạn thấy lỗi biên dịch kỳ lạ khi sử dụng phương pháp này có lẽ là vấn đề của bạn. Ví dụ: lấy SSID từ từ điển được trả về, hãy sử dụng // Lấy đối tượng từ điển chứa thông tin của mạng, iPhone được kết nối với NSDipedia * networkDict = [self fetchSSIDInfo]; // Chọn SSID từ thông tin mạng NSString * iPhoneNetworkSSID = [networkDict objectForKey: @ "SSID"];
Groot

có ai biết BSSID là gì không? Nó trông giống như địa chỉ MAC của bộ định tuyến, nhưng thực tế không phải vậy. không phải là địa chỉ MAC của thiết bị.
peetonn

1
@Filip Cập nhật mã thân thiện với ARC này bằng cách sử dụng mô-đun bao gồm ( @importchứ không phải #import). Clang sẽ tự động liên kết trong khung cần thiết khi một mô-đun, thay vì chỉ một tiêu đề, được nhập.
Jeremy W. Sherman

1
iOS 13 beta hiện yêu cầu quyền truy cập vị trí ngoài khả năng CNCopyCurrentNetworkInfotrả lại thông tin hữu ích; nếu không thì nó trả về nil. Xem: stackoverflow.com/questions/56583650/ khăn
RedMatt

61

Đây là phiên bản ARC đã được dọn sạch, dựa trên mã của @ 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;
}

1
Đây thực sự nên là câu trả lời ưa thích vì nó sử dụng ARC. Tôi đã bỏ lỡ điều này ngay từ đầu chỉ vì nó không phải là câu trả lời có ích.
Johan Karlsson

@mindbomb đã đúng, đây là một câu hỏi về vấn đề đó: stackoverflow.com/questions/31555640/
Kẻ

vâng, Apple đã kích hoạt lại API CaptiveNetwork sau khi không dùng nữa trên betas iOS9 ..
mindbomb

@mindbomb đây có phải là trường hợp không? Tôi đang có vấn đề thực hiện điều này.
SamYoungNY

@SamYoungNY Lưu ý rằng điều này chỉ hoạt động trên thiết bị, trên Trình mô phỏng sẽ được trả lại
esad

60

CẬP NHẬT CHO iOS 10 trở lên

CNCopySupportedInterfaces không còn bị phản đối trong iOS 10. ( Tham khảo API )

Bạn cần nhập SystemConfiguration / CaptiveNetwork.h và thêm SystemConfiguration.framework vào Thư viện được liên kết của mục tiêu của bạn (trong các giai đoạn xây dựng).

Đây là đoạn mã trong swift (Câu trả lời của 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
    }
}

( Quan trọng: CNCopySupportedInterfaces trả về nil trên trình giả lập.)

Đối với Mục tiêu-c, xem câu trả lời của Esad tại đây và bên dưới

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

CẬP NHẬT CHO iOS 9

Kể từ iOS 9 Captive Network không được dùng nữa *. ( nguồn )

* Không còn bị phản đối trong iOS 10, xem ở trên.

Bạn nên sử dụng NEHotspotHelper ( nguồn )

Bạn sẽ cần gửi email cho apple tại networkextension@apple.com và yêu cầu quyền lợi. ( nguồn )

Mã mẫu ( Không phải mã của tôi. Xem câu trả lời của 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;
}

Lưu ý bên lề: Yup, họ đã từ chối CNCopySupportedInterfaces trong iOS 9 và đảo ngược vị trí của họ trong iOS 10. Tôi đã nói chuyện với một kỹ sư mạng của Apple và sự đảo ngược xuất hiện sau khi rất nhiều người nộp Radars và nói về vấn đề này trên diễn đàn Apple Developer.


Tôi đã được apple chấp thuận sử dụng tiện ích mở rộng mạng, nhưng tôi vẫn nhận được mảng trống từ [NEHotspotHelper hỗ trợNetworkInterfaces]. Bạn có biết lý do có thể?
JZAU

28

Điều này làm việc cho tôi trên thiết bị (không phải giả lập). Hãy chắc chắn rằng bạn thêm khung cấu hình hệ thống.

#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

Mã này hoạt động tốt để có được 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;
}

Và đây là kết quả:

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

}


1
Làm việc hoàn hảo.
Yomo

9

Nếu bạn đang chạy iOS 12, bạn sẽ cần thực hiện thêm một bước. Tôi đã vật lộn để làm cho mã này hoạt động và cuối cùng đã tìm thấy mã này trên trang web của Apple: "Quan trọng Để sử dụng chức năng này trong iOS 12 trở lên, hãy bật khả năng Truy cập thông tin WiFi cho ứng dụng của bạn trong Xcode. Khi bạn bật khả năng này, Xcode sẽ tự động thêm quyền truy cập Thông tin WiFi vào tệp quyền lợi và ID ứng dụng của bạn. " https://developer.apple.com/documentation/systemconfiguration/1614126-cncopyciennetworkinfo


Cảm ơn bạn, nó đã khắc phục vấn đề của tôi!
david72


5

Đây là phiên bản Swift ngắn & ngọt ngào.

Hãy nhớ liên kết và nhập Khung:

import UIKit
import SystemConfiguration.CaptiveNetwork

Xác định phương thức:

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

Gọi phương thức khi bạn cần:

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

Như đã đề cập ở nơi khác, điều này chỉ hoạt động trên iDevice của bạn. Khi không có WiFi, phương thức sẽ trở về con số không - do đó là tùy chọn.


2

Dành cho iOS 13

Kể từ iOS 13, ứng dụng của bạn cũng cần có quyền truy cập Vị trí lõi để sử dụng CNCopyCurrentNetworkInfo chức năng trừ khi cấu hình mạng hiện tại hoặc có cấu hình VPN:
trích đoạn từ https://developer.apple.com/documentation/systemconfiguration/1614126-cncopyciennetworkinfo?lingu=objc

Vì vậy, đây là những gì bạn cần (xem tài liệu apple ):
- Liên kết CoreLocation.frameworkthư viện
- Thêm location-servicesdưới dạng UIRequiredDeviceCapabilitiesKhóa / Giá trị trong Info.plist
- Thêm NSLocationWhenInUseUsageDescriptionKhóa / Giá trị trong Info.plist mô tả lý do tại sao ứng dụng của bạn yêu cầu Vị trí cốt lõi
- Thêm "Truy cập WiFi Thông tin "quyền lợi cho ứng dụng của bạn

Bây giờ là ví dụ Objective-C, trước tiên hãy kiểm tra xem quyền truy cập vị trí có được chấp nhận hay không trước khi đọc thông tin mạng bằng cách sử dụng 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];
            }
        }
    }        
        ...
    ...
}

Điều đó là bắt buộc trên iOS13, nếu không, bạn đã nhận được số không cho CNCopyCienNetworkInfo ()
Franz Wang

@Sugar có thực sự iOS13 - xem dòng đầu tiên của câu trả lời của tôi
Francois B
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.