iPhone ottiene SSID senza libreria privata


154

Ho un'app commerciale che ha un motivo completamente legittimo per vedere l'SSID della rete a cui è connessa: se è connessa a una rete Adhoc per un dispositivo hardware di terze parti, deve funzionare in modo diverso rispetto a se lo è connesso a internet.

Tutto quello che ho visto su come ottenere l'SSID mi dice che devo usare Apple80211, che capisco è una libreria privata. Ho anche letto che se uso una libreria privata, Apple non approverà l'app.

Sono bloccato tra una mela e un posto difficile, o c'è qualcosa che mi manca qui?


Risposte:


186

A partire da iOS 7 o 8, puoi farlo (hai bisogno di Titolarità per iOS 12+ come mostrato di seguito):

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

Esempio di output:

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

Si noti che nessun simulatore è supportato sul simulatore. Prova sul tuo dispositivo.

iOS 12

È necessario abilitare l'accesso alle informazioni wifi dalle funzionalità.

Importante Per utilizzare questa funzione in iOS 12 e versioni successive, abilita la funzionalità di accesso alle informazioni WiFi per la tua app in Xcode. Quando si abilita questa funzionalità, Xcode aggiunge automaticamente il diritto di accesso alle informazioni WiFi al file di diritti e all'ID app. Link alla documentazione

Rapido 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
Grazie! Se stai usando ARC, ecco come dovrebbe apparire: - (id) fetchSSIDInfo {NSArray * ifs = ( id bridge_transfer) CNCopySupportedInterfaces (); NSLog (@ "% s: interfacce supportate:% @", _func , ifs); id id = zero; for (NSString * ifnam in ifs) {info = ( bridge_transfer id) CNCopyCurrentNetworkInfo (( _bridge CFStringRef) ifnam); NSLog (@ "% s:% @ =>% @", __func , ifnam, informazioni); if (info && [conteggio informazioni]) {break; }} informazioni di ritorno; }
elsurudo,

1
+1 Funziona alla grande! Non dimenticare di aggiungere / collegare il framework [+] al tuo progetto. Se vedi strani errori di compilazione quando usi questo metodo, questo è probabilmente il tuo problema. Ad esempio, per ottenere l'SSID dal dizionario restituito, utilizzare // Ottenere un oggetto dizionario contenente le informazioni della rete a cui l'iPhone è connesso a NSDictionary * networkDict = [self fetchSSIDInfo]; // Seleziona il SSID dalle informazioni di rete NSString * iPhoneNetworkSSID = [networkDict objectForKey: @ "SSID"];
Groot

qualcuno sa cos'è il BSSID? sembra l'indirizzo MAC di un router, ma in realtà non lo è. né è l'indirizzo MAC del dispositivo.
peetonn,

1
@Filip Il codice ARC-aggiornato aggiornato risolve questo problema utilizzando le inclusioni modulari ( @importanziché #import). Clang si collegherà automaticamente nel framework necessario quando viene importato un modulo, anziché solo un'intestazione.
Jeremy W. Sherman,

1
iOS 13 beta ora richiede l'autorizzazione di localizzazione oltre alla possibilità CNCopyCurrentNetworkInfodi restituire informazioni utili; altrimenti ritorna nil. Vedi: stackoverflow.com/questions/56583650/...
RedMatt

61

Ecco la versione ARC pulita, basata sul codice di @ 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
Questa dovrebbe davvero essere la risposta preferita poiché usa ARC. L'ho perso fin dall'inizio solo perché non era la risposta offerta.
Johan Karlsson,

@mindbomb ha ragione, ecco una domanda a riguardo: stackoverflow.com/questions/31555640/…
newenglander,

sì, Apple ha riabilitato l'API CaptiveNetwork dopo aver disapprovato le versioni beta di iOS9 ..
mindbomb,

@mindbomb è ancora così? Sto riscontrando problemi nell'attuazione di questo.
SamYoungNY,

@SamYoungNY Nota che funziona solo sul dispositivo, su Simulator viene restituito un vuoto
esad

60

AGGIORNAMENTO PER iOS 10 e versioni successive

CNCopySupportedInterfaces non è più obsoleto in iOS 10. ( Riferimento API )

Devi importare SystemConfiguration / CaptiveNetwork.h e aggiungere SystemConfiguration.framework nelle librerie collegate del tuo target (in fase di costruzione).

Ecco uno snippet di codice in rapido (la risposta di 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
    }
}

