在Swift 2中获取SSID

15

我正在尝试使用这段代码来获取SSID

import Foundation
import SystemConfiguration.CaptiveNetwork

public class SSID {
    class func getSSID() -> String{
        var currentSSID = ""
        let interfaces = CNCopySupportedInterfaces()
        if interfaces != nil {
            let interfacesArray = interfaces.takeRetainedValue() as [String : AnyObject]
            if interfacesArray.count > 0 {
                let interfaceName = interfacesArray[0] as String
                let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
                if unsafeInterfaceData != nil {
                    let interfaceData = unsafeInterfaceData.takeRetainedValue() as Dictionary!
                    currentSSID = interfaceData[kCNNetworkInfoKeySSID] as! String
                    let ssiddata = NSString(data:interfaceData[kCNNetworkInfoKeySSIDData]! as! NSData, encoding:NSUTF8StringEncoding) as! String
                    // ssid data from hex
                    print(ssiddata)
                }
            }
        }
        return currentSSID
    }
}

但是在这一行代码中出现了错误

let interfacesArray = interfaces.takeRetainedValue() as [String : AnyObject]

错误信息为:

类型 'CFArray?' 的值没有成员 'takeRetainedValue'

感谢您的帮助


很可能,您只需删除take(Un)RetainedValue()调用,因为Swift 2中的函数不再返回非托管对象。请参见https://dev59.com/_l0a5IYBdhLWcg3wD1Lb以获取类似的问答。 - Martin R
我删除了 .takeRetainedValue(),但现在当我尝试测试代码时,出现了 EXC_BREAKPOINT (EXC_ARM_BREAKPOINT, subcode=0xe7ffdefe)。 - Oswaldo Rodriguez
很抱歉,我无法帮助您。我没有被控制的网络来测试代码。 - Martin R
不用担心,无论如何还是谢谢。 - Oswaldo Rodriguez
欢迎来到StackOverflow!我已经格式化了您的代码,使其适合普通窗口;但是您可能需要再次检查一下那些非常长的行。祝你好运! - JB.
10个回答

27

这可能会对你有所帮助(在Swift 2上测试通过):

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
    }
}

我从Ray Wenderlich的网站上获取并改编了代码(曾在这里:Retrieve SSID in iOS9,但现在该特定主题已从网站中删除)。

iOS 12

您必须在功能中启用Access WiFi Information。

重要提示 要在iOS 12及更高版本中使用此功能,请在Xcode中为您的应用程序启用Access WiFi Information功能。当您启用此功能时,Xcode会自动向您的entitlements文件和App ID添加Access WiFi Information权限。 文档链接

Swift4.2

public class SSID {
    class func fetchSSIDInfo() -> String {
        var currentSSID = ""
        if let interfaces = 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 let interfaceData = unsafeInterfaceData as? [String: AnyObject] {
                    currentSSID = interfaceData["SSID"] as! String
                    let BSSID = interfaceData["BSSID"] as! String
                    let SSIDDATA = interfaceData["SSIDDATA"] as! String
                    debugPrint("ssid=\(currentSSID), BSSID=\(BSSID), SSIDDATA=\(SSIDDATA)")
                }
            }
        }
        return currentSSID
    }
}

