Open sultanmyrza opened 3 years ago
SwiftWifiIotPlugin method getSSID() can be changed to:
private func getSSID() -> String? {
var ssid: String?
if #available(iOS 14.0, *) {
NEHotspotNetwork.fetchCurrent(completionHandler: { currentNetwork in
ssid = currentNetwork?.ssid
})
}
if(ssid == nil){
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 case the NEHotspotNetwork gives the error, the CNCopySupportedInterfaces will do the trick. Tested on iOS 14.7.1
Related issue: #163
the fix for getSSID
is done at #175.
@DominikStarke Does the PR fix this issue too?
Maybe!?
I've only ever seen this error if com.apple.developer.networking.HotspotConfiguration isn't properly set.
It requires the provisioning profile to contain the entitlement and can only be unlocked on developer.apple.com. Manually adding it to the entitlement file is not enough.
@sultanmyrza Can you test against PR and let us know if it fixes the issue. Else as @DominikStarke suggested, check the entitlements the profiles on developer.apple.com account.
Hello, I encountered the same issue as well.
I checked the documents and it was said that in order to make NEHotspotNetwork.fetchCurrent()
working one of the four requirements must be satisfied, this is written in the NetworkExtentsion file
The following link also mentions the same requirements https://developer.apple.com/forums/thread/679038
I assume the package is trying to fulfil the second requirement, however I didn't see that the NEHotspotConfiguration API is called from the getSSID()
function in ios/Classes/SwiftWifiIotPlugin.swift judging from the code.
I tried to satisfy the first requirement by :
Adding the following variable to SwiftWifiIotPlugin
class
var locationManager = CLLocationManager();
and add the following code to the handle()
locationManager.requestWhenInUseAuthorization()
and it worked after the app asked for the device location, hence satisfy the first requirement.
By all means I am not experienced in swift, so I do not understand much how the code works at the moment, but apparently using NEHotspotConfiguration API seems requires the Wi-Fi details where it will mostly be unknown most of the time, so I am not sure how you can use that to get the SSID.
The plugin only fulfills condition 2, if you connected to the wifi using the plugin as well.
Otherwise you'll need the locationPermission (for example using this plugin: https://pub.dev/packages/permission_handler)
[] NEHotspotNetwork nehelper sent invalid result code [1] for Wi-Fi information request
is also logged out when calling WiFiForIoTPlugin.connect
(Tested with iOS 15).
Turns out that connect
tries to fetch current wifi info after connecting - to see if it was connected or not - apparenly the comment (L157) reads this is to check if wifi was found or not - ios does not throw any error for it. Check this part:
On my test device - the device gets connected to the wifi but returns with false
with folowing output:
WiFi network not found
This is the print message from L160 (confirmed it by changing the message).
Looks like getSSID
is returning null (at least immediately) even when the network is connected via NEHotspotConfiguration
.
@DominikStarke Can you confirm the above findings? And do you have any idea of how to fix it?
Some references
apply(_:completionHandler:)
The system calls your completion handler when it has applied the Wi-Fi level configuration. A successful configuration doesnʼt mean the device has joined that Wi-Fi network. To get the current Wi-Fi state, call fetchCurrent(completionHandler:).
I cannot confirm this right now, because I don't have my macbook available until monday.
It seems we have to check for connectivity before proceeding any further as mentioned in the article:
Furthermore, joining a Wi-Fi network doesn’t guarantee that the network is fully operational. The system might still be in the process of configuring TCP/IP on that network.
The article also mentions that we should call fetchCurrent to retrieve a NEHotspotNetwork, which should hold some information regarding the currently joined network. But in my tests these informations were always null.
I checked by adding delay - it worked but is unreliable - sometimes it too 4s - sometimes 8s, sometimes >10s.
In android in older connectToDeprecated
method we used to wait for upto 30s - checking every second.
Something similar needs to be implemented.Maybe.
But when calling connect
twice - second time it always works.
This the code I tested with
NEHotspotConfigurationManager.shared.apply(configuration) { [weak self] (error) in
guard let this = self else {
print("WiFi network not found")
result(false)
return
}
if (error != nil) {
if (error?.localizedDescription == "already associated.") {
print("Already connected")
result(true)
} else {
print("Not Connected")
result(false)
}
}else{
var checkCount = 0;
let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
checkCount += 1
this.getSSID { (sSSID) -> () in
print("Check if connected after x\(checkCount) seconds...")
if sSSID != nil || checkCount > 15 {
timer.invalidate()
if let ssid = sSSID {
print("Connected to " + ssid)
// ssid check is required because if wifi not found (could not connect) there seems to be no error given
result(ssid == sSSID)
} else {
print("WiFi network not found")
result(false)
}
}
}
}
}
}
As I said is unreliable - sometimes it does not work even after 15s.
@DominikStarke Let me know if any syntactical error - I don't know ios/swift.
I see 3 approaches (from best case to worse case) from here to reliably return the result of connection request:
getSSID
work after NEHotspotConfigurationManager.apply
NEHotspotConfigurationManager.apply
twice - as it definetly works the second timegetSSID
worksApart from this, we can choose to not fix it and add this as caveats in README.
Posted about it on Apple Forum: https://developer.apple.com/forums/thread/695418
Hi all,
Any movement on this at all?
Android works perfectly but iOS however... More often than not I get NEHotspotNetwork nehelper sent invalid result code [1] for Wi-Fi information request
followed by WiFi network not found
in my console but I find the iPhone has actually connected. WiFiForIoTPlugin.connect()
then returns false
causing my error handling to catch it and ask the user to try again, as mentioned previously in this thread calling WiFiForIoTPlugin.connect()
a second time returns true
While calling WiFiForIoTPlugin.connect()
a second time on iOS does return true
it also causes the "join network" iOS native prompt to appear a second time, which isn't a great user experience.
I have tried a few other things in my flutter code but with not much luck, if anyone has any updates or solutions, I would greatly appreciate assistance
Many thanks
@liamjbarry Got 1 response on the Apple Forum thread, will work on it and get back here.
Any progress on this issue?
I don't know if this is helpful, but just in case:
I get this error after a recent change to a jailbreak device. I'm currently in the process of diagnosing it because it's rather annoying.
Symptoms:
At a seemingly random time after using Unc0ver to jailbreak the device (that is: everything is fine in the first few minutes post-jailbreak)
On the other side of this:
I arrived at this thread because while replicating the issue in Instagram I got this:
error 09:47:46.839605-0300 Instagram Couldn't read values in CFPrefsPlistSource<0x281b9f600> (Domain: group.com.burbn.instagram, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd
error 09:47:46.858078-0300 Instagram nehelper sent invalid result code [1] for Wi-Fi information request
error 09:47:46.861257-0300 nehelper WiFiManagerClientGetDevice: null deviceClient for interface <private> (manager <private>)
error 09:47:46.861340-0300 nehelper [NEHelperWiFiInfoManager] WiFiManagerClientGetDevice for en1 returned NULL
error 09:47:46.862843-0300 nehelper WiFiManagerClientGetDevice: null deviceClient for interface <private> (manager <private>)
error 09:47:46.862972-0300 nehelper [NEHelperWiFiInfoManager] WiFiManagerClientGetDevice for en2 returned NULL
error 09:47:46.865622-0300 CommCenter Client [<private>] entitlement failed: 'public-signal-strength', required for request "<private>"
Note the second line
Apologies if this pollutes the thread. I am hoping that it adds information that helps unblock others. If I get the go-ahead I will try to loop back on this when I find the solution for my specific device.
@Joshfindit Feel free to shed light on this issue.
@daadu So I had some time to do some digging and I have come up with the following...
The example given by Apple shows confirming the connected SSID in a separate screen/process, not being called automatically after a successful NEHotspotConfigurationManager.shared.apply
so I first commented out the line to automatically get the SSID, moved this code to a new function in the Swift file and setup all the other code so I could call this function from Flutter (I know I could have used the getSSID()
function that already existed I just wanted my own that I could modify and break etc)
Flutter code in the example app now looks like
Future<bool> connect() async {
try {
var isApplied = await WiFiForIoTPlugin.connect(ssid,
password: pass,
security: NetworkSecurity.WPA,
withInternet: false,
joinOnce: true);
print("wifi applied $isApplied");
var currentSSID = await WiFiForIoTPlugin.currentSSID(); //this is the function I added
print(currentSSID);
return isConnected;
} on Exception catch (e) {
print(e.toString());
return false;
}
}
Swift code for my currentSSID()
function
private func getCurrentSSID(result: FlutterResult) {
var count = 0;
if #available(iOS 14.0, *) {
Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { timer in
if (count == 8) {
timer.invalidate()
}
NEHotspotNetwork.fetchCurrent(completionHandler: { (network) in
if let unwrappedNetwork = network {
let networkSSID = unwrappedNetwork.ssid
print("Network: \(networkSSID) and signal strength \(unwrappedNetwork.signalStrength)")
timer.invalidate()
} else {
print("No available network")
}
})
count += 1
print("[DEBUG] - Number: \(count)")
}
}
}
I have very little knowledge of swift so this was all a bit of a stab in the dark, I managed to steal bits of this from various forum posts, this seemed to work it would successfully log the correct network name to console and reliably work too. I had the timer in from previous testing but I imagine this could be removed. I was getting the correct result printed to console so now I just needed to get the SSID back to Flutter so I could confirm it was connected to the network I requested in Flutter. After reading some of the other code in the wifi_iot library I tried adding an @escaping
tag to return the value and suddenly I was getting the dreaded [] NEHotspotNetwork nehelper sent invalid result code [1] for Wi-Fi information request
again, I removed the @escaping
(reverted to Swift code above) and it worked reliably again.
Swift code with @escaping
private func getCurrentSSID(result: @escaping FlutterResult) {
var count = 0;
if #available(iOS 14.0, *) {
Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { timer in
if (count == 8) {
timer.invalidate()
}
NEHotspotNetwork.fetchCurrent(completionHandler: { (network) in
if let unwrappedNetwork = network {
let networkSSID = unwrappedNetwork.ssid
print("Network: \(networkSSID) and signal strength \(unwrappedNetwork.signalStrength)")
timer.invalidate()
result(networkSSID);
} else {
print("No available network")
}
})
count += 1
print("[DEBUG] - Number: \(count)")
}
}
}
So the TLDR of this is I believe it’s some sort of async/await problem? As I said I am unfamiliar with Swift so I may well be doing it wrong but from my testing as soon as I added the @escaping
it would stop working reliably.
All of this code is incomplete as I was just trying to get to the bottom of what the issue was and I hope I made some headway on this issue or at least understanding it. I am unsure as to what a solution might be as I have little knowledge of how Flutter interacts with Swift code and Swift itself. from my testing it seems that applying the configuration and checking the currently connected network need to be called separately, again I am unsure as to why this is but it seems to work reliably when you do that.
I apologise for the waffle but I had a real roller-coaster of a day with all this testing on Friday 😆 If anyone has any ideas or suggestions as to what to try next please feel free
@liamjbarry Thanks for the effort and sharing it. I am not good with Swift either, a lot of the swift code was written by someone else.
@DominikStarke Can you check the above comment? any idea on what makes this work? how can we fix the issue by integrating this?
@daadu, came across problem #271 getSSID returns nil for iOS 15 and above. It led here to this defect, however, I don't think it's related as we see this error but the connection still works.
Tried with a loop(20 times 1 sec interval) calling the isConnected() API to perform the NEHotspotNetwork.fetchCurrent() call and when it fails it's still failing. Tried calling the connect() API after failure and it returns within 4s as connected, whereas it previously took 6-8s on a successful connection, the downside is this can cause a duplicate OS request to join the network.
The problem with calling the API twice is that we can't determine that the user has not clicked cancel, only a true/false is returned for all paths.
There is a possibility to return an error in this scenario, but this is not the current behaviour of the plugin, and I don't want to provide a solution that is unacceptable. Would it be ok to return an error when the user denies access that can be detected by the user of the wifi_iot and catch it in a try-catch block?
@darhaywa You could do that, and would be considered breaking change - plus, need to implement similar behavior with Android.
Lately, I have not been able to work on this - but the real solution here is #229. In wifi_connect_to
plugin [#189] - we can plan proper error-results. But sadly, I am not able to give time to it.
I run example app https://github.com/alternadom/WiFiFlutter/tree/master/example on ios getting this error
My environment
My
Runner.entitlements
click to expand
``` xmlMy
Info.plist
click to expand
``` xml