iPhone получит SSID без приватной библиотеки
У меня есть коммерческое приложение, которое имеет вполне законную причину для просмотра SSID сети, к которой оно подключено: если оно подключено к сети Adhoc для стороннего аппаратного устройства, оно должно функционировать не так, как если бы оно было подключен к интернету.
Все, что я видел о получении SSID, говорит мне, что я должен использовать Apple80211, который, как я понимаю, является частной библиотекой. Я также читал, что если я использую личную библиотеку, Apple не одобрит приложение.
Я застрял между Apple и наковальней, или мне чего-то не хватает здесь?
8 ответов
Начиная с iOS 7 или 8, вы можете сделать это, используя преимущества ARC и модулей, которые будут автоматически связываться в необходимой среде:
@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;
}
(Это модернизация образца кода, написанного для iOS 4.1+. Единственными изменениями были введение более четких имен переменных и принятие ARC и модулей.)
Пример вывода:
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>;
}
Обратите внимание, что в симуляторе не поддерживаются if. Протестируйте на своем устройстве.
До версии 4.1 вам, возможно, повезло в словарях "Конфигурация системы". Например, используя scutil
на моем Mac:
$ scutil
> show State:/Network/Interface/en1/AirPort
<dictionary> {
Power Status : 1
SecureIBSSEnabled : FALSE
BSSID : <data> 0xcafecafecafe
SSID_STR : XXXX
SSID : <data> 0x012345670123456701234567
Busy : FALSE
CHANNEL : <dictionary> {
CHANNEL : 1
CHANNEL_FLAGS : 10
}
}
> exit
ОБНОВЛЕНИЕ для iOS 10 и выше
CNCopySupportedInterfaces больше не считается устаревшим в iOS 10. ( Справочник по API)
Вам необходимо импортировать SystemConfiguration/CaptiveNetwork.h и добавить SystemConfiguration.framework в связанные библиотеки вашей цели (в стадии сборки).
Вот фрагмент кода в быстром (ответ 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 возвращает ноль на симуляторе.)
Для Objective-c см . Ответ Эсада здесь и ниже.
+ (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 и запросить разрешения. ( источник)
Пример кода ( не мой код. См. Ответ Пабло А):
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 Developer.
Вот очищенная версия 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;
}
Это работает для меня на устройстве (не симулятор). Убедитесь, что вы добавили каркас конфигурации системы.
#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;
}
Этот код хорошо работает для получения 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>;
}
Если вы используете iOS 12, вам нужно будет сделать дополнительный шаг. Я изо всех сил пытался заставить этот код работать и, наконец, нашел его на сайте Apple: "Важно! Чтобы использовать эту функцию в iOS 12 и более поздних версиях, включите возможность доступа к информации Wi-Fi для вашего приложения в XCode. Когда вы включите эту возможность, XCode автоматически добавляет право доступа к информации Wi-Fi в ваш файл разрешений и идентификатор приложения. " https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo
См. CNCopyCurrentNetworkInfo в CaptiveNetwork: http://developer.apple.com/library/ios/#documentation/SystemConfiguration/Reference/CaptiveNetworkRef/Reference/reference.html.
Вот короткая и сладкая версия 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, метод вернет ноль - следовательно, необязательный.
Для iOS 13
Начиная с iOS 13 вашему приложению также требуется доступ к Core Location, чтобы использовать CNCopyCurrentNetworkInfo
функция, если он не настроил текущую сеть или не имеет конфигурации VPN:
Итак, это то, что вам нужно (см. Документацию 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];
}
}
}
...
...
}