NEHotspotNetwork - The application crashes during the linking process

Hello,

I have problem with compiling my project. When I include NEHotspotNetwork library to my project and try e.g. get information about network :

NSArray * networkInterfaces = [NEHotspotHelper supportedNetworkInterfaces];

So everything looks fine, but during compiling/linking the application crashes and xcode shows recent Issues:

"_OBJC_CLASS_$_NEHotspotNetwork", referenced from:
Objc-class-ref in iosNative.o
: Symbol(s) not found for architecture x86_64
Linker command failed with exit code 1 (use -v to see invocation)

What am I doing wrong ?

A few questions here:

  1. Is this a Catalyst app, ": Symbol(s) not found for architecture x86_64?" The NEHotspotHelper symbols are available there, but the APIs do not actually work in a macOS environment.
  1. If this is iOS, do you have the com.apple.developer.networking.HotspotHelper entitlement if you are working with these APIs?
Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Hello,

this is iOS app. No I have not, but also tried to get info about SSID. So I wrote this part of code :

    if (@available(iOS 14.0, *)) {
        [NEHotspotNetwork fetchCurrentWithCompletionHandler:^(NEHotspotNetwork * _Nullable currentNetwork) {
           NSString  *strSSID = [currentNetwork SSID];
           NSLog(@"SSID: %@",strSSID);
        }];
    } 

On the webpage is written, that I only need these entitlements:

<key>com.apple.developer.networking.wifi-info</key><true/>
<key>com.apple.external-accessory.wireless-configuration</key><true/>

but I also get same problem during the app compiling/linking :-(

First, regarding the use of fetchCurrentWithCompletionHandler, the header documentation on this symbol does list out the requirements:

This method returns SSID and BSSID of the current Wi-Fi network when the requesting application meets one of following 4 requirements -.

1. application is using CoreLocation API and has user's authorization to access precise location.
2. application has used NEHotspotConfiguration API to configure the current Wi-Fi network.
3. application has active VPN configurations installed.
4. application has active NEDNSSettingsManager configuration installed.

An application will receive nil if it fails to meet any of the above 4 requirements.
An application will receive nil if does not have the "com.apple.developer.networking.wifi-info" entitlement.

Next, regarding your linker issue; it looks like you are running a Qt application based on the path in your image: /iotmeter/app/Qt/IoTMeter/ios/src/iOSNative.mm. I would recommend that you extract your code out of the Qt project and test it from a blank test bed project. If you can get it working there, you know that you have to resolve a linking issue in the configuration of your Qt project.

Try it with this Swift code and CoreLocation on iOS 14.


import UIKit
import NetworkExtension
import os
import CoreLocation

class ViewController: UIViewController {
    
    var locationManger: CLLocationManager?

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    
    // MARK: - Public CoreLocation Methods

    @IBAction func startLocationManager() {

        guard locationManger == nil else {
            // If locationManager is being started for the second time, for instance in .confirmNetwork, don't set accuracy and delegate again.
            locationManger?.requestWhenInUseAuthorization()
            locationManger?.startUpdatingLocation()
            return
        }

        locationManger = CLLocationManager()
        locationManger?.delegate = self
        locationManger?.desiredAccuracy = kCLLocationAccuracyKilometer
        locationManger?.requestWhenInUseAuthorization()
        locationManger?.startUpdatingLocation()
    }


    @IBAction func testNetwork() {
        NEHotspotNetwork.fetchCurrent(completionHandler: { (network) in
            if let unwrappedNetwork = network {
                let networkSSID = unwrappedNetwork.ssid
                os_log("Network: %{public}@ and signal strength %d", networkSSID , unwrappedNetwork.signalStrength)
            } else {
                os_log("No available network")
            }
        })
    }
}

// MARK: - CLLocationManagerDelegate Methods

extension ViewController: CLLocationManagerDelegate {

    // MARK: - CLLocationManagerDelegate Methods

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let lastLocation = locations.last {
            print("<LocationManager> lastLocation:\(lastLocation.coordinate.latitude), \(lastLocation.coordinate.longitude)")
        }
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        // Detect the CLAuthorizationStatus and enable the capture of associated SSID.
        if status == CLAuthorizationStatus.authorizedAlways ||
            status == CLAuthorizationStatus.authorizedWhenInUse  {
            // Stubbing out authorization checks
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        if let error = error as? CLError, error.code == .denied {
            print("<LocationManager> Error Denied: \(error.localizedDescription)")
            // Notify the user of any errors.
            manager.stopUpdatingLocation()
        }
    }
}

Next, add two buttons onto the Storyboard that trigger the startLocationManager first and then the testNetwork function second.

Next, add this to your entitlements file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.developer.networking.wifi-info</key>
	<true/>
	<key>com.apple.external-accessory.wireless-configuration</key>
	<true/>
</dict>
</plist>

And then lastly add the location usage description keys to your Info.plist for what makes sense in your application:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Gather location updates to get SSID</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Gather location updates to get SSID</string>

Let me know if that works out better, and then try and refactor your Qt project to use the same recipe. If that still does not work, you will need to resolve how your Qt project is linking the NetworkExtension framework.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
NEHotspotNetwork - The application crashes during the linking process
 
 
Q