iPhone obtient le SSID sans bibliothèque privée

154

J'ai une application commerciale qui a une raison tout à fait légitime de voir le SSID du réseau auquel elle est connectée: si elle est connectée à un réseau Adhoc pour un périphérique matériel tiers, elle doit fonctionner d'une manière différente que si elle est connecté à Internet.

Tout ce que j'ai vu sur l'obtention du SSID me dit que je dois utiliser Apple80211, qui, je crois, est une bibliothèque privée. J'ai également lu que si j'utilise une bibliothèque privée, Apple n'approuvera pas l'application.

Suis-je coincé entre une pomme et un endroit difficile, ou y a-t-il quelque chose qui me manque ici?

Steve Reed Sr
la source

Réponses:

186

À partir d'iOS 7 ou 8, vous pouvez le faire (vous devez avoir droit à iOS 12+ comme indiqué ci-dessous):

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

Exemple de sortie:

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

Notez qu'aucun if n'est pris en charge sur le simulateur. Testez sur votre appareil.

iOS 12

Vous devez activer l'accès aux informations wifi à partir des fonctionnalités.

Important Pour utiliser cette fonction dans iOS 12 et versions ultérieures, activez la fonctionnalité Accéder aux informations WiFi pour votre application dans Xcode. Lorsque vous activez cette fonctionnalité, Xcode ajoute automatiquement le droit d'accès aux informations WiFi à votre fichier de droits et à l'ID d'application. Lien de documentation

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

}
Jeremy W. Sherman
la source
8
Merci! Si vous utilisez ARC, voici à quoi cela devrait ressembler: - (id) fetchSSIDInfo {NSArray * ifs = ( bridge_transfer id) CNCopySupportedInterfaces (); NSLog (@ "% s: interfaces prises en charge:% @", _func , ifs); info id = nil; pour (NSString * ifnam dans ifs) {info = ( id_transfert de pont) CNCopyCurrentNetworkInfo (( _bridge CFStringRef) ifnam); NSLog (@ "% s:% @ =>% @", __func , ifnam, info); if (info && [nombre d'informations]) {pause; }} informations de retour; }
elsurudo
1
+1 Fonctionne très bien! N'oubliez pas d'ajouter / lier le framework [+] à votre projet. Si vous voyez des erreurs de compilation étranges lors de l'utilisation de cette méthode, c'est probablement votre problème. Pour obtenir par exemple le SSID du dictionnaire renvoyé, utilisez // Obtenir un objet de dictionnaire contenant les informations du réseau auquel l'iPhone est connecté à NSDictionary * networkDict = [self fetchSSIDInfo]; // Sélectionnez le SSID à partir des informations réseau NSString * iPhoneNetworkSSID = [networkDict objectForKey: @ "SSID"];
Groot
est-ce que quelqu'un sait ce qu'est le BSSID? cela ressemble à l'adresse MAC d'un routeur, mais ce n'est pas le cas. ce n'est pas non plus l'adresse MAC de l'appareil.
peetonn
1
@Filip Mise à jour du code compatible ARC en utilisant des inclusions modulaires ( @importplutôt que #import). Clang se liera automatiquement dans le cadre nécessaire lorsqu'un module, plutôt qu'un simple en-tête, est importé.
Jeremy W. Sherman
1
iOS 13 bêta nécessite désormais une autorisation de localisation en plus de la possibilité CNCopyCurrentNetworkInfode renvoyer des informations utiles; sinon, il revient nil. Voir: stackoverflow.com/questions/56583650/…
RedMatt
61

Voici la version ARC nettoyée, basée sur le code de @ 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;
}
esad
la source
1
Cela devrait vraiment être la réponse préférée car il utilise ARC. J'ai manqué cela depuis le début simplement parce que ce n'était pas la réponse proposée.
Johan Karlsson
@mindbomb a raison, voici une question à ce sujet: stackoverflow.com/questions/31555640/…
newenglander
oui, Apple a réactivé l'API CaptiveNetwork après avoir abandonné la version bêta d'iOS9.
mindbomb
@mindbomb est-ce toujours le cas? J'ai des problèmes de mise en œuvre.
SamYoungNY
@SamYoungNY Notez que cela ne fonctionne que sur l'appareil, sur Simulator un vide est retourné
esad
60

MISE À JOUR POUR iOS 10 et plus

CNCopySupportedInterfaces n'est plus obsolète dans iOS 10. ( Référence API )

Vous devez importer SystemConfiguration / CaptiveNetwork.h et ajouter SystemConfiguration.framework aux bibliothèques liées de votre cible (sous les phases de construction).

Voici un extrait de code en swift (réponse de 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
    }
}

( Important: CNCopySupportedInterfaces renvoie nul sur le simulateur.)

Pour Objective-c, voir la réponse d'Esad ici et ci-dessous

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

MISE À JOUR POUR iOS 9

À partir d'iOS 9, le réseau captif est obsolète *. ( source )

* N'est plus obsolète dans iOS 10, voir ci-dessus.

Il est recommandé d'utiliser NEHotspotHelper ( source )

Vous devrez envoyer un e-mail à apple à [email protected] et demander des droits. ( source )

Exemple de code ( pas mon code. Voir la réponse de 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;
}

Note latérale: Oui, ils ont désapprouvé CNCopySupportedInterfaces dans iOS 9 et ont inversé leur position dans iOS 10. J'ai parlé avec un ingénieur réseau Apple et l'inversion est survenue après que tant de personnes ont déposé des radars et ont parlé du problème sur les forums des développeurs Apple.

Emin Israfil iOS
la source
J'ai été approuvé par Apple pour utiliser l'extension réseau, mais j'ai toujours un tableau vide de [NEHotspotHelper supportedNetworkInterfaces]. Connaissez-vous la raison possible?
JZAU
28

Cela fonctionne pour moi sur l'appareil (pas sur le simulateur). Assurez-vous d'ajouter le cadre de configuration du système.

#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;
}
Chris
la source
10

Ce code fonctionne bien pour obtenir le 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;
}

Et voici les résultats:

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

}

