How to get available wifi network name in iOS using swift - ios

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

Related

Is it possible to connect to WiFi automatically by capturing QR-Code?

I'm newbie in iOS development(SwiftUI).
Recently, I have encountered a problem about connecting to WiFi by capturing QR-Code.
I wonder that if is there any possible solution to connect to WiFi directly by using QR-Code.
After I did a lot of research, I still cannot find any references about this issue.
There are my keywords: SwiftUI, Swift, QR-Code, Wi-Fi, iOS.
What do I have now:
ContentView
struct ContentView: View {
#State private var isShowingScanner = false
#State private var resultOfScanning: String = "Result will be shown here..."
var body: some View {
VStack {
Button(action: { self.isShowingScanner = true }, label: { Text("Scan Button") })
.sheet(isPresented: self.$isShowingScanner) {
CodeScannerView(codeTypes: [.qr], simulatedData: "www.opgg.com", completion: self.handleScan)
}
Text("\(resultOfScanning)")
}
}
func handleScan(result: Result<String, CodeScannerView.ScanError>) {
self.isShowingScanner = false
switch result {
case .success(let code):
let codeStr = code as! String
self.resultOfScanning = codeStr
case .failure(let error):
print("Scanning failed")
}
}
}
CodeScannerView (Reference: An article by Paul Hudson)
What do I wanna build:
I want to use this App, connecting to the specific WiFi automatically by capturing QR-Code(It contains SSID & Password of WiFi).
What is my problem:
I cannot find a way to connect to the specific WiFi automatically by using QR-Code. It seems that no one have talked about this issue.
May someone know that how to solve the problems like above-mentioned?
Thanks for comments and answers.
We have four steps to deal with this issue.
1.Capture the QR-Code which contains the specific WiFi hotspot information(SSID, Password, Encryption Type).
2.Convert JSON data of QR-Code to Dictionary.
3.Get the SSID, Password and Encryption type value from before-mentioned Dictionary.
4.Use NEHotspotConfiguration of Apple API to set our SSID, Password and Encryption type and connect to the specific WiFi Hotspot.
p.s. Your app needs the signing certificate to active some function of your project and Apple API.
Let's see what have I done here:
func handleScan(result: Result<String, CodeScannerView.ScanError>) {
switch result {
case .success(let code):
let data_code = code.data(using: .utf8)
do {
let dict_code = try JSONSerialization.jsonObject(with: data_code!, options: .allowFragments) as! [String : Any]
let wifi_ssid = dict_code["S"] as! String
let wifi_pwd = dict_code["P"] as! String
let wifi_type = dict_code["T"] as! String
let configuration = NEHotspotConfiguration.init(ssid: wifi_ssid, passphrase: wifi_pwd, isWEP: self.checkWifiType(type: wifi_type))
configuration.joinOnce = true
NEHotspotConfigurationManager.shared.apply(configuration) {
(error) in
if error != nil {
if let errorStr = error?.localizedDescription {
print("Error Information:\(errorStr)")
}
if (error?.localizedDescription == "already associated.") {
print("Connected!")
} else {
print("No Connected!")
}
} else {
print("Connected!")
}
}
print("Dict_Code:\(dict_code)")
} catch (let error) {
print("JSONSerial... Convert Error:\(error.localizedDescription)")
}
case .failure(let error):
self.connectionStatus = "Scanning failed!"
}
}
After doing this, I finally can scan my own QR-Code and connect to the specific WiFi Hotspot.

How to find printers on IOS from Brother SDK?

