SystemConfiguration.CaptiveNetwork doesn't work on iOS 12 - ios

I have a function that detects the current SSID from the user. Unfortunately this doesn't work anymore with iOS 12. This means it just jumps over the if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? { part. Maybe it's just a bug or it's deprecated. I've found nothing on Apple Docs.
On older iOS 11, 10, and 9 devices, it works well.
Here's my Code:
func getWiFiSsid() -> String? {
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
}
}
}
return ssid
}

To use this function in iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID.
https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc

Related

Getting two different device IDs from same iphone

I am getting different UDIDs for my iphone when i get it from itunes and programatically like this
UDID:String = UIDevice.current.identifierForVendor!.uuidString
Basically im trying to acquire a unique identifier for my iphone just like we have mac address for android phones.
one easiest way is to solve this issue by storing the identifierForVendor in keychain. even if you uninstall app ,value for the key remains same and its unchanged. many third party libraries available to perform this . one of them https://github.com/jrendel/SwiftKeychainWrapper.
func getGlobalUniqueIdentifierFromKeyChain()->String{
let retrievedString: String? = KeychainWrapper.standard.string(forKey: "DeviceId")
if retrievedString == nil{
if let deviceKey = UIDevice.current.identifierForVendor?.uuidString{
let _ = KeychainWrapper.standard.set(deviceKey, forKey: "DeviceId")
}
}
if let globalID = KeychainWrapper.standard.string(forKey: "DeviceId"){
return globalID
}else{
return UIDevice.current.identifierForVendor?.uuidString ?? ""
}
}

How to get iOS device model number (eg. A1530)?

I'm wondering is that possible to get the iOS device model number programmatically. I mean the device model on the back of iPhone. It's always in this format "AXXXX".
With a little use of private API it is possible
let device = UIDevice.current
var selector = NSSelectorFromString("deviceInfoForKey:")
if !device.responds(to: selector) {
selector = NSSelectorFromString("_deviceInfoForKey:")
}
if device.responds(to: selector) {
if let unmanagedModel = device.perform(selector, with:"ModelNumber") {
let model = unmanagedModel.takeRetainedValue() as! String
print("Device hardware model: \(model)")
}
}
let myDevice = UIDevice.currentDevice()
let deviceModel = myDevice.model

How to get ssid in Swift 2.0 without CaptiveNetwork deprecated framework?

No one of the solutions found in this other question Get SSID in Swift 2 works because CaptiveNetwork framework was deprecated in Swift 2.0
In Swift 1.2 a use this function:
func getSSID() -> String {
let interfaces = CNCopySupportedInterfaces()
if interfaces == nil {
return ""
}
//let interfacesArray = interfaces.takeRetainedValue() as! [String]
let interfacesArray = Array(arrayLiteral: interfaces)
if interfacesArray.count <= 0 {
return ""
}
let interfaceName = String(interfacesArray[0])
let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
if unsafeInterfaceData == nil {
return ""
}
let interfaceData = unsafeInterfaceData.takeRetainedValue() as Dictionary!
print(interfaceData["SSID"], terminator: "")
return interfaceData["SSID"] as! String
}
But the following code does not work anymore..
As far as I'm aware, the CaptiveNetwork APIs are deprecated in iOS 9, but still available — so you should still be able to use them (at your own peril, as future updates may cause them to no longer work as expected). If they aren't visible from Swift, you can make them so from an ObjC bridging header.
This isn't an area I work with much, but it looks like the new Network Extensions API is intended to replace CaptiveNetwork anyway. See Network Extension Framework Reference for docs and the WWDC15 session What's New in Network Extension and VPN.

Swift CNCopySupportedInterfaces not valid

