How to pause Safari App Extension on toolbarItemClicked()

60 views Asked by At

I have a safari app extension that I would like to achieve the following with then the toolbar item is clicked:

  • Toggle the extension state between paused and enabled
  • When paused, no scripts would be injected, and no content blocked

As of yet, I have been struggling to find helpful documentation online relating to this issue. The toolbar click successfully changes the icon but doesn't pause the content blocker.

My current strategy:

  1. Set the default app state to true(in appgroup user defaults) in the app delegate.
  2. When the toolbar item is clicked, switch the icon and toggle the app group, and the user defaults to the tiny blocker state.
  3. Reload content blocker
  4. When it reloads, it should read the tiny blocker state from shared app group user defaults, then load an empty JSON file or the populated blocker list.

The state is successfully updated. However, nothing is printed to the console from the content blocker handler, and it does not successfully switch and stop blocking ads.

Here is the SafariExtensionHandler.swift file.

//
//  SafariExtensionHandler.swift
//  TinyBlocker Extension
//
//  Created by Thomas Wissemann on 1/18/24.
//

import SafariServices
import os.log
import SafariServices.SFContentBlockerManager

class SafariExtensionHandler: SFSafariExtensionHandler {
    



    override func beginRequest(with context: NSExtensionContext) {
        let request = context.inputItems.first as? NSExtensionItem
        
        let profile: UUID?
        if #available(iOS 17.0, macOS 14.0, *) {
            profile = request?.userInfo?[SFExtensionProfileKey] as? UUID
        } else {
            profile = request?.userInfo?["profile"] as? UUID
        }
        
        os_log(.default, "The extension received a request for profile: %@", profile?.uuidString ?? "none")
    }
    
    override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) {
        page.getPropertiesWithCompletionHandler { properties in
            os_log(.default, "The extension received a message (%@) from a script injected into (%@) with userInfo (%@)", messageName, String(describing: properties?.url), userInfo ?? [:])
        }
    }

    override func toolbarItemClicked(in window: SFSafariWindow) {
        // Toggle the state
        let appGroupIdentifier = "group.Personal_Team_4H8FFXXPM4.sharedgroup"
        let sharedUserDefaults = UserDefaults(suiteName: appGroupIdentifier)

        let currentState = sharedUserDefaults?.bool(forKey: "tinyBlockerState") ?? true
        
        sharedUserDefaults?.set(!currentState, forKey: "tinyBlockerState")
        
        os_log("toolbaritemclicked changed state to %d", currentState)
        // Update toolbar item
        let imageName = currentState ? "ToolbarItemIcon.pdf" : "disabled.pdf"
        window.getToolbarItem { (toolbarItem) in
            toolbarItem?.setImage(NSImage(named: NSImage.Name(imageName)))
        }
        
        self.updateContentBlocker()
        os_log(.default, "The extension's toolbar item was clicked")
    }

    override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping ((Bool, String) -> Void)) {
        validationHandler(true, "")
    }

    override func popoverViewController() -> SFSafariExtensionViewController {
        return SafariExtensionViewController.shared
    }
    
    func toggleScripts() {
        
    }

    func updateContentBlocker() {
        SFContentBlockerManager.reloadContentBlocker(withIdentifier: "WiseDev.TinyBlocker.Blocker") { error in
            if let error = error {
                os_log("Error reloading content blocker: %@", error.localizedDescription)
            } else {
                os_log(.default, "Content blocker reloaded successfully")
            }
        }
        os_log(.default, "Reload message received")
    }
}

Here is the content blocker Request Handler:

import Foundation
import os.log

class ContentBlockerRequestHandler: NSObject, NSExtensionRequestHandling {
    func beginRequest(with context: NSExtensionContext) {
        print("beginRequest executed")
        //should grab from app group live shared userdefaults.
        //let contentBlockingEnabled = true
        // Check the content blocking state
        let appGroupIdentifier = "group.Personal_Team_4H8FFXXPM4.sharedgroup"
        let sharedUserDefaults = UserDefaults(suiteName: appGroupIdentifier)

        let currentState = sharedUserDefaults?.bool(forKey: "tinyBlockerState") ?? true
        
        NSLog("content blocking enabled %d", currentState)
        
        let attachment = NSItemProvider(contentsOf: Bundle.main.url(forResource: "blockerList", withExtension: "json"))!
        let attachment_disabled = NSItemProvider(contentsOf: Bundle.main.url(forResource: "blockerListDisabled", withExtension: "json"))!
    
        let item = NSExtensionItem()
        
        if (!currentState) {
            item.attachments = [attachment]
        } else {
            item.attachments = [attachment_disabled]
        }
        context.completeRequest(returningItems: [ item ], completionHandler: nil)
    }
}
0

There are 0 answers