11 Replies
      Latest reply: Feb 23, 2017 5:24 PM by adam.ma RSS
      sdfijasdlfkjasd Level 1 Level 1 (0 points)

        We're looking to create a packet tunnel provider network extension. Inside this extension we will have some custom client code that runs to check a few things on the device prior to allowing the VPN to connect per enterprise policy. This code will be inside of the startTunnelWithOptions:completionHandler: block and execute prior to fully completing the connection, if something is wrong the connection will not be completed. The initial VPN profile and such will be installed during the first execution of the container app.


        My question is around how we can relay to the user why the VPN connection was not allowed. This is an enterprise application where specific artifacts must be present prior to the VPN connection completing (OS version, WiFi vs. Celluar, etc). Our code inside startTunnelWithOptions:completionHandler: determines this. The VPN will be initiated on-demand or per-app, (it could be started from inside the container app but unlikely), therefore our container app may not be running at all when the VPN comes up but the extension will clearly be called when appropriate. This rule's out the use of handleAppMessage:completionHandler: to send some kind of message back to the user if the container app is closed (I thought this was the intention of the handleAppMessage API but maybe not). If the container app is not running this API will not work, correct? Even if it did work, it won't flip the user back to the container app, correct?


        Our issues is that the container app provides a dashboard and we need to tell the user why the VPN connection was disallowed. The way I see it we could do this  in two ways:


        1) If it's allowed for an extension to show a UI elemetn (e.g., deprecated alertView, etc) initiated by the code inside startTunnelWithOptions, but it's unclear to me if we are able to do that as an extension. Idealy we would display a UIAlert window stating that the connection was disallowed and the user needs to open our app to see why.


        2) We could call back to our container app  via openURL, it would be launched if not running, and we could then have it display the dashboard along with the reason why the VPN connection was disallowed (sent in the openURL payload). The problem with this is that only Today extensions can do this per documentation "Each extension point determines whether to support this method, or under which conditions to support this method." "A Today widget (and no other app extension type) can ask the system to open its containing app by calling the openURL:completionHandler: method of the NSExtensionContext class. ". Obviously, there may be work arounds to launch the app still but its clearly not supported to do so as a Network Extension.


        Any idea's how a network extension can display a simple message to the user in response to the VPN not starting? This would need to be displayed in any scenario that the VPN starts, via general->settings->VPN, ondemand, etc.


        Thanks

        • Re: Can a Network Extension display any UI or launch it's container app?
          mike.ly Level 1 Level 1 (10 points)

          There's a new displayMessage:completionHandler: method in NEProvider that might be useful.

            • Re: Can a Network Extension display any UI or launch it's container app?
              eskimo Apple Staff Apple Staff (5,995 points)

              mike.ly wrote:

              There's a new -displayMessage:completionHandler: method in NEProvider that might be useful.

              Indeed.  I’d completely forgotten about that.

              sdfijasdlfkjasd’s wrote:

              1) If it's allowed for an extension to show a UI elemetn (e.g., deprecated alertView, etc) initiated by the code inside startTunnelWithOptions, but it's unclear to me if we are able to do that as an extension.

              Network Extension provider extensions are definitely not allowed to display UI directly.

              2) We could call back to our container app via openURL …

              Yeah, that’s definitely not going to work.  Code running in the background (like Network Extension provider extension) is not allowed to open a URL because it would switch the user’s foreground app out from underneath them.

              I’m still researching whether it’s possible to use iOS 10’s new User Notification framework to post real notifications from an Network Extension provider extension.  The good news is that, even if that doesn’t work out, -displayMessage:completionHandler: provides a minimum level of functionality for you.

              Share and Enjoy

              Quinn “The Eskimo!”
              Apple Developer Relations, Developer Technical Support, Core OS/Hardware
              let myEmail = "eskimo" + "1" + "@apple.com"

                • Re: Can a Network Extension display any UI or launch it's container app?
                  sdfijasdlfkjasd Level 1 Level 1 (0 points)

                  Thanks for the help on this. I understand both points. displayMessage should work for what we're tyring to do! In the event we wanted to use notifications, are you thinking that normal notifications would not work and iOS 10's new mechanism would? I was under the impression that having our VPN client code schedule a notification to be sent to the device would be a last result to send them a message, but it sounds like that may not be possible and only possible under iOS 10's new mechanism?

                    • Re: Can a Network Extension display any UI or launch it's container app?
                      eskimo Apple Staff Apple Staff (5,995 points)

                      In the event we wanted to use notifications, are you thinking that normal notifications would not work and iOS 10's new mechanism would?

                      The current UILocalNotification mechanism requires access to +[UIApplication sharedApplication], which is not available to extensions (it’s tagged with NS_EXTENSION_UNAVAILABLE_IOS).  In contrast, the entry point to the User Notification framework is +[UNUserNotificationCenter currentNotificationCenter], which is available to extensions.  So, I can’t see any reason why it wouldn’t work.  OTOH, I don’t think anyone has tested it in the context of an Network Extension provider extension.

                      If you have time to test it yourself, please give it a whirl and let us know what you see.

                      Share and Enjoy

                      Quinn “The Eskimo!”
                      Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                      let myEmail = "eskimo" + "1" + "@apple.com"

                        • Re: Can a Network Extension display any UI or launch it's container app?
                          eskimo Apple Staff Apple Staff (5,995 points)

                          If you have time to test it yourself, please give it a whirl and let us know what you see.

                          After discussing this with the User Notification framework engineering team, the consensus is that this should work.  I still haven’t had chance to sit down and test it myself though.

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"

                            • Re: Can a Network Extension display any UI or launch it's container app?
                              adam.ma Level 1 Level 1 (0 points)

                              Hello, eskimo,

                               

                                  I tried NSUserNotification on mac, and it doesn't work.

                               

                               

                              class PacketTunnelProvider: NEPacketTunnelProvider, NSUserNotificationCenterDelegate {

                                  override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {

                                      ....

                                      let notification = NSUserNotification.init();

                                      notification.title = "mactunnel";

                                      notification.informativeText = "do body"

                                      notification.soundName = NSUserNotificationDefaultSoundName

                                      NSUserNotificationCenter.default.delegate = self

                                      NSUserNotificationCenter.default.deliver(notification)

                                  }

                               

                              delegate

                               

                               

                                  func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool {

                                      NSLog("should present")

                                      return true

                                  }

                                  func userNotificationCenter(_ center: NSUserNotificationCenter, didDeliver notification: NSUserNotification) {

                                      NSLog("did deliver")

                                  }  

                                  func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) {

                                      NSLog("did active")

                                  }

                               

                              Only "did deliver" is printed, but the notification is not delivered to the system notification panel, surprisely, no any error messages are printed any where.

                               

                              I am using sierra, 10.12.1. MacBook Pro Retina Mid2012.

                               

                              Same code works in container app context.

                               

                              Any idea why it doesn't work? My use case is I want to prompt logon dialog for username and password, in case the container app is not running, and user start vpn from network preference.

                               

                              displayMessage does work for me, but I am hoping more advanced user action like click a link to launch the app etc can be provided.

                               

                              thanks!!

                              -Adam

                      • Re: Can a Network Extension display any UI or launch it's container app?
                        sdfijasdlfkjasd Level 1 Level 1 (0 points)

                        Excellent, I had no idea this was in iOS 10. It should work as we're simply telling the user to open our app (to troubleshoot) if the connection was not completed.