From 8d27a5d2c59e0f1824753d59a7326b6b76887bf7 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 4 Sep 2026 20:48:27 -0700 Subject: Android wrapper app (android/): a minimal TWA around v3.coinos.io whose whole reason to exist is intent registration — lightning:/bitcoin:/nostr:/lnurl:/lnurlw:/lnurlp: VIEW intents and the same schemes via NFC NDEF dispatch (bolt cards, address stickers; NFC declared required=false), plus verified https links to the site. LauncherActivity forwards a scheme URI into the web app as ?u=; the web app reads it BEFORE features construct — a nostr npub/nprofile rewrites itself onto the existing /npub profile deep link, payment URIs stash and dispatch through handleScanned (the QR path) once a wallet is open, and the param is stripped from the URL either way. assetlinks.json (static/.well-known/, copied by build.js) vouches for the signing cert so the TWA runs URL-bar-less; the built APK is served at /coinos.apk for sideloading. Signing keystore lives in android/ GITIGNORED (keystore.properties beside it) — the assetlinks fingerprint pins it, so losing it means re-shipping assetlinks too. Verified: headless ?u= routing (lightning → Send with invoice filled + URL cleaned; nostr → profile page), APK installed on a real phone via adb, schemes registered (chooser appears where other wallets also claim lightning:) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01MGzU12QrAA4G6BYGzGVdXz --- build.js | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'build.js') diff --git a/build.js b/build.js index e48c4f7..daa986d 100644 --- a/build.js +++ b/build.js @@ -463,6 +463,15 @@ if (import.meta.main) { .replaceAll('{{NWC_WAKE_FALLBACK}}', nwcSw ? '' : SW_WAKE_ONLY); await Bun.write('dist/sw.js', nwcSw ? swBody + '\n' + await buildSwNwc() : swBody); for (const f of STATIC) await Bun.write('dist/' + f, Bun.file('static/' + f)); + // Android app plumbing: assetlinks.json vouches for the TWA wrapper's + // signing cert (URL-bar-less fullscreen), and the wrapper APK itself is + // served for sideloading when a build has been dropped in static/. + if (await Bun.file('static/.well-known/assetlinks.json').exists()) { + await Bun.write('dist/.well-known/assetlinks.json', Bun.file('static/.well-known/assetlinks.json')); + } + if (await Bun.file('static/coinos.apk').exists()) { + await Bun.write('dist/coinos.apk', Bun.file('static/coinos.apk')); + } // default avatars, self-hosted since coinos.io's copies are half-broken const { readdirSync } = await import('node:fs'); for (const f of readdirSync('static/punks')) await Bun.write('dist/punks/' + f, Bun.file('static/punks/' + f)); -- cgit v1.2.3