Jameel
la source
1
A parfaitement fonctionné.
Yomo
9

Si vous utilisez iOS 12, vous devrez effectuer une étape supplémentaire. J'ai eu du mal à faire fonctionner ce code et j'ai finalement trouvé ceci sur le site d'Apple: "Important Pour utiliser cette fonction dans iOS 12 et versions ultérieures, activez la fonctionnalité Accéder aux informations WiFi pour votre application dans Xcode. Lorsque vous activez cette fonctionnalité, Xcode automatiquement ajoute le droit d'accès aux informations WiFi à votre fichier de droits et à votre ID d'application. " https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo

Muvimotv
la source
Merci, cela a résolu mon problème!
david72
5

Voici la version courte et douce de Swift.

N'oubliez pas de lier et d'importer le Framework:

import UIKit
import SystemConfiguration.CaptiveNetwork

Définissez la méthode:

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

Appelez la méthode quand vous en avez besoin:

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

Comme mentionné ailleurs, cela ne fonctionne que sur votre iDevice. Lorsqu'elle n'est pas sur WiFi, la méthode retournera nil - d'où l'option.

n.Drake
la source
2

Pour iOS 13

À partir d'iOS 13, votre application a également besoin d'un accès Core Location pour utiliser la CNCopyCurrentNetworkInfo fonction, sauf si elle a configuré le réseau actuel ou dispose de configurations VPN:
extrait de https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc

Voici donc ce dont vous avez besoin (voir la documentation Apple ):
- Lier la CoreLocation.frameworkbibliothèque
- Ajouter en location-servicestant que UIRequiredDeviceCapabilitiesclé / valeur dans Info.plist
- Ajouter une NSLocationWhenInUseUsageDescriptionclé / valeur dans Info.plist décrivant pourquoi votre application nécessite un emplacement principal
- Ajouter le "Accès WiFi Droit aux informations "pour votre application

Maintenant, à titre d'exemple Objective-C, vérifiez d'abord si l'accès à la localisation a été accepté avant de lire les informations réseau en utilisant 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];
            }
        }
    }        
        ...
    ...
}
François B
la source
Cela est requis sur iOS13, sinon vous avez nul pour CNCopyCurrentNetworkInfo ()
Franz Wang
@Sugar oui en effet iOS13 - voir la première ligne de ma réponse
Francois B