Hi. I am developing VPN app with NWTCPConnection.
I have implemented switching network ( from WiFi to LTE or LTE to Wifi ) and upgrade connections or create new connections as Apple suggested.
In Apple document for hasBetterPath property, "Evaluates to true if a new connection attempt to the remote endpoint would use a different and preferred path. If the current connection is not viable, this can be used as a hint to try again. If the current connection is still viable, this can indicate that the system or user has a preference for the newly available network path. For example, if the connection is established over a cellular data network and Wi-Fi is now available, then the connection has a better path available and this property is set to true. Use the initWithUpgradeForConnection:initializer to create a new connection with the same parameters as the current connection. Use Key-Value Observing to watch this property".
As Apple documented, hasBetterPath has been observed when switching network or turn off/on network. However, hasBetterPath sometimes has been observed as soon as connecting new network ( new network should be LTE or WiFi ).
For example, if I switch network from LTE to WiFi, I observe "hasBetterPath" which is expected. Then I do upgrade and create new connection. ( we also have tried to create new connection and new tunnel without upgrading. Both are resulting same )
Normally, new connection successfully connect to VPN with new network and I do not observe "hasBetterPath" after connecting if there is no network changes.
However, in some networks ( Vodafone LTE in Europe or WiFi ), I have observed "hasBetterPath" as soon as connecting to VPN with new network ( Normally it occurs within 1 sec after observing “state” and connection.state = .connected ).
If I handle this weird "hasBetterPath" case and upgrade connection again, device's network goes down ( WiFi or LTE icon shows, but can not browse any website with Safari ). Once device’s network has been down, disconnect VPN ( terminate VPN process ) is the only way to come network back.
Moreover, if I do not handle this weird "hasBetterPath" case and keep staying current connection, I get no observation anymore ( NSKeyValueChangeKey : state, isViable and hasBetterPath ) even though I have added those observations.
Our workaround for this weird “hasBetterPath” case, App has to terminate VPN extension (Disconnect) and create new one. Then connect VPN with same settings. If “hasBetterPath” shows up again as soon as connecting to VPN ( Normally within 1 sec ), App keeps terminating extension and creating new connection until we do not get “hasBetterPath” with current network.
This workaround seems to work if App is in foreground; however, we are not able to launch VPN extension when App is in background and terminate VPN extension.
Please let me know if you need more information about unexpected “hasBetterPath” issue.
//// more update on Code level ///////
This hasBetterPath issue doesn't even need to change network. We have observed this issue easily on iPhone6Plus ( IOS 11.3 and 11.4 )
What I observed is that sometimes "hasBetterPath" has been observed as soon as connection gets connected even though no network change.
Moreover, If I upgrade connection or create new connection with new tunnel after getting this hasBetterPath, device's network goes down ( WiFi or LTE icon shows, but can not browse any website with Safari ).
Once device’s network has been down, disconnect VPN ( terminate VPN process ) is the only way to come network back.
Moreover, if I do not handle this weird ( hasBetterPath right after connection gets connected state ) "hasBetterPath" case and keep current connection, I get no observation anymore ( NSKeyValueChangeKey : state, isViable and hasBetterPath ) even though I have added those observations.
STEPS TO REPRODUCE
1. Try to connect to VPN ( SSL VPN with TCPConnection )
2. We Observed key value "state" of our NWTCPConnection instance and connection state changed to .connected.
3. After processing PPP negotiation on the connection, then we call completionHandler from startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void).
4. Then we observed "hasBetterPath" even though no network change. Normally we do not get this weird hasBetterPath after calling completionHandler from startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void)