Previously, I added a post about the problem with NEFilterManager configuration. Since then, I explored the SimpleTunnel example project and I changed NEFilterManager setup to my own and it still worked well. Now, I simplified the code to just test that Content Filter is starting, but unfortunately it's displayed as 'Invalid' in System Settings.
Here are the samples of my code, but I still don't understand what I am doing wrong here. I would be very grateful for any help.
Test View
struct ContentFilterView: View {
@ObservedObject var vm = FilterManager.shared
@State private var toggleState = false
var body: some View {
VStack {
Toggle("Filter Status", isOn: $toggleState)
.padding()
.onChange(of: toggleState) { status in
vm.setupFilter(with: status)
}
}
.onAppear {
vm.loadFilterConfiguration { success in
if success {
print("loadFilterConfiguration is successful")
toggleState = vm.isEnabled ?? false
print("NEFilterManager config: \(String(describing: NEFilterManager.shared().providerConfiguration?.organization))")
} else {
print("loadFilterConfiguration failed")
toggleState = false
}
}
}
}
}
FilterManager
class FilterManager: ObservableObject {
@Published
private(set) var isEnabled: Bool? = nil
// MARK: - Properties
private let manager = NEFilterManager.shared()
private var subs = Set<AnyCancellable>()
static let shared = FilterManager()
private init() {
manager.isEnabledPublisher()
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] isEnabled in
self?.setIsEnabled(isEnabled)
})
.store(in: &subs)
}
public func setupFilter(with status: Bool) {
if status && manager.providerConfiguration == nil {
let newConfiguration = NEFilterProviderConfiguration()
newConfiguration.username = "TestUser"
newConfiguration.organization = "Test Inc."
newConfiguration.filterBrowsers = true
newConfiguration.filterSockets = true
manager.providerConfiguration = newConfiguration
print("manager configuration saved successfully: \(String(describing: manager.providerConfiguration?.organization))")
}
manager.isEnabled = status
manager.saveToPreferences { [weak self] error in
if let error {
print("Failed to save the filter configuration: \(error.localizedDescription)")
self?.isEnabled = false
return
}
}
}
public func loadFilterConfiguration(withCompletion completion: @escaping (Bool) -> Void) {
manager.loadFromPreferences { error in
if let loadError = error {
print("Failed to load the filter configuration: \(loadError)")
completion(false)
} else {
completion(true)
}
}
}
private func setIsEnabled(_ isEnabled: Bool) {
guard self.isEnabled != isEnabled else { return }
self.isEnabled = isEnabled
print("NEFilter \(isEnabled ? "enabled" : "disabled")")
}
}
extension NEFilterManager {
// MARK: - Publisher enabling
func isEnabledPublisher() -> AnyPublisher<Bool, Never> {
NotificationCenter.default
.publisher(for: NSNotification.Name.NEFilterConfigurationDidChange)
.compactMap { [weak self] notification in
guard let self else { return nil }
return self.isEnabled
}
.eraseToAnyPublisher()
}
}
NEFilterDataProvider
class FilterDataProvider: NEFilterDataProvider {
// MARK: - Properties
/// A record of where in a particular flow the filter is looking.
var flowOffSetMapping = [URL: Int]()
/// The list of flows that should be blocked after fetching new rules.
var blockNeedRules = [String]()
/// The list of flows that should be allowed after fetching new rules.
var allowNeedRules = [String]()
override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict {
Log("Will handle filter flow \(flow)", prefix: "[Filter Data]")
return .drop()
}
}
NEFilterControlProvider is the same as SimpleTunnel example project NEFilterControlProvider implementation.
I also followed suggested steps mentioned in this post but it didn't seem to help.