Hi, I am currently building my own VPN application using NetworkExtension's PacketTunnelProvider.
I want to send information from the PacketTunnelProvider to the ViewController when a VPN connection fails and to tell the user why.
The code now is as shown below.
When the startTunnel()
being overwritten is executed, somehow NotificationCenter.default.post(name: NSNotification.Name.NEVPNStatusDidChange, object: nil)
is executed and VPNStatusDidChange(_ notification: Notification?)
in the ViewController is called and displays some message.
I tried to do the same thing by writing NotificationCenter.default.post(name: NSNotification.Name(rawValue: "testnotify"), object: nil)
in the PacketTunnelProvider.swift , but it does not work. What is wrong?
Here is a part of current PacketTunnelProvider.swift
override func startTunnel(options: [String : NSObject]? = nil, completionHandler: @escaping (Error?) -> Void) {
conf = (self.protocolConfiguration as! NETunnelProviderProtocol).providerConfiguration! as [String : AnyObject]
self.setupWSSession()
DispatchQueue.global().async {
while (self.connectionPhase < 5) {
Thread.sleep(forTimeInterval: 0.5)
}
self.tunToWS()
}
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "testnotify"), object: nil)
}
And here is a part of ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
initVPNTunnelProviderManager()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.VPNStatusDidChange(_:)), name: NSNotification.Name.NEVPNStatusDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.receieve(_:)), name: NSNotification.Name(rawValue: "testnotify"), object: nil)
}
@objc func VPNStatusDidChange(_ notification: Notification?) {
print("VPN Status changed:")
let status = self.vpnManager.connection.status
switch status {
case .connecting:
print("Connecting...")
connectButton.setTitle("Disconnect", for: .normal)
break
case .connected:
print("Connected...")
connectButton.setTitle("Disconnect", for: .normal)
break
case .disconnecting:
print("Disconnecting...")
break
case .disconnected:
print("Disconnected...")
connectButton.setTitle("Connect", for: .normal)
break
case .invalid:
print("Invliad")
break
case .reasserting:
print("Reasserting...")
break
}
}
@objc func receive(_ notification: Notification?) {
print("receive Notification!")
}
I would like to know how to change the
NETunnelProviderManager.connection.status
available in the Container APP from the PacketTunnelProvider side.
That happens automatically based on the state of the provider that’s visible to the system, for example, whether it’s called your start-tunnel method and whether you’ve then called that method’s completion handler. If you want to provide more detailed information, you’ll need to build that on top of an IPC mechanism.
If possible, I would like to know how to communicate with PacketTunnelProvider without calling
sendProviderMessage(_:responseHandler:)
on the Container APP side.
In situations like this I usually have the container app always call sendProviderMessage(_:responseHandler:)
with a get-latest-status request. The provider then holds on to its completion handler and, the next time the status changes, the provider completes the request with that status.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"