From c7e890e65c8e2c78d99ce4274ff6604b46dbe8b0 Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Wed, 9 Sep 2026 10:47:39 +0700 Subject: [PATCH] Citrine: allow loopback ws:// in WebView so the local relay connects (1.3.5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The real fix for "Citrine running but 0 connections": the app is served over https in the WebView and Citrine listens on plaintext ws://127.0.0.1, which modern Android WebViews block as mixed content BEFORE it reaches the network layer — allowMixedContent + the loopback network-security-config don't fully cover WebSocket mixed content. MainActivity now sets the bridge WebView's mixed-content mode to MIXED_CONTENT_ALWAYS_ALLOW after super.onCreate(), which lets the localhost ws:// connection through for every user. All real traffic stays wss:///https://; this only unblocks the loopback relay. The WebViewClient is left untouched (overriding it previously caused a black screen). Wrapped in try/catch so it can never crash the launcher. Also removed the temporary on-screen probe debug readout (kept the diagnostic fields in useCitrine, unused by UI, for future use). Co-authored-by: shakespeare.diy --- android-templates/MainActivity.java | 25 +++++++++++++++++++++++++ package.json | 2 +- src/pages/SettingsPage.tsx | 11 ----------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/android-templates/MainActivity.java b/android-templates/MainActivity.java index 997b604..5c7a1c0 100644 --- a/android-templates/MainActivity.java +++ b/android-templates/MainActivity.java @@ -2,6 +2,8 @@ package org.skatespots.app; import android.content.Intent; import android.os.Bundle; +import android.webkit.WebSettings; +import android.webkit.WebView; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; @@ -49,5 +51,28 @@ public class MainActivity extends BridgeActivity { registerPlugin(AmberIntentPlugin.class); super.onCreate(savedInstanceState); + + // ── Allow the on-device Citrine relay (ws://127.0.0.1) ────────────── + // The app is served to the WebView over the https scheme, and Citrine + // listens on a PLAINTEXT WebSocket (ws://, not wss://). Modern Android + // WebViews treat "secure page → insecure ws" as mixed content and block + // it BEFORE it ever reaches the network layer — which is why the local + // relay showed 0 connections despite allowMixedContent + the loopback + // network-security-config (neither fully covers WebSocket mixed content). + // + // MIXED_CONTENT_ALWAYS_ALLOW on the bridge WebView lets the localhost + // ws:// connection through. All real traffic remains wss:// / https://; + // this only unblocks the loopback relay. We do NOT touch the + // WebViewClient (overriding it previously caused a black-screen crash). + try { + WebView webView = getBridge().getWebView(); + if (webView != null) { + WebSettings settings = webView.getSettings(); + settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + } + } catch (Exception e) { + // Non-fatal: if this fails the app still runs, the local relay just + // won't connect. Never crash the launcher over an optional feature. + } } } diff --git a/package.json b/package.json index 57520cb..3d6dff5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "skate-spots", "private": true, - "version": "1.3.4", + "version": "1.3.5", "type": "module", "homepage": "https://skate-spots.com", "scripts": { diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 8ffb263..ebf9f93 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -490,17 +490,6 @@ function CitrineCard() { )} - {/* Debug readout — shows the exact probe URL + failure reason on the - device so connectivity can be diagnosed without USB/adb. Only shown - while not connected. */} - {state !== 'live' && citrine.reason && citrine.reason !== 'not-android' && ( -
-
debug
-
url: {citrine.probeUrl}
-
result: {citrine.reason}
-
- )} - {/* Privacy reassurance — always present when enabled */}