iPhoneはプライベートライブラリなしでSSIDを取得します


154

接続しているネットワークのSSIDを確認する完全に正当な理由がある商用アプリがあります。サードパーティのハードウェアデバイスのアドホックネットワークに接続している場合は、それとは異なる方法で機能する必要があります。インターネットに接続されています。

SSIDの取得に関して私が見たものはすべて、私がApple80211を使用する必要があることを示しています。プライベートライブラリを使用すると、Appleがアプリを承認しないことも読んだ。

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

シミュレータではifsはサポートされていないことに注意してください。デバイスでテストします。

iOS 12

機能からwifi情報へのアクセスを有効にする必要があります。

重要iOS 12以降でこの機能を使用するには、XcodeでアプリのWiFi情報へのアクセス機能を有効にします。この機能を有効にすると、Xcodeは自動的にアクセスWiFi情報の資格を資格ファイルとアプリ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

}

8
ありがとう!ARCを使用している場合、以下のようになります。-(id)fetchSSIDInfo {NSArray * ifs =(bridge_transfer id)CNCopySupportedInterfaces(); NSLog(@ "%s:サポートされるインターフェース:%@"、_func、ifs); id info = nil; for(NSString * ifnam in ifs){info =(bridge_transfer id)CNCopyCurrentNetworkInfo(( _bridge CFStringRef)ifnam); NSLog(@ "%s:%@ =>%@"、__func、ifnam、info); if(info && [info count]){break; }} return info; }
elsurudo

1
+1すばらしい![+]フレームワークをプロジェクトに追加/リンクすることを忘れないでください。この方法を使用しているときに奇妙なコンパイルエラーが表示される場合は、おそらくそれが問題です。たとえば、返された辞書からSSIDを取得するには、// iPhoneがNSDictionaryに接続されているネットワークの情報を含む辞書オブジェクトを取得する* networkDict = [self fetchSSIDInfo]; //ネットワーク情報からSSIDを選択しますNSString * iPhoneNetworkSSID = [networkDict objectForKey:@ "SSID"];
Groot

誰もがBSSIDが何であるか知っていますか?ルーターのMACアドレスのように見えますが、実際はそうではありません。また、デバイスのMACアドレスでもありません。
peetonn 2013年

1
@Filip更新されたARC対応のコード@importは、モジュラーインクルード(ではなく#import)を使用してこれに対処しています。Clangは、ヘッダーだけでなくモジュールがインポートされると、必要なフレームワークに自動的にリンクします。
ジェレミーW.シャーマン

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を使用しているため、これは実際に推奨される答えです。提案された答えではなかったからといって、最初から見逃してしまいました。
ヨハンカールソン、2014

@mindbombはここで、右でその問題についての質問です:stackoverflow.com/questions/31555640/...
newenglander

いや、Appleは... iOS9ベータ版上に卑下した後CaptiveNetworkのAPIを再有効化
mindbomb

@mindbombはまだそうですか?これの実装に問題があります。
SamYoungNY 2016年

@SamYoungNYこれはデバイスでのみ機能することに注意してください。シミュレータでは空が返されます
esad

60

iOS 10以降のアップデート

CNCopySupportedInterfacesはiOS 10で廃止されなくなりました(APIリファレンス

SystemConfiguration / CaptiveNetwork.hをインポートし、SystemConfiguration.frameworkをターゲットのリンクライブラリに(ビルドフェーズで)追加する必要があります。

以下は、swiftのコードスニペット(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(ソース)を使用することをお勧めします

アップルにnetworkextension@apple.com宛てにメールを送信し、資格をリクエストする必要があります。(ソース

サンプルコード(私のコードではありません。PabloAの回答を参照してください):

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のネットワークエンジニアと話しました。その逆は、非常に多くの人々がレーダーを提出し、Apple開発者フォーラムで問題について話し合った後に行われました。


Appleからネットワーク拡張の使用を承認されましたが、[NEHotspotHelper supportedNetworkInterfaces]から空の配列を取得しました。考えられる理由を知っていますか?
JZAU 2016年

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でアプリのAccess WiFi Information機能を有効にします。この機能を有効にすると、Xcodeが自動的にアクセスWiFi情報の資格を資格ファイルとアプリIDに追加します。」 https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo


ありがとう、問題が解決しました!
david72

7

CaptiveNetworkのCNCopyCurrentNetworkInfoを参照してください:http ://developer.apple.com/library/ios/#documentation/SystemConfiguration/Reference/CaptiveNetworkRef/Reference/reference.html 。


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ライブラリをリンクします-Info.plistにキー/値として
追加します - アプリがコアロケーションを必要とする理由を説明するキー/値をInfo.plistに追加します - 「アクセスWiFiアプリの「情報」資格 location-servicesUIRequiredDeviceCapabilities
NSLocationWhenInUseUsageDescription

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()でnil返され
Franz Wang

@Sugarはい、確かにiOS13-私の回答の最初の行を参照してください
フランソワB
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.