Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if user has enabled application's Safari content blocker extension

I'm working on a Safari Content Blocking extension. I intend to show setup instructions if the extension is disabled and to show settings if it is conversely enabled. How can I determine if the extension is enabled by the user?

I've seen this method to detect if a custom keyboard is activated but there's no key on NSUserDefaults that relates to Safari Content Blockers.

like image 510
Ryan Brodie Avatar asked Oct 31 '15 14:10

Ryan Brodie


People also ask

How do I enable content blocker on Safari?

To change these preferences, choose Safari > Preferences, then click Websites. The settings you can customize (such as Reader and Content Blockers) are listed on the left. To apply a setting to a website on the right, first select the setting, then choose the option you want from the pop-menu next to the website.

What does enable content blockers mean on Safari?

Content blockers are app extensions that you build using Xcode. They indicate to Safari a set of rules to use to block content in the browser window. Blocking behaviors include hiding elements, blocking loads, and stripping cookies from Safari requests.

What does URL blocked by content blocker mean?

So the Content blocking is a feature of the browsers that allows you to block or hide all or some content in a webpage or site that you do not want to see, including images, ads, pop-ups, comments and plug-ins.


2 Answers

As of iOS 10, there is a new method in SFContentBlockerManager to support this:

getStateOfContentBlocker(withIdentifier:completionHandler:)

And you call it like this (Swift 3):

SFContentBlockerManager.getStateOfContentBlocker(withIdentifier: "your.identifier.here", completionHandler: { (state, error) in
    if let error = error {
        // TODO: handle the error
    }
    if let state = state {
        let contentBlockerIsEnabled = state.isEnabled
        // TODO: do something with this value
    }
})
like image 106
breakingobstacles Avatar answered Sep 28 '22 05:09

breakingobstacles


You could utilize a SFSafariViewController to load a custom website. This website checks whether it is able to show something that your content blocker should block. Then redirect to the respective custom url (success/failure) that your app previously registered for. You could even use a hidden Safari View Controller without animation to avoid any distraction from the user's perspective (as shown here). (I guess this technique is used by former content blocker Peace)

Steps

App

  1. Register custom URLs for success/failure
  2. Register for notification callback using the NotificationCenter (e.g. contentBlockerEnabled)
  3. Use SFSafariViewController to show a custom website and include the following rule in blockerList.json:

    {
        "action": {
            "type": "css-display-none",
            "selector": ".blocked_selector"
        },
        "trigger": {
            "url-filter": ".*"
        }
    }
    

Website

  1. Check for blocked content:

    if($('.blocked_selector').css('display') == "none") {
       // Content blocker enabled
    }
    
  2. Redirect to custom URL (success/failure)

App

  1. Post notification from application:openURL:options: (success/failure based on called url)

Update 18/01

Following on from Tilo's hypothesis, I built the proposed solution. I wrote about what I learnt on Medium and you can grab the source files from GitHub.

TL;DR It works but only temperamentally due to the latency incurred of the content blocking rules database to update. A potential workaround is redirecting the test page to create an artificial delay.

like image 35
tilo Avatar answered Sep 28 '22 03:09

tilo