IPhone получает SSID без частной библиотеки
У меня есть коммерческое приложение, которое имеет совершенно законную причину, чтобы увидеть SSID сети, к которой он подключен: если он подключен к сети Adhoc для стороннего аппаратного устройства, он должен работать по-другому, чем если он подключен к Интернету.
Все, что я видел о получении SSID, говорит мне, что я должен использовать Apple80211, который, как я понимаю, является частной библиотекой. Я также читал, что если я использую частную библиотеку, Apple не одобрит приложение.
Я застрял между Apple и жестким местом, или там что-то мне не хватает?
Ответы
Ответ 1
Начиная с 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
Вы должны включить доступ к информации Wi-Fi из возможностей.
Важный Чтобы использовать эту функцию в iOS 12 и позже, включите возможность Доступа к Информации WiFi для своего приложения в XCode. Когда вы включаете эту возможность, XCode автоматически добавляет право доступа к информации Wi-Fi в ваш файл разрешений и идентификатор приложения. Ссылка на документацию
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
}
Ответ 2
Здесь очищенная версия ARC, основанная на коде @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;
}
Ответ 3
ОБНОВЛЕНИЕ ДЛЯ iOS 10 и up
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 (источник)
Вам нужно будет отправить электронное письмо по адресу [email protected] и запросить разрешения. (источник)
Пример кода (Не мой код. См. ответ Пабло):
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;
}
Боковое примечание: Да, они отказались от CNCopySupportedInterfaces в iOS 9 и отменили свою позицию в iOS 10. Я разговаривал с инженером сети Apple, и разворот пришел после того, как так много людей подали Radars и высказались по поводу этой проблемы на форумах разработчиков Apple,
Ответ 4
Это работает для меня на устройстве (а не на симуляторе). Убедитесь, что вы добавили фреймворк systemconfiguration.
#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;
}
Ответ 5
Этот код работает хорошо, чтобы получить 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>;
}
Ответ 6
Если вы используете iOS 12, вам нужно сделать дополнительный шаг. Я пытаюсь сделать этот код работой и, наконец, нашел это на сайте Apple: "Важно. Чтобы использовать эту функцию в iOS 12 и более поздних версиях, включите возможность доступа к информации о WiFi для вашего приложения в Xcode. Когда вы включите эту возможность, Xcode автоматически добавляет право доступа к беспроводной сети доступа к вашему файлу прав и идентификатору приложения. " https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo
Ответ 7
См. CNCopyCurrentNetworkInfo в CaptiveNetwork: http://developer.apple.com/library/ios/#documentation/SystemConfiguration/Reference/CaptiveNetworkRef/Reference/reference.html.
Ответ 8
Вот короткая и сладкая версия Swift.
Не забудьте связать и импортировать Framework:
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 - следовательно, необязательный.
Ответ 9
Для iOS 13
Начиная с iOS 13, вашему приложению также необходим доступ к Core Location, чтобы использовать функцию CNCopyCurrentNetworkInfo
function, если оно не настроило текущую сеть или не настроило VPN:
![excerpt from https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc]()
Так что это то, что вам нужно (см. документацию Apple):
- Ссылка на библиотеку CoreLocation.framework
- Добавьте location-services
в качестве ключа/значения UIRequiredDeviceCapabilities
в Info.plist
- Добавьте ключ/значение NSLocationWhenInUseUsageDescription
в Info.plist, описывающий, почему вашему приложению требуется базовое расположение
- Добавьте разрешение "Доступ к WiFi-информации" для своего приложения
Теперь, в качестве примера 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];
}
}
}
...
...
}