Android browser router. When a user taps an HTTP/HTTPS link in any app — or shares text containing one to Warden — this app intercepts it via Android intent filters and presents a picker so the user chooses which browser opens it, in what privacy mode, with which intent extras. Built with Expo (React Native).
App display name: Warden (both launcher tile and in-app). App ID: org.vikingware.webwarden — kept as-is so existing installs receive updates.
registerRootComponent.modules/default-browser/ (Kotlin) forintent dispatch, default-browser detection, shared-text intake
expo-linking for URL interceptionnpm run lint)@/* maps to project rootSingle-file app — no router, no navigation library.
index.js — entry; calls registerRootComponent(App)
App.tsx — wraps Home with SafeAreaProvider + StatusBar
Home() does everything: state, URL/share intake, UI
Home mounts, calls Linking.getInitialURL() and our native getInitialSharedText() on cold start.
Linking.addEventListener('url', ...) catches subsequent VIEW intentswhile the app is running.
AppState.addEventListener('change', ...) polls the native shared-textgetter on every foreground transition (catches new SEND intents).
https?:// URL we see populates the URL field andmarks the session as external.
openInBrowser(url, pkg, mode) fires the appropriate Intent. On success in external mode, BackHandler.exitApp()
finishes our task so back-from-browser returns to the originating app.
app.json): - VIEW + http/https + BROWSABLE/DEFAULT/APP_BROWSER — registers
us as a browser candidate
- SEND + text/plain — accepts shared text from any app's share sheet
app.json): package list of every browser wesupport, so Android 11+ package-visibility lets us see them
org.vikingware.webwardenandroid.permission.INTERNET is stripped from release builds via a small config plugin at
plugins/with-release-no-internet.js. Debug builds keep INTERNET so
Metro can reach the app. The plugin writes
android/app/src/release/AndroidManifest.xml with a
tools:node="remove" directive — do NOT set blockedPermissions in
app.json for INTERNET, that would strip it from debug too
| File | Purpose |
|---|---|
App.tsx | Entire app UI + state |
index.js | Registers App with React Native |
constants/browsers.ts | Browser list + private-mode strategy per browser |
constants/theme.ts | Palette, Fonts |
constants/build-info.ts | Auto-generated version + commit at release time |
modules/default-browser/ | Local Kotlin Expo module |
app.json | Expo config, intent filters, Android queries |
scripts/release-apk.sh | Builds signed arm64 APK, tags, uploads to Gitea |
Dark forest theme. All colors from Palette in constants/theme.ts:
#0a1a12 (bg), surfaces in #1a2e1a#f2ead3 (primary), #a8b89a (muted)#6b8e4e / #8fb87a (bright)#b8d49anpm start # Start Metro dev server
npm run android # Build & install on emulator (expo run:android)
npm run lint # ESLint
npx expo prebuild # Regenerate android/ from app.json (required after intent filter changes)
app.json (intent filters, queries, etc.), run npx expo prebuild to regenerate the android/ directoryandroid/ directory is generated — do not manually edit AndroidManifest.xml or Gradle files; changes will be overwritten by prebuildBROWSERS array in constants/browsers.ts AND add the package name to app.json → android.queries.package27.1.12297006 flat is the lean trick. Don't add expo-router, react-navigation,
react-native-reanimated, etc. unless we genuinely need them.
ssh://git@orly/home/git/webwarden-releases.git (bare, owned by git:git). Every dev/prod release pushes an APK here under releases/<tag>/Warden-<tag>.apk + SHA256SUMS.https://git.smesh.lol/webwarden. The README on that page is rendered as HTML; Obtainium's HTML source scans <a href> tags for URLs ending in .apk, picks the last one (alphabetically by URL), and extracts the version from the filename using standard regex patterns..apk links cause Obtainium to pick the alphabetically-last URL, which may not be the actual latest (lexical sort ≠ semver). One link = no ambiguity. Older releases are available in the releases repo archive but are not linked from the README.vX.Y.Z for stable releases (these sort approximately correctly). Dev releases use vX.Y.Z-dev-<commit> tags. The release-dev.sh script auto-updates the README's Releases section to show only the latest build.[0-9]+.[0-9]+.[0-9]+ etc.).release-dev.sh auto-installs to any connected device via adb install -r. Builds for arm64-v8a only.