Two months ago I posed a question to the Stack Overflow community (as well as some others):

How do you determine if a user has enabled your application’s Safari Content Blocker extension?

With no public Cocoa API the best answer (thanks to Tilo) came as a hypothesis. Let’s put it to the test.

blockerList.json

Don’t forget to change the placeholder domain

This solution proposes inspecting the state of a known HTML element’s CSS attributes to determine whether the app’s Content Blocker is allowed. Above is the rule we’ll be using to test this.

testPage.html

For the purpose of this experiment I’m hosting a similar gist on RawGit

This page utilises Apple URL Schemes to communicate the result of the test back to our app (more on that later). Remember to register your custom URL scheme in your project settings under Info ↦ URL Types.

SFSafariViewController fun

Here’s the clever bit: SFSafariViewController (released in iOS 9) lets us present an in-app browser complete with user cookie and session information, as well as the allowed Content Blocker’s effects, carried over from Safari proper. Thanks to Riz’s genius we can hide this view controller for a distraction free user experience.

I’ve put this in the viewDidAppear delegate method of a view controller

So here’s the flow.

Present a hidden SFSafariViewController containing your hosted test page Communicate the result of this test back to your app using JavaScript and Apple’s URL Schemes

Your AppDelegate

Now all that’s left to do is handling those custom URL schemes. Above does just that. I’m simply setting an NSUserDefaults boolean once determined but if you’re smart you’d probably send an NSNotification to gracefully handle the potential change in state.

And?

It works, some of the time.

Firing one immediately after a user has enabled your extension almost always results in a a false positive, seemingly requiring a few seconds for the restrictions database’s changes to propagate. This scenario of unreliable testing is far worse than the current practice of installation instructions shown on first-launch.

How about if you make an interstitial redirect page first?

This, at least in my tests, works every time. Despite being a dirty hack, the first page request—the one that redirects to the actual test page—gives the content blocking system enough time to settle in with its new rules. But like I said, it’s a dirty hack and something I wouldn’t feel comfortable using in production. Another problem point is SFSafariViewController’s lack of local file support (by design it’s run outside the app’s sandbox) meaning internet connectivity is a must.

iOS 10

The real answer is Apple providing an NSUserDefaults key for enabled Content Blockers, just like it does for keyboards, providing a dependable solution. Tangentially, the process of instructing a user to enable your Content Blocker is clunky and cumbersome (it takes five steps, five!). The ability to toggle the app’s Content Blocker from its setting page (reachable through UIApplicationOpenSettingsURLString) would make it a single tap away and would be a welcome revision in the next release of iOS.

For now, check out the source files on GitHub and let me know if you’ve found an alternative method on Twitter.