Hi, Using iOS 17.2 trying to build an ios app with Content Filter Network extension. My problem is that when I build it on a device and go to Settings --> VNP & Device Management the Content Filter with my identifier is showing BUT is shows invalid.
Appname is Privacy Monitor and Extension name is Social Filter Control Here is is my code
`// // PrivacyMonitorApp.swift
import SwiftUI
@main struct PrivacyMonitorApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
} import NetworkExtension
class AppDelegate: UIResponder, UIApplicationDelegate { static private(set) var instance: AppDelegate! = nil func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { configureNetworkFilter() return true }
func configureNetworkFilter() {
let manager = NEFilterManager.shared()
manager.loadFromPreferences { error in
if let error = error {
print("Error loading preferences: \(error.localizedDescription)")
return
}
// Assume configuration is absent or needs update
if manager.providerConfiguration == nil {
let newConfiguration = NEFilterProviderConfiguration()
newConfiguration.filterBrowsers = true
newConfiguration.filterSockets = true
// newConfiguration.vendorConfiguration = ["someKey": "someValue"]
manager.providerConfiguration = newConfiguration
}
manager.saveToPreferences { error in
if let error = error {
print("Error saving preferences: \(error.localizedDescription)")
} else {
print("Filter is configured, prompt user to enable it in Settings.")
}
}
}
}
}
Next the FilterManager.swift
`import NetworkExtension
class FilterManager {
static let shared = FilterManager()
init() {
NEFilterManager.shared().loadFromPreferences { error in
if let error = error {
print("Failed to load filter preferences: \(error.localizedDescription)")
return
}
print("Filter preferences loaded successfully.")
self.setupAndSaveFilterConfiguration()
}
}
private func setupAndSaveFilterConfiguration() {
let filterManager = NEFilterManager.shared()
let configuration = NEFilterProviderConfiguration()
configuration.username = "MyConfiguration"
configuration.organization = "SealdApps"
configuration.filterBrowsers = true
configuration.filterSockets = true
filterManager.providerConfiguration = configuration
filterManager.saveToPreferences { error in
if let error = error {
print("Failed to save filter preferences: \(error.localizedDescription)")
} else {
print("Filter configuration saved successfully. Please enable the filter in Settings.")
}
}
}
}
Next The PrivacyMonitor.entitlements `<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.networking.networkextension</key> <array> <string>content-filter-provider</string> </array> <key>com.apple.security.application-groups</key> <array> <string>group.com.seald-apps.PrivacyMonitor</string> </array> </dict> </plist>
The Network Extension capabilties are on and this is the SocialFilterControl
`import NetworkExtension
class FilterControlProvider: NEFilterControlProvider {
override func startFilter(completionHandler: @escaping (Error?) -> Void) {
// Initialize the filter, setup any necessary resources
print("Filter started.")
completionHandler(nil)
}
override func stopFilter(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Clean up filter resources
print("Filter stopped.")
completionHandler()
}
override func handleNewFlow(_ flow: NEFilterFlow, completionHandler: @escaping (NEFilterControlVerdict) -> Void) {
// Determine if the flow should be dropped or allowed, potentially downloading new rules if required
if let browserFlow = flow as? NEFilterBrowserFlow,
let url = browserFlow.url,
let hostname = browserFlow.url?.host {
print("Handling new browser flow for URL: \(url.absoluteString)")
if shouldBlockDomain(hostname) {
print("Blocking access to \(hostname)")
completionHandler(.drop(withUpdateRules: false)) // No rule update needed immediately
} else {
completionHandler(.allow(withUpdateRules: false))
}
} else {
// Allow other types of flows, or add additional handling for other protocols
completionHandler(.allow(withUpdateRules: false))
}
}
// Example function to determine if a domain should be blocked
private func shouldBlockDomain(_ domain: String) -> Bool {
// Add logic here to check the domain against a list of blocked domains
let blockedDomains = ["google.com", "nu.nl"]
return blockedDomains.contains(where: domain.lowercased().contains)
}
}
And it's info.plist `<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.networkextension.filter-control</string> <key>NSExtensionPrincipalClass</key> <string>$(PRODUCT_MODULE_NAME).FilterControlProvider</string> </dict> </dict> </plist>
and the entitlements file `<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.networking.networkextension</key> <array> <string>content-filter-provider</string> </array> <key>com.apple.security.application-groups</key> <array> <string>group.com.seald-apps.PrivacyMonitor</string> </array> </dict> </plist>
In Xcode using automatically manage signing and both targets have the same Team
Please explain the missing part