From 8969744783e2851b287e937f71033ce4b6bb4dc3 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 6 Nov 2026 23:01:15 -0700 Subject: A third Android build, fcm (io.coinos.beta, "Coinos Beta"): the wallet in its own WebView, as the webview build, with Firebase Cloud Messaging for push on phones with Google Play Services — no distributor app to install. A user on the TWA APK found launching slow next to Minibits (2026-11-05); measured on a Pixel 9, a WebView paints ~0.7 s sooner than a cold Chrome. This build installs beside the TWA for a side-by-side trial before deciding whether it replaces it. Fcm asks for the token and stores "fcm:" as the push endpoint, which reaches the page down the UnifiedPush road (?up= on the next launch, or written straight into the page's localStorage once it has loaded, since the token arrives after the first load starts); nwcpush (coinosv3-server 0c50417) sends an fcm: endpoint through Firebase. FcmService hands a message's "body" to the same handler UnifiedPush messages use (PushReceiver.onPush: wake the wallet off-screen, notify unless it answered a silent request). Firebase is set up in code (CoinosApp → Fcm.init) from values build.gradle reads out of app/google-services.json (gitignored) — without it the build still builds and falls back to UnifiedPush. The webview and fdroid builds get a stub Fcm (src/nofcm) and carry no Google code; the notification permission is asked when Firebase or a distributor can deliver; CoinosHost.env reports app "fcm" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VMan6Ts5Tktega8VbLg31q --- .../src/main/java/io/coinos/app/PushReceiver.java | 28 ++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'android/app/src/main') diff --git a/android/app/src/main/java/io/coinos/app/PushReceiver.java b/android/app/src/main/java/io/coinos/app/PushReceiver.java index ce3e3f0..b14de53 100644 --- a/android/app/src/main/java/io/coinos/app/PushReceiver.java +++ b/android/app/src/main/java/io/coinos/app/PushReceiver.java @@ -49,14 +49,7 @@ public class PushReceiver extends BroadcastReceiver { case Push.ACTION_MESSAGE: { byte[] bytes = intent.getByteArrayExtra(Push.EXTRA_BYTES_MESSAGE); String body = bytes != null ? new String(bytes) : intent.getStringExtra(Push.EXTRA_MESSAGE); - // On the WebView build the wallet lives in THIS app's storage, so it - // can be woken and told to deal with whatever arrived. On the TWA - // build the wallet is Chrome's and out of reach, so the notification - // is the whole of what we can do. - boolean woke = Wake.start(context, body); - // A payment or a message is news whether or not we handled it; a - // wallet-connect request is not, unless nobody is going to answer it. - if (!woke || !isSilent(body)) notify(context, body); + onPush(context, body); Push.ack(context, intent.getStringExtra(Push.EXTRA_ID)); break; } @@ -65,8 +58,23 @@ public class PushReceiver extends BroadcastReceiver { } } + /** + * A push, however it came (a UnifiedPush distributor, or Firebase in the + * fcm build — FcmService): the same JSON either way. + */ + static void onPush(Context context, String body) { + // On the WebView build the wallet lives in THIS app's storage, so it + // can be woken and told to deal with whatever arrived. On the TWA + // build the wallet is Chrome's and out of reach, so the notification + // is the whole of what we can do. + boolean woke = Wake.start(context, body); + // A payment or a message is news whether or not we handled it; a + // wallet-connect request is not, unless nobody is going to answer it. + if (!woke || !isSilent(body)) notify(context, body); + } + /** Requests the woken wallet answers by itself need no notification. */ - private boolean isSilent(String payload) { + private static boolean isSilent(String payload) { try { JSONObject j = new JSONObject(payload == null ? "{}" : payload); String reason = j.optString("reason", j.optString("type", "")); @@ -79,7 +87,7 @@ public class PushReceiver extends BroadcastReceiver { * describes; anything we don't recognise still gets a notification, because * silence is the one answer that's always wrong here. */ - private void notify(Context c, String payload) { + private static void notify(Context c, String payload) { String title = c.getString(R.string.app_name); String text = c.getString(R.string.push_generic); String deepLink = null; -- cgit v1.2.3