I'm currently trying to build a proof-of-concept iOS app to check if we are able to implement some sort of indoor positioning capability without deploying beacons or any other hardware.
What we have
There is a database containing all registered access points in our building including their X- and Y-coordinates. The coordinates are mapped to a custom-built grid that spans the whole building.
The app will be released using our Enterprise distribution, so there are no constraints concerning any Apple Store requirements. The app will be running exclusively on devices that automatically connect to the proper WiFi using a certificate.
What we'd like to build
In order to improve the usability of the app, we'd like to show the user his current position. Using Apples native CLLocation
services is not accurate enough because we are operating inside a building. The basic idea is to fetch all nearby access points including their BSSID and signal strength and calculate a more or less accurate position using both signal strength and the location database for our access points (see above).
What i've tried so far
Using SystemConfiguration.CaptiveNetwork
to get the BSSID
import SystemConfiguration.CaptiveNetwork
func getCurrentBSSID() -> String {
guard let currentInterfaces = CNCopySupportedInterfaces() as? [String] else { return "" }
for interface in currentInterfaces {
print("Looking up BSSID info for \(interface)") // en0
let SSIDDict = CNCopyCurrentNetworkInfo(interface as CFString) as! [String : AnyObject]
return SSIDDict[kCNNetworkInfoKeyBSSID as String] as! String
}
return ""
}
This solution works (after setting the proper entitlements), but i'm only able to read the BSSID of the CURRENTLY CONNECTED access point.
Using UIStatusBarDataNetworkItemView
to read signal strength
private func wifiStrength() -> Int? {
let app = UIApplication.shared
var rssi: Int?
guard let statusBar = app.value(forKey: "statusBar") as? UIView, let foregroundView = statusBar.value(forKey: "foregroundView") as? UIView else {
return rssi
}
for view in foregroundView.subviews {
if let statusBarDataNetworkItemView = NSClassFromString("UIStatusBarDataNetworkItemView"), view .isKind(of: statusBarDataNetworkItemView) {
if let val = view.value(forKey: "wifiStrengthRaw") as? Int {
rssi = val
break
}
}
}
return rssi
}
This one is kind of obvious, it only reads the signal strength for the connected WiFi network, not the access point specific one.
QUESTION
Is there any way to read a list of available access points (not WiFi networks) including their BSSID and signal strength? We cannot jailbreak the devices since they are under device management.
Maybe there is some way to do it using MobileWiFi.framework
(see this link), but i couldn't wrap my head around doing it in Swift (kind of a beginner when it comes to iOS development).