There’s some good news and some bad news here. The good news is that Xcode 9 introduced radically better support for building Network Extension providers. Specifically:
The bad news is that this makes the advice from old DevForums threads, anything before the release of Xcode 9, less than useful, because back in the day we were using much more primitive tools.
In terms of your specific issue, my advice is:
I’ll discuss each of the last two points in section below
Here’s the expected file system layout for an app hosting Network Extension filter providers:
$ find QNEFilter.app
QNEFilter.app
… _CodeSignature stuff …
QNEFilter.app/embedded.mobileprovision
… Frameworks stuff …
QNEFilter.app/Info.plist
… Frameworks stuff …
… Storyboard stuff …
QNEFilter.app/PlugIns
QNEFilter.app/PlugIns/QNEFilterControlProvider.appex
… _CodeSignature stuff …
QNEFilter.app/PlugIns/QNEFilterControlProvider.appex/embedded.mobileprovision
QNEFilter.app/PlugIns/QNEFilterControlProvider.appex/Info.plist
QNEFilter.app/PlugIns/QNEFilterControlProvider.appex/QNEFilterControlProvider
QNEFilter.app/PlugIns/QNEFilterDataProvider.appex
… _CodeSignature stuff …
QNEFilter.app/PlugIns/QNEFilterDataProvider.appex/embedded.mobileprovision
QNEFilter.app/PlugIns/QNEFilterDataProvider.appex/Info.plist
QNEFilter.app/PlugIns/QNEFilterDataProvider.appex/QNEFilterDataProvider
QNEFilter.app/QNEFilter
Note:
Lines 10 and 15 show that both
.appex
es are within the PlugIns
directoryLines 14, 19 and 20, which are the actual executables; these should include the necessary entitlements, as discussed above
Lines 4, 12 and 17 show that each executable has an embedded provisioning profile; this profile should whitelist the necessary entitlements, as discussed above
With regards the various
Info.plist
files, here’s what I’d expect to see:
Nothing special in the main app’s
Info.plist
:An
NSExtension
entry in the control provider’s Info.plist
:
$ /usr/libexec/PlistBuddy -c "print :NSExtension" QNEFilter.app/PlugIns/QNEFilterControlProvider.appex/Info.plist
Dict {
NSExtensionPointIdentifier = com.apple.networkextension.filter-control
NSExtensionPrincipalClass = QNEFilterControlProvider.ControlProvider
}
Note:
The
NSExtensionPointIdentifier
property must be com.apple.networkextension.filter-control
to indicate that this is a control provider.The
NSExtensionPrincipalClass
combines the Swift module name (QNEFilterControlProvider
) and the class name within that module (ControlProvider
). If you’re using Objective-C, you just include the class name.
An
NSExtension
entry in the data provider’s Info.plist
:
$ /usr/libexec/PlistBuddy -c "print :NSExtension" QNEFilter.app/PlugIns/QNEFilterDataProvider.appex/Info.plist
Dict {
NSExtensionPointIdentifier = com.apple.networkextension.filter-data
NSExtensionPrincipalClass = QNEFilterDataProvider.DataProvider
}
This is very like the control provider except that the extension point identifier is
com.apple.networkextension.filter-data
to indicate that it’s a data provider.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"