I find printers from iPad setting print can find my Brother printer.
But when I try the code I get empty device list and I don't know why.
I am not familiar with Swift. I just try the sample code from Official documentation.
https://support.brother.com/g/s/es/htmldoc/mobilesdk/guide/discover-printer.html
Here is my code:
func getPrinter() {
let printerManager = BRPtouchNetworkManager()
printerManager.setPrinterName("Brother QL-720NW")
printerManager.startSearch(5)
printerManager.getPrinterNetInfo()
print("start")
let testFind = YourClass()
print("1")
testFind.startSearchWiFiPrinter()
testFind.didFinishSearch(printerManager)
print("2")
}
class YourClass: NSObject, BRPtouchNetworkDelegate {
private var networkManager: BRPtouchNetworkManager?
func startSearchWiFiPrinter() {
print("3")
let manager = BRPtouchNetworkManager()
manager.delegate = self
manager.startSearch(5)
self.networkManager = manager
}
// BRPtouchNetworkDelegate
func didFinishSearch(_ sender: Any!) {
print("4")
guard let manager = sender as? BRPtouchNetworkManager else {
print("5")
return
}
guard let devices = manager.getPrinterNetInfo() else {
print("6")
return
}
print(devices)
print("7")
for deviceInfo in devices {
print("8")
if let deviceInfo = deviceInfo as? BRPtouchDeviceInfo {
print("Model: \(deviceInfo.strModelName), IP Address: \(deviceInfo.strIPAddress)")
}
}
}
}
I call my function getPrinter() and here is my print log:
The SDK documentation gives you an example implementation of two methods:
func startSearchWiFiPrinter() {}
and
func didFinishSearch(_ sender: Any!) {}
In the class you want to execute the search you must implement these. You also need to declare the class to attend the protocol BRPtouchNetworkDelegate. The last thing is to have a property to be able to hold the Network manager (Which is done in the line: private var networkManager: BRPtouchNetworkManager?)
However, you are not supposed to call the "didFinishSearch" method by yourself. When you call startSearchWiFiPrinter, the search begins, and the BRPtouchNetworkManager instance itself calls the didFinishSearch method. It is capable of doing so because you set the delegate in the line: manager.delegate = self.
You should not need 2 classes for this. You should not use 2 instances of BRPtouchNetworkManager either.
Try this. Remember the number you put as an argument to startSearchWiFiPrinter means how long in seconds the search will be.
class EXAMPLEClass: NSObject, BRPtouchNetworkDelegate {
private var networkManager: BRPtouchNetworkManager?
func getPrinter() {
self.startSearchWiFiPrinter()
}
func startSearchWiFiPrinter() {
let manager = BRPtouchNetworkManager()
manager.delegate = self
manager.setPrinterName("Brother QL-720NW")
manager.startSearch(5)
self.networkManager = manager
}
// BRPtouchNetworkDelegate
func didFinishSearch(_ sender: Any!) {
print("4")
guard let manager = sender as? BRPtouchNetworkManager else {
print("5")
return
}
guard let devices = manager.getPrinterNetInfo() else {
print("6")
return
}
print(devices)
print("7")
for deviceInfo in devices {
print("8")
if let deviceInfo = deviceInfo as? BRPtouchDeviceInfo {
print("Model: \(deviceInfo.strModelName), IP Address: \(deviceInfo.strIPAddress)")
}
}
}
}

How to check if WiFi is on or off in iOS Swift 2?