Trying to get the SSID of current device. I have found plenty of examples on how to do it however I am struggling with getting the CNCopySupportedInterfaces to autocomplete. I have 'import SystemConfiguration' at the top of my swift file but no success. Can't seem to figure out what I am doing wrong.
iOS 12
You must enable Access WiFi Information from capabilities.
Important
To use this function in iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID. Documentation link
You need: import SystemConfiguration.CaptiveNetwork
Underneath the covers, CaptiveNetwork is a C header file (.h) that is within the SystemConfiguration framework:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SystemConfiguration.framework/Headers/CaptiveNetwork.h
If you know Objective-C, this goes into more depth:
iPhone get SSID without private library
You have to use the awkward syntax to bridge from any pure C API, so the following is required:
for interface in CNCopySupportedInterfaces().takeRetainedValue() as! [String] {
println("Looking up SSID info for \(interface)") // en0
let SSIDDict = CNCopyCurrentNetworkInfo(interface).takeRetainedValue() as! [String : AnyObject]
for d in SSIDDict.keys {
println("\(d): \(SSIDDict[d]!)")
}
}
ADDENDUM FOR SWIFT 2.2 and 3.0
The CFxxx datatypes are now bridged to native Objective-C runtime, eliminating the head-scratching retain calls. However, nullable pointers give rise to Optionals, so things don't get any shorter. At least, it's fairly clear what's going on, plus the nil helps us identify the simulator. The other answer uses an awful lot of bit-casting and unsafe operations which seems non-Swiftian, so I offer this.
func getInterfaces() -> Bool {
guard let unwrappedCFArrayInterfaces = CNCopySupportedInterfaces() else {
print("this must be a simulator, no interfaces found")
return false
}
guard let swiftInterfaces = (unwrappedCFArrayInterfaces as NSArray) as? [String] else {
print("System error: did not come back as array of Strings")
return false
}
for interface in swiftInterfaces {
print("Looking up SSID info for \(interface)") // en0
guard let unwrappedCFDictionaryForInterface = CNCopyCurrentNetworkInfo(interface) else {
print("System error: \(interface) has no information")
return false
}
guard let SSIDDict = (unwrappedCFDictionaryForInterface as NSDictionary) as? [String: AnyObject] else {
print("System error: interface information is not a string-keyed dictionary")
return false
}
for d in SSIDDict.keys {
print("\(d): \(SSIDDict[d]!)")
}
}
return true
}
Output on success:
SSIDDATA: <57696c6d 79>
BSSID: 12:34:56:78:9a:bc
SSID: YourSSIDHere
In Swift 2.0 / iOS 9 the API CaptiveNetwork is (nearly) gone or depreciated. I contacted Apple regarding this problem and I thought we could (or should) use the NEHotspotHelper instead. I got a respond from Apple today: One should continue to use CaptiveNetwork and the two relevant APIs (even tough there marked depreciated):
CNCopySupportedInterfaces
CNCopyCurrentNetworkInfo
The user braime posted an updated code-snippet for this problem on Ray Wenderlich forums:
let interfaces:CFArray! = 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
} else {
currentSSID = ""
}
}
Works perfect for me.
Swift:
import SystemConfiguration.CaptiveNetwork
func currentSSIDs() -> [String] {
guard let interfaceNames = CNCopySupportedInterfaces() as? [String] else {
return []
}
return interfaceNames.flatMap { name in
guard let info = CNCopyCurrentNetworkInfo(name as CFString) as? [String:AnyObject] else {
return nil
}
guard let ssid = info[kCNNetworkInfoKeySSID as String] as? String else {
return nil
}
return ssid
}
}
Then print(currentSSIDs()), not working on simulator, only real devices.
Taken from https://forums.developer.apple.com/thread/50302
func getInterfaces() -> String? {
var ssid: String?
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
break
}
}
}
return ssid
}
In iOS 12 and up you will need to enable the Access WiFi Information capability for your app in order to get the ssid

How to get available wifi network name in iOS using swift

I want to get all the WiFi networks available in a region and their SSID value. But the problem is how to get the SSID of all the WiFi network available even if I am not connected to one.
iOS 12
You must enable Access WiFi Information from capabilities.
Important
To use this function in iOS 12 and later, enable the Access WiFi Information capability for your app in Xcode. When you enable this capability, Xcode automatically adds the Access WiFi Information entitlement to your entitlements file and App ID. Documentation link
First;
import SystemConfiguration.CaptiveNetwork
Then;
func getInterfaces() -> Bool {
guard let unwrappedCFArrayInterfaces = CNCopySupportedInterfaces() else {
print("this must be a simulator, no interfaces found")
return false
}
guard let swiftInterfaces = (unwrappedCFArrayInterfaces as NSArray) as? [String] else {
print("System error: did not come back as array of Strings")
return false
}
for interface in swiftInterfaces {
print("Looking up SSID info for \(interface)") // en0
guard let unwrappedCFDictionaryForInterface = CNCopyCurrentNetworkInfo(interface) else {
print("System error: \(interface) has no information")
return false
}
guard let SSIDDict = (unwrappedCFDictionaryForInterface as NSDictionary) as? [String: AnyObject] else {
print("System error: interface information is not a string-keyed dictionary")
return false
}
for d in SSIDDict.keys {
print("\(d): \(SSIDDict[d]!)")
}
}
return true
}
Here my class that prints the WIFI network name
import UIKit
import Foundation
import SystemConfiguration.CaptiveNetwork
class FirstView: UIViewController
{
#IBOutlet weak var label: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
let ssid = self.getWiFiName()
print("SSID: \(ssid)")
}
func getWiFiName() -> String? {
var ssid: String?
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
break
}
}
}
return ssid
}
}
Yes it is possible to list all nearby WiFi networks.You need to complete a questionnaire at https://developer.apple.com/contact/network-extension, and then you can use NEHotspotHelper to return a list of hotspots. Technical Q&A https://developer.apple.com/library/archive/qa/qa1942/_index.html

Resources