From 90bc4d3d54b91cb9845cda4edc53ed148ae00251 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 13 Oct 2026 06:51:13 +0000 Subject: Android 1.14 (code 15): UnifiedPush only where web push can't reach the app. isolabellart asked why Coinos opens a prompt inside ntfy: every launch of the TWA asked whatever UnifiedPush distributor was installed for an endpoint (and asked for notification permission for it), Play Services or not. UnifiedPush is there for phones without Google Play Services (GrapheneOS and the like); with Play Services, web push reaches Chrome — and so the TWA — through Google already, and asking ntfy too only put up its prompt (and would bring every notification twice). The TWA now asks a distributor only when Play Services isn't installed and enabled (Push.playServices; its package named in the manifest's queries for Android 11+), or when it already holds an endpoint — whoever has one has been through the prompt and may be counting on it. The WebView builds (webview, fdroid) are unchanged: web push never reaches a WebView, so UnifiedPush is their only way in either way. 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_01KPw21NEpWeTGu6swVASmBt --- android/app/src/twa/java/io/coinos/app/LauncherActivity.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'android/app/src/twa') diff --git a/android/app/src/twa/java/io/coinos/app/LauncherActivity.java b/android/app/src/twa/java/io/coinos/app/LauncherActivity.java index bf960e2..6e05403 100644 --- a/android/app/src/twa/java/io/coinos/app/LauncherActivity.java +++ b/android/app/src/twa/java/io/coinos/app/LauncherActivity.java @@ -27,12 +27,20 @@ public class LauncherActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + // UnifiedPush is for phones without Google Play Services (GrapheneOS and + // the like, without the sandboxed Play): web push reaches Chrome — and so + // this app — through Google, and with it there it already does. Asking + // ntfy as well there only put up its prompt in an app the user hadn't + // asked for anything (and would have brought every notification twice). + // A registration already made is kept: whoever has one has been through + // the prompt, and may be counting on it. + boolean unifiedPush = !Push.playServices(this) || Push.endpoint(this) != null; // Ask the distributor on every launch: it's idempotent, and it's how a // distributor installed after us ever gets noticed. - Push.register(this); + if (unifiedPush) Push.register(this); // Android 13+ won't show our notifications without this, and the TWA's // own permission covers the browser's, not ours. - if (Build.VERSION.SDK_INT >= 33 + if (unifiedPush && Build.VERSION.SDK_INT >= 33 && checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED && Push.distributor(this) != null) { try { requestPermissions(new String[] { Manifest.permission.POST_NOTIFICATIONS }, 1); } catch (Exception ignored) {} -- cgit v1.2.3