I want to check if the wifi is off then show alert to the user to check his/her connectivity.
I find code like this but it checks if there is an internet connection, not checking if the wifi is on or off:
func isConnectionAvailble()->Bool{
var rechability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, "www.apple.com").takeRetainedValue()
var flags : SCNetworkReachabilityFlags = 0
if SCNetworkReachabilityGetFlags(rechability, &flags) == 0
{
return false
}
let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
You can't.
With Apple's reachability class, you can distinguish three things according to the NetworkStatus struct:
typedef enum : NSInteger {
NotReachable = 0, // 1
ReachableViaWiFi, // 2
ReachableViaWWAN // 3
} NetworkStatus;
You have neither WiFi nor mobile data connection.
You have a WiFi connection, but you may or may not have a mobile data connection.
You have a mobile data connection, but no WiFi connection.
You can't check whether WiFi is turned off, or whether WiFi is turned on but there is no WiFi network nearby, or whether Airplane mode has been turned on.
For mobile data, you can use the telephony class to find whether your device is capable of mobile data connections (iPhone and not iPad, and SIM card plugged in), and you can detect whether mobile data is disabled in the preferences of your application.
Found the following, which was really helpful for me (found on the Apple Developer Forums). The below code works with Swift 4.
func fetchSSIDInfo() -> String {
var currentSSID = ""
if let interfaces:CFArray = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafeRawPointer = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString)
if unsafeInterfaceData != nil {
let interfaceData = unsafeInterfaceData! as Dictionary!
for dictData in interfaceData! {
if dictData.key as! String == "SSID" {
currentSSID = dictData.value as! String
}
}
}
}
}
return currentSSID
}
You can then check if a device is connected to Wi-Fi by the following:
if fetchSSIDInfo() != nil {
/* Wi-Fi is Connected */
}
Not perfect, but if the device is not connected to a Wi-Fi Network, you could then ask the user to connect to a Wi-Fi Network:
let wifiNotifcation = UIAlertController(title: "Please Connect to Wi-Fi", message: "Please connect to your standard Wi-Fi Network", preferredStyle: .alert)
wifiNotifcation.addAction(UIAlertAction(title: "Open Wi-Fi", style: .default, handler: { (nil) in
let url = URL(string: "App-Prefs:root=WIFI")
if UIApplication.shared.canOpenURL(url!){
UIApplication.shared.openURL(url!)
self.navigationController?.popViewController(animated: false)
}
}))
self.present(wifiNotifcation, animated: true, completion: nil)
Tested with swift 4 and swift 5
let nwPathMonitor = NWPathMonitor()
nwPathMonitor.pathUpdateHandler = { path in
if path.usesInterfaceType(.wifi) {
print("Path is Wi-Fi")
} else if path.usesInterfaceType(.cellular) {
print("Path is Cellular")
} else if path.usesInterfaceType(.wiredEthernet) {
print("Path is Wired Ethernet")
} else if path.usesInterfaceType(.loopback) {
print("Path is Loopback")
} else if path.usesInterfaceType(.other) {
print("Path is other")
}
}
nwPathMonitor.start(queue: .main)
As already #abba_de_bo mentioned: you could fetch the current SSID and check if it's set or nil.
This is the answer Apple's Eskimo gave to this question:
The trick with using CF-based APIs from Swift is to get the data into ‘Swift space’ as quickly as possible.
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
}
}
Note that this returns an array of names; how you handle the non-standard cases (no elements, more than one element) is up to you.
Make sure you import SystemConfiguration.CaptiveNetwork. Otherwise the build will fail with on of those error messages:
Use of unresolved identifier 'CNCopySupportedInterfaces'
Use of unresolved identifier 'CNCopyCurrentNetworkInfo'
Use of unresolved identifier 'kCNNetworkInfoKeySSID'
You can take a look at the official Apple sample for Reachability:
https://developer.apple.com/library/content/samplecode/Reachability/Introduction/Intro.html
var netStatus = reachability.currentReachabilityStatus()
var connectionRequired = reachability.connectionRequired()
var statusString = ""
switch netStatus {
case NotReachable:
break
case ReachableViaWWAN:
//DATA
break
case ReachableViaWiFi:
//WIFI
break
}
You can use this method to check:
First you import this framework:
import SystemConfiguration.CaptiveNetwork
func isWifiEnabled() -> Bool {
var hasWiFiNetwork: Bool = false
let interfaces: NSArray = CFBridgingRetain(CNCopySupportedInterfaces()) as! NSArray
for interface in interfaces {
// let networkInfo = (CFBridgingRetain(CNCopyCurrentNetworkInfo(((interface) as! CFString))) as! NSDictionary)
let networkInfo: [AnyHashable: Any]? = CFBridgingRetain(CNCopyCurrentNetworkInfo(((interface) as! CFString))) as? [AnyHashable : Any]
if (networkInfo != nil) {
hasWiFiNetwork = true
break
}
}
return hasWiFiNetwork;
}

Displaying SSID in iOS App using Swift

I'm currently trying to display the SSID of a user's connected WiFi and compare it to a particular SSID, for example, the set SSID is 'WirelessHotspot'.
When the user's connected WiFi is 'WirelessHotspot', the app will display that it is connected to the correct WiFi and also display the WiFi name.
Currently, I have tried this code, referenced from Get SSID in Swift 2:
import UIKit
import Foundation
import SystemConfiguration.CaptiveNetwork
public class SSID {
class func fetchSSIDInfo() -> String {
var currentSSID = ""
if 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
}
}
self.networkname.text = String(currentSSID)
}
return currentSSID
}
}
class AttendanceScreen: UIViewController {
#IBOutlet weak var networkname: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
However, this code:
self.networkname.text = String(currentSSID)
Will return error:
Type 'SSID' has no member 'networkname'
So, how can I implement this in Swift for iOS 9? Thanks in advance!
I figured out that it would be much easier to create a bridge from Swift to Objective-C.
Importing framework:
#import <SystemConfiguration/CaptiveNetwork.h>
Code to get the SSID of user's connected WiFi:
func getMAC()->(success:Bool,ssid:String,mac:String){
if let cfa: NSArray = CNCopySupportedInterfaces() {
for x in cfa {
if let dict = CFBridgingRetain(CNCopyCurrentNetworkInfo(x as! CFString)) {
let ssid = dict ["SSID"]!
let mac = dict["BSSID"]!
return (true, ssid as! String, mac as! String)
}
}
}
return (false,"","")
}
Print and display in a label when needed:
let x = getMAC()
if x.success {
MAClabel = x.mac
SSIDlabel = x.ssid
print(x.mac)
print (x.ssid)
}
I hope that those with this question would find this useful!

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

Resources