( Importante: CNCopySupportedInterfaces restituisce zero sul simulatore.)

Per Objective-c, vedi la risposta di Esad qui e sotto

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

AGGIORNAMENTO PER iOS 9

A partire da iOS 9 Captive Network è obsoleto *. ( fonte )

* Non più deprecato in iOS 10, vedi sopra.

Si consiglia di utilizzare NEHotspotHelper ( fonte )

Dovrai inviare un'e-mail a apple all'indirizzo networkextension@apple.com e richiedere i diritti. ( fonte )

Codice di esempio ( non il mio codice. Vedi la risposta di 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;
}

Nota a margine: Sì, hanno deprecato CNCopySupportedInterfaces in iOS 9 e invertito la loro posizione in iOS 10. Ho parlato con un ingegnere di rete Apple e l'inversione è arrivata dopo che molte persone hanno presentato Radar e hanno parlato del problema sui forum degli sviluppatori Apple.


Sono stato approvato da Apple per utilizzare l'estensione di rete, ma ho ancora array vuoto da [NEHotspotHelper supportNetworkInterfaces]. Conosci la possibile ragione?
JZAU,

28

Questo funziona per me sul dispositivo (non sul simulatore). Assicurati di aggiungere il framework di configurazione del sistema.

#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

Questo codice funziona bene per ottenere 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;
}

E questi sono i risultati:

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

}


1
Ha funzionato perfettamente.
Yomo

9

Se usi iOS 12 dovrai fare un passo in più. Ho avuto difficoltà a far funzionare questo codice e alla fine l'ho trovato sul sito di Apple: "Importante Per utilizzare questa funzione in iOS 12 e versioni successive, abilita la funzionalità di accesso alle informazioni WiFi per la tua app in Xcode. Quando abiliti questa funzionalità, Xcode automaticamente aggiunge il diritto di accesso alle informazioni WiFi al file di diritti e all'ID app. " https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo


Grazie, risolto il mio problema!
david72,


5

Ecco la versione breve e dolce di Swift.

Ricorda di collegare e importare il Framework:

import UIKit
import SystemConfiguration.CaptiveNetwork

Definire il metodo:

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

Chiama il metodo quando ne hai bisogno:

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

Come menzionato altrove, questo funziona solo sul tuo iDevice. Quando non è su WiFi, il metodo restituirà zero, quindi l'opzione facoltativa.


2

Per iOS 13

A partire da iOS 13 la tua app necessita anche dell'accesso alla posizione principale per poter utilizzare la CNCopyCurrentNetworkInfo funzione a meno che non abbia configurato la rete corrente o abbia configurazioni VPN:
estratto da https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc

Quindi questo è ciò di cui hai bisogno (vedi la documentazione di Apple ):
- Collega la CoreLocation.frameworklibreria
- Aggiungi location-servicescome UIRequiredDeviceCapabilitieschiave / valore in Info.plist
- Aggiungi una NSLocationWhenInUseUsageDescriptionchiave / valore in Info.plist descrivendo perché la tua app richiede Core Location
- Aggiungi il "Access WiFi Informazioni "diritto alla tua app

Ora, come esempio Objective-C, controlla prima se l'accesso alla posizione è stato accettato prima di leggere le informazioni di rete usando 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];
            }
        }
    }        
        ...
    ...
}

Questo è richiesto su iOS13, altrimenti non hai nulla per CNCopyCurrentNetworkInfo ()
Franz Wang

@Sugar sì davvero iOS13 - vedi la prima riga della mia risposta
Francois B
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.