aboutsummaryrefslogtreecommitdiffstats
path: root/android/app/src/webview/java/io/coinos
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-11-06 23:01:15 -0700
committerAdam Soltys <[email protected]>2026-11-06 23:01:15 -0700
commit8969744783e2851b287e937f71033ce4b6bb4dc3 (patch)
tree682652e80d9119da9106a2e5ce2d11eeadb08d6f /android/app/src/webview/java/io/coinos
parent1fe10057f301b09bbad0cfccdfecac9826733048 (diff)
downloadcoinosv3-8969744783e2851b287e937f71033ce4b6bb4dc3.tar.gz
coinosv3-8969744783e2851b287e937f71033ce4b6bb4dc3.zip
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:<token>" 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"
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VMan6Ts5Tktega8VbLg31q
Diffstat (limited to 'android/app/src/webview/java/io/coinos')
-rw-r--r--android/app/src/webview/java/io/coinos/app/MainActivity.java32
1 files changed, 27 insertions, 5 deletions
diff --git a/android/app/src/webview/java/io/coinos/app/MainActivity.java b/android/app/src/webview/java/io/coinos/app/MainActivity.java
index d88a969..b26d6c5 100644
--- a/android/app/src/webview/java/io/coinos/app/MainActivity.java
+++ b/android/app/src/webview/java/io/coinos/app/MainActivity.java
@@ -77,6 +77,11 @@ public class MainActivity extends Activity {
}
@Override
+ public void onPageFinished(WebView v, String url) {
+ endpointToPage();
+ }
+
+ @Override
public boolean shouldOverrideUrlLoading(WebView v, WebResourceRequest r) {
Uri u = r.getUrl();
String host = u.getHost();
@@ -118,9 +123,11 @@ public class MainActivity extends Activity {
}
});
- // Notifications only ever come from UnifiedPush, so the permission is
- // asked for only when a distributor is installed to deliver them.
- if (Build.VERSION.SDK_INT >= 33 && !Push.distributors(this).isEmpty()
+ // Notifications come from Firebase (the fcm build, with Play Services)
+ // or a UnifiedPush distributor, so the permission is asked for only when
+ // one of them is there to deliver them.
+ boolean fcm = Fcm.available(this);
+ if (Build.VERSION.SDK_INT >= 33 && (fcm || !Push.distributors(this).isEmpty())
&& checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
try { requestPermissions(new String[] { Manifest.permission.POST_NOTIFICATIONS }, REQ_PERMS); } catch (Exception ignored) {}
}
@@ -128,10 +135,25 @@ public class MainActivity extends Activity {
// can deliver a push — the advice it gives is useless otherwise ("use
// Firefox" makes no sense inside a WebView that IS the app).
web.addJavascriptInterface(new Host(), "CoinosHost");
- Push.register(this);
+ // Firebase when it can; otherwise a distributor. A Firebase token
+ // arrives after the page has started loading, so it goes straight into
+ // the page rather than waiting for the next launch's ?up=.
+ if (!Fcm.register(this, () -> runOnUiThread(this::endpointToPage))) Push.register(this);
web.loadUrl(urlFor(getIntent()));
}
+ /**
+ * The push endpoint, put where the page keeps it (messages.js and nwc.js
+ * read 'coinos-unifiedpush') — once the page is ours to write into.
+ */
+ private void endpointToPage() {
+ String endpoint = Push.endpoint(this);
+ String url = web == null ? null : web.getUrl();
+ if (endpoint == null || Push.endpointDelivered(this) || url == null || !url.startsWith(BASE)) return;
+ web.evaluateJavascript("try{localStorage.setItem('coinos-unifiedpush'," + org.json.JSONObject.quote(endpoint) + ")}catch(e){}", null);
+ Push.markEndpointDelivered(this);
+ }
+
/** What the page is allowed to ask about its surroundings. */
private class Host {
@android.webkit.JavascriptInterface
@@ -139,7 +161,7 @@ public class MainActivity extends Activity {
String dist = Push.distributor(MainActivity.this);
List<String> all = Push.distributors(MainActivity.this);
String endpoint = Push.endpoint(MainActivity.this);
- return "{\"app\":\"graphene\",\"distributors\":" + all.size()
+ return "{\"app\":\"" + (Fcm.available(MainActivity.this) ? "fcm" : "graphene") + "\",\"distributors\":" + all.size()
+ ",\"distributor\":" + (dist == null ? "null" : "\"" + dist + "\"")
+ ",\"endpoint\":" + (endpoint != null) + "}";
}