3

When creating a native content blocker from a Safari App Extension, how do I update the static JSON list after the plugin has loaded?

The only way I can see right now is to deploy a whole new version of the app which wouldn't update automatically for users.

Is it possible to update the JSON blocklist file for a content blocker from another URL without having to update the Safari App Extension through the Apple store?

Kevin Ghadyani
  • 6,829
  • 6
  • 44
  • 62

1 Answers1

1

YES its possible you can update the JSON blocklist

Step 1:

Create new JSON for content blocking rules

Step 2 : Save the JSON file in Shared Container

fileprivate func saveRuleFile(ruleList:[Rule]) {
        let encoder = JSONEncoder()
        if let encoded = try? encoder.encode(ruleList) {

            let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.xxx.xxxx.xxx")
            print("sharedContainerURL = \(String(describing: sharedContainerURL))")

            if let json = String(data: encoded, encoding: .utf8) {
                print(json)
            }

            if let destinationURL = sharedContainerURL?.appendingPathComponent("Rules.json") {
                do {
                    try  encoded.write(to: destinationURL)
                } catch {
                    print (error)
                }
            }
        }
    }

Step 3: Call this method to ask the Content blocker to reload the rules

SFContentBlockerManager.reloadContentBlocker(withIdentifier:"com.xxxx.xxx.xxxx", completionHandler: nil)

Step: 4 Read the JSON rules file from Shared container and pass the rules to content blocker extension

func beginRequest(with context: NSExtensionContext) {
        let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.xxx.xxx.xxx")
        let sourceURL = sharedContainerURL?.appendingPathComponent("Rules.json")
        let ruleAttachment = NSItemProvider(contentsOf: sourceURL)
        let item = NSExtensionItem()
        item.attachments = ([ruleAttachment] as! [NSItemProvider])
        context.completeRequest(returningItems: [item], completionHandler: nil)
    }
Imran
  • 3,045
  • 2
  • 22
  • 33
  • Does beginRequest get called on every request? or only during Safari bootstrap? I am trying to fetch from a server wether a domain is allowed or not and then block or allow the request. I know it's slow, but I'm just testing something out right now. – Tony Apr 29 '20 at 21:01
  • 1
    No, beginsRequest did not get called with every request, It will only get called when you will call FContentBlockerManager.reloadContentBlocker(withIdentifier:"com.xxxx.xxx.xxxx", completionHandler: nil) – Imran May 04 '20 at 04:55
  • Followed the code, for me it works with blocking but not when unblocking. JFYI, I remove the trigger/action block from json for deactivating filter. – Daniyal dehleh Mar 13 '22 at 17:32