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 --- android/app/src/main/AndroidManifest.xml | 69 +++++++++++++++++++++ .../main/java/io/coinos/app/LauncherActivity.java | 27 ++++++++ .../app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2208 bytes .../app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1412 bytes .../app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3084 bytes .../app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5131 bytes .../src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 7923 bytes android/app/src/main/res/values/strings.xml | 11 ++++ 8 files changed, 107 insertions(+) create mode 100644 android/app/src/main/AndroidManifest.xml create mode 100644 android/app/src/main/java/io/coinos/app/LauncherActivity.java create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 android/app/src/main/res/values/strings.xml (limited to 'android/app/src/main') diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c6b7a01 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/java/io/coinos/app/LauncherActivity.java b/android/app/src/main/java/io/coinos/app/LauncherActivity.java new file mode 100644 index 0000000..d0b56bb --- /dev/null +++ b/android/app/src/main/java/io/coinos/app/LauncherActivity.java @@ -0,0 +1,27 @@ +package io.coinos.app; + +import android.net.Uri; + +/** + * Forwards scheme intents into the web app. A lightning:/bitcoin:/nostr:/ + * lnurl: URI arrives as this activity's data; the web app receives it as + * https://v3.coinos.io/?u= and routes it (send form + * for payments, profile for nostr npubs). https links to the site pass + * through untouched, everything else opens the default URL. + */ +public class LauncherActivity + extends com.google.androidbrowserhelper.trusted.LauncherActivity { + + @Override + protected Uri getLaunchingUrl() { + Uri data = getIntent().getData(); + if (data != null) { + String scheme = data.getScheme(); + if (scheme != null && !scheme.equals("https") && !scheme.equals("http")) { + return Uri.parse("https://v3.coinos.io/?u=" + Uri.encode(data.toString())); + } + if ("v3.coinos.io".equals(data.getHost())) return data; + } + return super.getLaunchingUrl(); + } +} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..f80c3c2 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..3d3df9d Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..e5b9241 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..4f9cf1d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..5b08781 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..0663994 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,11 @@ + + + coinos + + + [{ + \"relation\": [\"delegate_permission/common.handle_all_urls\"], + \"target\": { \"namespace\": \"web\", \"site\": \"https://v3.coinos.io\" } + }] + + -- cgit v1.2.3