Skip to content

feat(content-blocker): wire WKContentRuleList via adblock-rust on Apple#348

Open
theoden8 wants to merge 5 commits into
masterfrom
claude/fix-ios-content-blocker-F3IBQ
Open

feat(content-blocker): wire WKContentRuleList via adblock-rust on Apple#348
theoden8 wants to merge 5 commits into
masterfrom
claude/fix-ios-content-blocker-F3IBQ

Conversation

@theoden8

Copy link
Copy Markdown
Owner

iOS/macOS WebViews were relying solely on the JS-bridge interceptor (Bloom + per-host roundtrip) for sub-resource blocking, which is slow under load. The Rust crate already exports the rules in Apple's JSON shape; this commit wires that output through
InAppWebViewSettings.contentBlockers so WebKit blocks natively before the JS layer sees the request. Stats still come from the JS bridge — WebKit fires no callback when a content rule matches.

Built once per ruleset (compute() isolate), cached on the service by content hash, paired with the fork branch that hash-keys WKContentRuleListStore identifiers so warm starts skip compilation.

https://claude.ai/code/session_01CKn59eXGzJiqj38EfT53ke

@theoden8 theoden8 force-pushed the claude/fix-ios-content-blocker-F3IBQ branch from 5ca22dd to 4c6b4e2 Compare May 16, 2026 11:00
claude added 5 commits May 16, 2026 13:13
iOS/macOS WebViews were relying solely on the JS-bridge interceptor
(Bloom + per-host roundtrip) for sub-resource blocking, which is
slow under load. The Rust crate already exports the rules in Apple's
JSON shape; this commit wires that output through
InAppWebViewSettings.contentBlockers so WebKit blocks natively
before the JS layer sees the request. Stats still come from the JS
bridge — WebKit fires no callback when a content rule matches.

Built once per ruleset (compute() isolate), cached on the service
by content hash, paired with the fork branch that hash-keys
WKContentRuleListStore identifiers so warm starts skip compilation.

https://claude.ai/code/session_01CKn59eXGzJiqj38EfT53ke
…purge

Calling the adblock-rust FFI through compute() crosses an isolate
boundary with a process-loaded DynamicLibrary, which is fragile and
unnecessary — the conversion is single-digit milliseconds for a
30K-rule list, same pattern _maybeRebuildRustEngine uses. Run it on
the caller's isolate.

Add a CB-012 scenario for the stale-identifier purge that the fork
companion commit added: WKContentRuleListStore would otherwise
accumulate one bytecode entry per ruleset edit, indefinitely.

https://claude.ai/code/session_01CKn59eXGzJiqj38EfT53ke
Surface what's happening to the WKContentRuleList payload during a
service rebuild and at every WebView attach so the in-app log
viewer can confirm the path is wired up: rebuild entry with list /
byte / hash detail, skip reasons (non-Apple platform, no cache,
unchanged hash), payload-ready summary with rule count + duration,
and per-webview attach messages tagged with siteId and identifier
short-hash.

https://claude.ai/code/session_01CKn59eXGzJiqj38EfT53ke
The WKContentRuleList build path called inapp.ContentBlocker.fromMap
on every rule emitted by adblock-rust. A single rule that tripped
fromMap (e.g. a non-null bool field arriving as null) used to abort
the entire payload build, leaving WebViews with no content rules.

Wrap each per-rule construction in try/catch, count the casualties,
and feed the skip total into the rebuild log so a stale fork pin
(missing the fromMap null-default fix) surfaces clearly instead of
"WKContentRuleList JSON export returned null" hiding the cause.

https://claude.ai/code/session_01CKn59eXGzJiqj38EfT53ke
"payload ready: 0 rules ($skipped skipped...)" was emitted at info
level, easy to miss when other rebuild paths fire info around it.
When the wrap rejects 100% (or >50%) of rules, log at error/warning
and mention the most likely cause — a stale fork pin missing the
ContentBlockerTrigger.fromMap null-default fix.

https://claude.ai/code/session_01CKn59eXGzJiqj38EfT53ke
@theoden8 theoden8 force-pushed the claude/fix-ios-content-blocker-F3IBQ branch from 4c6b4e2 to 836a139 Compare May 16, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants