Unfortunately My App won't run anymore because of a missing symbol:
dyld: Symbol not found: _NEHotspotConfigurationErrorDomain
Referenced from: /private/var/containers/Bundle/Application/905F594E-CBAC-43C6-8B9D-7EF29E3C3E6A/Runner.app/Frameworks/part1.framework/part1
Expected in: /System/Library/Frameworks/NetworkExtension.framework/NetworkExtension
in /private/var/containers/Bundle/Application/905F594E-CBAC-43C6-8B9D-7EF29E3C3E6A/Runner.app/Frameworks/dashcam.framework/part1
This is a new error and only started showing this morning when I tried compiling our iOS App with Xcode11 GM Seed.
Our deployment target is 12.4.
Has the symbol moved?
Bug number FB7285688.
Thanks for that.
Are those references to the configuration error what causes the trouble?
Yes. If I comment out lines 11 through 29 of your test code, the reference to
NEHotspotConfigurationErrorDomain goes away. If I then uncomment lines 28 through 29, it comes back.
Unfortunately can not use
as it would still crash.if #available(iOS 13.0, *) {
Right. The
#available guard prevents you from running that code but the issue here is that the linker has added a strong reference to the symbol, and it does that because it thinks the symbol is available all the way back to iOS 11.
It’s tricky to work around this because just touching the error codes, as shown below, triggers the reference )-:
print(NEHotspotConfigurationError.Code.invalid)The best option I can think of right now is to bounce into
NSError space:
if let error = error as NSError? {
switch (error.domain, error.code) {
… case clauses here …
}
}Then declare the
NSError equivalents of the required values under a new name:
let NEHotspotConfigurationErrorDomainWorkaround: String = {
… tricky code here …
}()
enum NEHotspotConfigurationErrorWorkaround: Int {
case alreadyAssociated = 13
}Note It’s OK to hard code the 13 here because the error codes are coming from Objective-C, which means they can’t change (changing them would break Objective-C clients).
Now, implement the
case clause as follows:
case (NEHotspotConfigurationErrorDomainWorkaround, NEHotspotConfigurationErrorWorkaround.alreadyAssociated.rawValue):
… your code here …Then all you need to do is write the body of
NEHotspotConfigurationErrorDomainWorkaround. Easy! Nah, not really. Here’s what I eventually come up with:
let NEHotspotConfigurationErrorDomainWorkaround: String = {
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
if let sym = dlsym(RTLD_DEFAULT, "_NEHotspotConfigurationErrorDomain") {
// If `NEHotspotConfigurationErrorDomain` is available, use its value.
return String(cString: sym.assumingMemoryBound(to: CChar.self))
} else {
// If not, meaning we’re on iOS 12 or earlier, use a hard-coded value
// that matches the value used on those systems.
return "NEHotspotConfigurationErrorDomain"
}
}()Wow, that’s a whole barrel of un-fun.
WARNING I’ve tested bits of this code but haven’t done a full end-to-end test on iOS 12 and iOS 13. Let me know how it goes (-:
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"