<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LinkRouter</title><link>https://deekue.github.io/linkrouter/</link><description>Recent content on LinkRouter</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 21 Sep 2026 13:10:31 +0000</lastBuildDate><atom:link href="https://deekue.github.io/linkrouter/index.xml" rel="self" type="application/rss+xml"/><item><title>URL Flow Chart</title><link>https://deekue.github.io/linkrouter/flow_chart/</link><pubDate>Mon, 21 Sep 2026 13:10:31 +0000</pubDate><guid>https://deekue.github.io/linkrouter/flow_chart/</guid><description>&lt;h1 id="url-flow"&gt;&#10; URL Flow&#10; &lt;a class="heading-link" href="#url-flow"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h1&gt;&#10;&lt;p&gt;An incoming link arrives through one of two intents and always travels the same pipeline before any browser is launched. Non-web schemes (e.g. &lt;code&gt;mailto:&lt;/code&gt;) are dropped, and once a URL reaches a browser it is marked so it is never re-processed (loop guard). The shortener-resolution step is opt-in and off by default (zero network):&lt;/p&gt;&#10;&lt;div class="mermaid"&gt;&#10;graph TD&#10; A["Incoming link&lt;br/&gt;ACTION_VIEW — default browser / link tap&lt;br/&gt;or ACTION_SEND — Share sheet"] --&gt; B["Extract and normalize URL&lt;br/&gt;(RuleEngine.normalize)"]&#10; B --&gt; C{"Web URL?&lt;br/&gt;(http / https)"}&#10; C --&gt;|"no (e.g. mailto:)"| O["Ignore — finish"]&#10; C --&gt;|"yes"| D{"Already handled?&lt;br/&gt;(loop guard)"}&#10; D --&gt;|"yes"| O&#10; D --&gt;|"no"| E["Load enabled rules,&lt;br/&gt;formats, filters, rewrites"]&#10; E --&gt; E3["Canonicalize AMP cache URLs&lt;br/&gt;(amp.to / ampproject.org → origin)"]&#10; E3 --&gt; F{"Enabled shortener host?&lt;br/&gt;(opt-in, off by default)"}&#10; F --&gt;|"no"| E2&#10; F --&gt;|"yes"| G["Resolve shortener to final URL&lt;br/&gt;(pure-JVM; ephemeral WebView fallback)"]&#10; G --&gt; E2["Unwrap redirect wrappers&lt;br/&gt;(user formats, e.g. google.com/url)"]&#10; E2 --&gt; F2{"Nested shortener host?&lt;br/&gt;(bounded depth)"}&#10; F2 --&gt;|"no"| H&#10; F2 --&gt;|"yes"| G&#10; H["Match rules&lt;br/&gt;(specificity first, list-order tie-break)"]&#10; H --&gt; I{"Rule matched?"}&#10; I --&gt;|"no"| J["Fallback&lt;br/&gt;(chooser / OS default / block / ask-and-remember / specific browser)"]&#10; J --&gt; N["finish"]&#10; I --&gt;|"yes"| K["Host rewrite&lt;br/&gt;(first enabled rewrite rule)"]&#10; K --&gt; L["Strip tracker query params&lt;br/&gt;(final launched URL only)"]&#10; L --&gt; M["Launch in target browser&lt;br/&gt;(private / normal / in-app WebView / Stop)"]&#10; M --&gt; N&#10;&#10;&lt;/div&gt;</description></item><item><title>Screenshots</title><link>https://deekue.github.io/linkrouter/screenshots/</link><pubDate>Mon, 21 Sep 2026 00:00:00 +0000</pubDate><guid>https://deekue.github.io/linkrouter/screenshots/</guid><description>&lt;p&gt;A look at the main screens of LinkRouter:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="#rules" &gt;Rules&lt;/a&gt; - route certain sites to certain browsers&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="#redirect-formats" &gt;Redirect formats&lt;/a&gt; - extract the real destination from tracking redirectors&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="#query-parameter-filters" &gt;Query parameter filters&lt;/a&gt; - strip off tracking query parameters&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="#shortener-hosts" &gt;Shortener hosts&lt;/a&gt; - resolve shortened URLs to their final destination before routing&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="#settings" &gt;Settings&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="rules"&gt;&#10; Rules&#10; &lt;a class="heading-link" href="#rules"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;img src="https://deekue.github.io/linkrouter/screenshot-rules-example.png" alt="Rules" style="border: 2px solid #ccc;" /&gt;&#10;&lt;h2 id="redirect-formats"&gt;&#10; Redirect formats&#10; &lt;a class="heading-link" href="#redirect-formats"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;img src="https://deekue.github.io/linkrouter/screenshot-redirectFormats.jpg" alt="Redirect formats" style="border: 2px solid #ccc;" /&gt;&#10;&lt;h2 id="query-parameter-filters"&gt;&#10; Query parameter filters&#10; &lt;a class="heading-link" href="#query-parameter-filters"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;img src="https://deekue.github.io/linkrouter/screenshot-paramQueryFilters.jpg" alt="Query parameter filters" style="border: 2px solid #ccc;" /&gt;&#10;&lt;h2 id="shortener-hosts"&gt;&#10; Shortener hosts&#10; &lt;a class="heading-link" href="#shortener-hosts"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;img src="https://deekue.github.io/linkrouter/screenshot-shortenerHosts.jpg" alt="Shortener hosts" style="border: 2px solid #ccc;" /&gt;&#10;&lt;h2 id="settings"&gt;&#10; Settings&#10; &lt;a class="heading-link" href="#settings"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;img src="https://deekue.github.io/linkrouter/screenshot-settings.png" alt="Settings" style="border: 2px solid #ccc;" /&gt;</description></item><item><title>Feature Test Links</title><link>https://deekue.github.io/linkrouter/tests/</link><pubDate>Thu, 10 Sep 2026 00:00:00 +0000</pubDate><guid>https://deekue.github.io/linkrouter/tests/</guid><description>&lt;h1 id="feature-test-links"&gt;&#10; Feature Test Links&#10; &lt;a class="heading-link" href="#feature-test-links"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h1&gt;&#10;&lt;p&gt;Every row below is rendered directly from&#10;&lt;a href="app/linkrouter-rules-examples.json" &gt;&lt;code&gt;app/linkrouter-rules-examples.json&lt;/code&gt;&lt;/a&gt; — the&#10;same fixtures the unit-test suite consumes — so the page is a 1:1 map of what&#10;the router should do: &lt;strong&gt;Input&lt;/strong&gt; (what you open) → &lt;strong&gt;Expected Output&lt;/strong&gt; (what the&#10;target browser should show).&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt; — enable the relevant feature before testing it:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;em&gt;Shortener hosts&lt;/em&gt; and &lt;em&gt;Host rewrites&lt;/em&gt; ship &lt;strong&gt;disabled&lt;/strong&gt; (opt-in) — flip the&#10;specific host ON in Settings first.&lt;/li&gt;&#10;&lt;li&gt;&lt;em&gt;Rules&lt;/em&gt; and &lt;em&gt;Redirect formats&lt;/em&gt; must exist (add them, or keep) in Settings.&lt;/li&gt;&#10;&lt;li&gt;&lt;em&gt;Query-param filters&lt;/em&gt; ship &lt;strong&gt;enabled&lt;/strong&gt; by default.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;See &lt;a href="#how-to-test" &gt;How to test&lt;/a&gt; for a reliable workflow.&lt;/p&gt;</description></item><item><title>LinkRouter Privacy Policy</title><link>https://deekue.github.io/linkrouter/repo/privacy/</link><pubDate>Wed, 09 Sep 2026 13:10:31 +0000</pubDate><guid>https://deekue.github.io/linkrouter/repo/privacy/</guid><description>&lt;h1 id="linkrouter-privacy-policy"&gt;&#10; LinkRouter Privacy Policy&#10; &lt;a class="heading-link" href="#linkrouter-privacy-policy"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h1&gt;&#10;&lt;p&gt;&lt;strong&gt;App:&lt;/strong&gt; LinkRouter (&lt;code&gt;net.chaosengine.linkrouter&lt;/code&gt;)&#10;&lt;strong&gt;Last updated:&lt;/strong&gt; 2026-09-08&lt;/p&gt;&#10;&lt;p&gt;LinkRouter is a local, rule-based URL router for Android. It contains &lt;strong&gt;no&#10;accounts, no analytics, no ads, no crash reporting, and no third-party&#10;SDKs.&lt;/strong&gt; This page explains what data is processed and where it lives.&lt;/p&gt;&#10;&lt;h2 id="what-data-linkrouter-processes"&gt;&#10; What data LinkRouter processes&#10; &lt;a class="heading-link" href="#what-data-linkrouter-processes"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;URLs you route.&lt;/strong&gt; When a link is delivered to LinkRouter (e.g. because&#10;you&amp;rsquo;ve set it as your default browser), the URL is read, matched against&#10;your rules, and forwarded to your chosen browser. It is &lt;strong&gt;processed&#10;locally, in memory, in the foreground&lt;/strong&gt;, only in response to your tap, and&#10;is &lt;strong&gt;not persisted&lt;/strong&gt; as browsing history.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Your rules and settings.&lt;/strong&gt; Your routing rules, fallback settings,&#10;shortener-host toggles, redirect formats, and tracking-param filters are&#10;stored &lt;strong&gt;locally in app-private storage&lt;/strong&gt; (Room/SQLite). They never leave&#10;your device.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Opt-in: shortener &amp;ldquo;web resolution.&amp;rdquo;&lt;/strong&gt; Only &lt;strong&gt;if you explicitly enable&lt;/strong&gt; a&#10;shortener host (e.g. t.co, bit.ly), LinkRouter makes a network fetch to&#10;follow that shortener&amp;rsquo;s redirect and learn the final URL. This feature is&#10;&lt;strong&gt;off by default&lt;/strong&gt; — a default install never makes any network calls.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="what-linkrouter-does-not-collect"&gt;&#10; What LinkRouter does NOT collect&#10; &lt;a class="heading-link" href="#what-linkrouter-does-not-collect"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;No accounts or sign-in.&lt;/li&gt;&#10;&lt;li&gt;No analytics, ads, telemetry, or crash reporting.&lt;/li&gt;&#10;&lt;li&gt;No third-party SDKs of any kind.&lt;/li&gt;&#10;&lt;li&gt;No collection or sale/sharing of data with any party.&lt;/li&gt;&#10;&lt;li&gt;No persisted browsing history or URL log.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="permissions"&gt;&#10; Permissions&#10; &lt;a class="heading-link" href="#permissions"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;INTERNET&lt;/code&gt;&lt;/strong&gt; (a normal, install-granted permission — not a runtime&#10;permission). Used &lt;strong&gt;only&lt;/strong&gt; for the opt-in shortener web-resolution feature&#10;described above. Disabled by default.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;System &amp;ldquo;default apps / handle links&amp;rdquo;&lt;/strong&gt; — this is a setting &lt;strong&gt;you&lt;/strong&gt; choose&#10;in the Android system settings (set LinkRouter as default browser or link&#10;handler). LinkRouter does not request or modify it by itself.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="data-retention--deletion"&gt;&#10; Data retention &amp;amp; deletion&#10; &lt;a class="heading-link" href="#data-retention--deletion"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;p&gt;Everything LinkRouter stores lives &lt;strong&gt;on your device, in app-private&#10;storage&lt;/strong&gt;. You can delete all of it at any time by:&lt;/p&gt;</description></item><item><title/><link>https://deekue.github.io/linkrouter/repo/agents/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deekue.github.io/linkrouter/repo/agents/</guid><description>&lt;h1 id="agent-directives--constraints"&gt;&#10; Agent Directives &amp;amp; Constraints&#10; &lt;a class="heading-link" href="#agent-directives--constraints"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h1&gt;&#10;&lt;h2 id="scope"&gt;&#10; Scope&#10; &lt;a class="heading-link" href="#scope"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Do NOT run destructive commands: &lt;code&gt;git reset --hard&lt;/code&gt;, &lt;code&gt;git push --force&lt;/code&gt;, &lt;code&gt;git clean -fd&lt;/code&gt;, &lt;code&gt;git checkout -- .&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Do NOT commit directly to &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt;. Always start new work with a checkout of a new branch in a worktree: &lt;code&gt;git worktree add -b &amp;lt;branchname&amp;gt; $(pwd)/../$(basename $(pwd))-worktrees/&amp;lt;branchname&amp;gt;&lt;/code&gt;, where &lt;code&gt;&amp;lt;branchname&amp;gt;&lt;/code&gt; is &lt;code&gt;opencode/&amp;lt;type&amp;gt;/&amp;lt;short-desc&amp;gt;&lt;/code&gt; (type is one of &lt;code&gt;feature&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;chore&lt;/code&gt;), e.g. &lt;code&gt;opencode/fix/login-crash&lt;/code&gt;.&#10;&lt;ul&gt;&#10;&lt;li&gt;When the work is complete, push the branch and create a PR with &lt;code&gt;gh&lt;/code&gt; targeting the base branch: &lt;code&gt;gh pr create --base main&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;After the PR is merged, remove the worktree: &lt;code&gt;git worktree remove $(pwd)/../$(basename $(pwd))-worktrees/&amp;lt;branchname&amp;gt;&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Never modify files inside &lt;code&gt;.git/&lt;/code&gt;, or any file ending in &lt;code&gt;.env*&lt;/code&gt;, &lt;code&gt;*.jks&lt;/code&gt;, or &lt;code&gt;.pem&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Edits can be made to files inside &lt;code&gt;.github/&lt;/code&gt; but do NOT commit them.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="verification"&gt;&#10; Verification&#10; &lt;a class="heading-link" href="#verification"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Before completing a task, run tests locally via &lt;code&gt;scripts/build-debug.sh&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Stage only the specific files modified for the requested feature.&lt;/li&gt;&#10;&lt;/ul&gt;</description></item><item><title/><link>https://deekue.github.io/linkrouter/repo/design/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deekue.github.io/linkrouter/repo/design/</guid><description>&lt;h1 id="linkrouter--build-specification"&gt;&#10; LinkRouter — Build Specification&#10; &lt;a class="heading-link" href="#linkrouter--build-specification"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;Self-contained design + build plan for a pure Android &lt;strong&gt;dispatcher&lt;/strong&gt; app.&#10;It matches each outgoing web URL against user-defined rules and launches the&#10;target browser — optionally in private — then exits immediately. It never&#10;renders pages, makes no network calls, and requires &lt;strong&gt;zero permissions&lt;/strong&gt;&#10;(the sole exception is D9 shortener resolution: opt-in per host, off by&#10;default → zero network).&lt;/p&gt;</description></item><item><title/><link>https://deekue.github.io/linkrouter/repo/readme/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deekue.github.io/linkrouter/repo/readme/</guid><description>&lt;h1 id="linkrouter-netchaosenginelinkrouter"&gt;&#10; LinkRouter (&lt;code&gt;net.chaosengine.linkrouter&lt;/code&gt;)&#10; &lt;a class="heading-link" href="#linkrouter-netchaosenginelinkrouter"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h1&gt;&#10;&lt;p&gt;A privacy-focused, rule-based URL router for Android: it intercepts &lt;code&gt;http&lt;/code&gt;/&lt;code&gt;https&lt;/code&gt; links (as the system default browser) and, per your user-defined rules, strips tracking/query params, rewrites URLs, and forwards them to a user-chosen browser — including private-window launchers for Chrome/Firefox. It is a &lt;strong&gt;router/dispatcher, not a browser&lt;/strong&gt;: it never renders pages itself.&lt;/p&gt;&#10;&lt;h2 id="features"&gt;&#10; Features&#10; &lt;a class="heading-link" href="#features"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Rule engine&lt;/strong&gt;: ordered rules matching exact host, &lt;code&gt;*.subdomain&lt;/code&gt;, path prefix, or full regex; list order is priority, with specificity scoring as tie-breaking.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Redirect formats&lt;/strong&gt;: pattern-based extraction from redirect-style URLs via pure-JVM string processing (no network).&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Shortener-host handling&lt;/strong&gt;: opt-in per-host resolution of t.co / bit.ly / is.gd-style redirects (pure-JVM redirect following with a WebView interstitial fallback), re-running the rule engine on the final URL. &lt;strong&gt;Off by default → zero network.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;URL query-param / tracker cleanup&lt;/strong&gt;: global and domain-scoped stripping of tracking params (&lt;code&gt;utm_*&lt;/code&gt;, &lt;code&gt;gclid&lt;/code&gt;, &lt;code&gt;fbclid&lt;/code&gt;, &lt;code&gt;fbid&lt;/code&gt;, etc.) from the &lt;strong&gt;final launched URL only&lt;/strong&gt;; never affects rule matching.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Browser chooser with private-window support&lt;/strong&gt;: dispatches to installed browsers with per-browser private capability (Firefox real-private verified; Chrome opens normally + honest warning when private is requested but unsupported); built-in in-app WebView target (real private, no cross-app leak); system/OS-default/chooser/ask-and-remember fallback modes.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;JSON import/export&lt;/strong&gt; of rules, settings, shortener hosts, redirect formats, and param filters (local backup/restore, no sync).&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="privacy"&gt;&#10; Privacy&#10; &lt;a class="heading-link" href="#privacy"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Local-only&lt;/strong&gt; rule and settings storage (Room, app-private storage). No URL history is ever persisted.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;No ads, no analytics, no telemetry, no third-party SDKs.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Only the &lt;code&gt;INTERNET&lt;/code&gt; permission&lt;/strong&gt; is declared (a normal, install-granted permission), and it is exercised &lt;strong&gt;only&lt;/strong&gt; if you enable the opt-in &amp;ldquo;shortener web resolution&amp;rdquo; feature for one or more hosts — all built-in shortener hosts ship disabled, so a default install makes zero network calls.&lt;/li&gt;&#10;&lt;li&gt;See &lt;a href="PRIVACY.md" &gt;PRIVACY.md&lt;/a&gt; for the full privacy policy.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="requirements"&gt;&#10; Requirements&#10; &lt;a class="heading-link" href="#requirements"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Android &lt;strong&gt;minSdk 26&lt;/strong&gt; (Android 8.0)&lt;/li&gt;&#10;&lt;li&gt;Gradle: AGP &lt;strong&gt;8.10.1&lt;/strong&gt;, Kotlin &lt;strong&gt;2.0.21&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="build"&gt;&#10; Build&#10; &lt;a class="heading-link" href="#build"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./gradlew :app:assembleDebug &lt;span style="color:#8b949e;font-style:italic"&gt;# debug APK (signed with the automatic debug key)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./gradlew :app:testDebugUnitTest &lt;span style="color:#8b949e;font-style:italic"&gt;# JVM + Robolectric unit tests&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./gradlew :app:bundleRelease &lt;span style="color:#8b949e;font-style:italic"&gt;# Play AAB (unsigned unless you configure release signing, below)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="release-signing"&gt;&#10; Release signing&#10; &lt;a class="heading-link" href="#release-signing"&gt;&#10; &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;&#10; &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;&#10; &lt;/a&gt;&#10;&lt;/h3&gt;&#10;&lt;p&gt;Release signing is entirely &lt;strong&gt;external-secret-driven&lt;/strong&gt; (no keystore path or password ever lives in this repo). Provide all four via &lt;strong&gt;environment variables&lt;/strong&gt; &lt;em&gt;or&lt;/em&gt; &lt;code&gt;gradle.properties&lt;/code&gt; keys (see &lt;code&gt;gradle.properties.example&lt;/code&gt;):&lt;/p&gt;</description></item></channel></rss>