请注意,CNCopySupportedInterfaces 在模拟器上返回 nil。因此,您应该检查 interfaces 是否不为 nil。 - Fogh
是的,实际上我没有考虑过这种可能性。也许最好检查应用程序是否在模拟器中运行,并在这种情况下返回一个“假”的SSID(请参见宏#if TARGET_IPHONE_SIMULATOR)。 - RikiRiocma
只需简单地写成这样就可以了:if let interfaces:CFArray! = CNCopySupportedInterfaces() - Fogh
3
请注意,CaptiveNetwork在iOS 9.0中已被弃用。因此,我建议使用替代方案。 - Matt Le Fleur
3
在iOS 10中不再弃用。https://dev59.com/fG435IYBdhLWcg3w0ThP#33132529 @MattLeFleur - Emin Israfil iOS
显示剩余3条评论

14

这是我的解决方案,使用 Swift 3iOS 10 并且能够在 Xcode 8 中良好运行。

import Foundation

import SystemConfiguration.CaptiveNetwork

class network : NSObject {

    func getSSID() -> String? {

        let interfaces = CNCopySupportedInterfaces()
        if interfaces == nil {
            return nil
        }

        let interfacesArray = interfaces as! [String]
        if interfacesArray.count <= 0 {
            return nil
        }

        let interfaceName = interfacesArray[0] as String
        let unsafeInterfaceData =     CNCopyCurrentNetworkInfo(interfaceName as CFString)
        if unsafeInterfaceData == nil {
            return nil
        }

        let interfaceData = unsafeInterfaceData as! Dictionary <String,AnyObject>

        return interfaceData["SSID"] as? String
    }

}

使用方法:

let wifiName = network().getSSID()

    guard wifiName != nil else {

        //// TODO: Alert -----
        print("no wifi name")

        return
    }


    print("my network name is: \(wifiName!)")

PS:注意,它在模拟器上无法工作


这在iOS 10中完美运行,使用Swift 3。谢谢! - bey23

8

目前提出的所有解决方案似乎都相当复杂,有丑陋不安全的强制转换。

我能够设计出如此简洁的解决方案(完全没有黑魔法):

import Foundation
import SystemConfiguration.CaptiveNetwork

func getSSID() -> 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
}

"CNCopySupportedInterfaces" 在 iOS 9.0 中已被弃用。 - norbDEV
1
然而,在这里(https://forums.developer.apple.com/thread/11807)和许多次在SO上讨论过,我们没有其他选择。 - werediver

5
在Swift 3中(适用于真实设备和模拟器):
import SystemConfiguration.CaptiveNetwork

internal class SSID {
    class 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!
                    currentSSID = ((interfaceData as? [String : AnyObject])?["SSID"])! as! String

                }
            }
        }
        return currentSSID
    }
}

使用方法:

SSID.fetchSSIDInfo()

//will return "" if no connected wifi or running in simulator 

2

Swift 4版本

import SystemConfiguration.CaptiveNetwork


func getSSID() -> String? {
    guard let interface = (CNCopySupportedInterfaces() as? [String])?.first,
        let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any],
        let ssid = unsafeInterfaceData["SSID"] as? String else{
            return nil
    }
    return ssid
}

2
我总是得到我的WIFI的nil值。如何修复这个问题? - Jerry Chong
你是否在功能中启用了访问WiFi信息? - alegelos
1
我的账户无法从功能中启用“访问WIFI信息”。 - Jerry Chong
你试过这个吗?https://izziswift.com/wp-content/uploads/2019/03/get-wifi-information-izziswfit.png - alegelos
从iOS13开始,用户必须按照这里所述允许位置服务:https://dev59.com/Srfna4cB1Zd3GeqPsGiK#58818768 - atineoSE

1
在Swift 2中,您不需要调用takeRetainedValue
将代码interfaces.takeRetainedValue() as [String : AnyObject]替换为Array(arrayLiteral: interfaces)
还要记得将代码interfacesArray[0] as String更改为String(interfacesArray[0])
完整代码:
public class SSID {
class func getSSID() -> String{
    var currentSSID = ""
    let interfaces = CNCopySupportedInterfaces()
    if interfaces != nil {
        let interfacesArray = Array(arrayLiteral: interfaces)
        if interfacesArray.count > 0 {
            let interfaceName =  String(interfacesArray[0])
            let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interfaceName)
            if unsafeInterfaceData != nil {
                let interfaceData = unsafeInterfaceData.takeRetainedValue() as Dictionary!
                currentSSID = interfaceData[kCNNetworkInfoKeySSID] as! String
                let ssiddata = NSString(data:interfaceData[kCNNetworkInfoKeySSIDData]! as! NSData, encoding:NSUTF8StringEncoding) as! String
                // ssid data from hex
                print(ssiddata)
            }
        }
    }
    return currentSSID
}

}


这段代码在iOS 9.2下无法编译。它仍然使用一个已经不再可用的takeRetainedValue()版本。 - mbeaty

1

在Swift中获取WiFi网络的SSID和BSSID

我看到了很多使用SystemConfiguration框架的这个非常流行的问题的版本。阅读这些答案列表,我发现它们都很混乱。不安全的位转换、魔法字符串、奇怪的强制转换。每当一个API返回CFArrayCFDictionary时,使用toll-free bridging来获取NS{Array,Dictionary}。它可以让你避免一些(在Swift上下文中)更丑陋的CoreFoundation方面。此外,您应该使用头文件中定义的常量来获取SSID和BSSID字典值。这里绝对没有必要使用不安全类型,所有数据类型都是明确定义的。话虽如此,在iOS 14中,这段代码的CaptiveNetwork版本已被弃用,建议您改用NetworkExtension框架。

NEHotspotNetwork

import NetworkExtension

NEHotspotNetwork.fetchCurrent { hotspotNetwork in
    if let ssid = hotspotNetwork?.ssid {
        print(ssid)
    }
}

已弃用 - CaptiveNetwork 方法

import SystemConfiguration.CaptiveNetwork

func getWiFiNetwork() -> (ssid: String, bssid: String)?
{
    var wifiNetwork: (ssid: String, bssid: String)?
    if let interfaces = CNCopySupportedInterfaces() as NSArray? {
        for interface in interfaces {
            let name = interface as! CFString
            if let interfaceData = CNCopyCurrentNetworkInfo(name) as NSDictionary? {
                if let ssid = interfaceData[kCNNetworkInfoKeySSID] as? String,
                    let bssid = interfaceData[kCNNetworkInfoKeyBSSID] as? String {
                    wifiNetwork = (ssid: ssid, bssid: bssid)
                }
            }
        }
    }
    
    return wifiNetwork
}

权限 - CoreLocation

在用户权限方面,您有几种可能性,但需要在CNCopyCurrentNetworkInfofetchCurrent的文档中定义其中四个选项之一 - 对于大多数情况,我认为您需要添加CoreLocation并请求使用用户位置的权限。例如,在Info.plist中隐私 - 使用时获取位置需要说明为什么需要用户位置,然后您必须调用请求用户授权对话框。

    import CoreLocation

    CLLocationManager().requestWhenInUseAuthorization()

权利

您的应用程序还需要权限 - com.apple.developer.networking.wifi-info,该权限已添加到项目的签名和功能部分,并称为访问WiFi信息。在使用NEHotspotNetwork方法时,还需要额外的网络扩展权限。


0

https://stackoverflow.com/users/3108877/rob的答案--简短版

func getSSID() -> String? {
        if let interface = (CNCopySupportedInterfaces() as? [String])?.first,
            let unsafeInterfaceData = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any],
            let ssid = unsafeInterfaceData["SSID"] as? String {
            return ssid
        }
        return nil
    }

0

您可以在 @japes 的更新的 Swift 标准答案中找到另一个答案,该答案支持 Swift 3Swift 4。在模拟器上返回空的 ""

import SystemConfiguration.CaptiveNetwork

internal class SSID {

    class func fetchSSIDInfo() -> String {
        var currentSSID = ""
        if let interfaces = CNCopySupportedInterfaces() {
            for i in 0..<CFArrayGetCount(interfaces){
                let interfaceName = CFArrayGetValueAtIndex(interfaces, i)
                let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
                guard let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString) else {
                    return currentSSID
                }
                guard let interfaceData = unsafeInterfaceData as? [String: Any] else {
                    return currentSSID
                }
                guard let SSID = interfaceData["SSID"] as? String else {
                    return currentSSID
                }
                currentSSID = SSID
            }
        }
        return currentSSID
    }

}

0
以下函数返回WiFi名称和Mac地址。
    func getNetworkInfo()->(success:Bool,ssid:String,mac:String){
      var currentSSID:String = ""
      var macAdrees:String = ""
      var succes:Bool = false
      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
            macAdrees = interfaceData["BSSID"] as! String
            succes = true
        } else {
            currentSSID = ""
        }
    }

    return (succes, currentSSID, macAdrees)
}

这段代码运行良好。在您的开发目标>= iOS9中可能会注意到一些警告。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接