From 88685262ce47fbb80a02f8d1a99b69aab793571c Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Fri, 4 Sep 2026 22:02:23 +0700 Subject: [PATCH] fix(android): remove custom MainActivity that broke app startup (black screen) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The injected MainActivity overrode Capacitor's WebViewClient, wiping out the client Capacitor needs to load the web layer — causing a black-screen crash on launch. Remove the MainActivity template, its injection script, and the build wiring. The real signing fix (setPackageName before signEvent) is unaffected and remains in place. Bump to 1.2.10. Co-authored-by: shakespeare.diy --- android-templates/MainActivity.java | 101 ---------------------------- package.json | 8 +-- release-notes.txt | 10 +++ scripts/inject-main-activity.mjs | 59 ---------------- 4 files changed, 14 insertions(+), 164 deletions(-) delete mode 100644 android-templates/MainActivity.java delete mode 100644 scripts/inject-main-activity.mjs diff --git a/android-templates/MainActivity.java b/android-templates/MainActivity.java deleted file mode 100644 index 215f0d9..0000000 --- a/android-templates/MainActivity.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.skatespots.app; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import com.getcapacitor.BridgeActivity; - -/** - * Custom MainActivity that lets the WebView hand OFF `intent:` / `nostrsigner:` - * URLs to the Android OS so Amber's approval screen actually opens. - * - * WHY THIS EXISTS - * ─────────────── - * When the JS signer navigates to an `intent:...;scheme=nostrsigner;...;end` - * URL, Capacitor's default WebView treats it as a page navigation and silently - * DROPS it — so Amber never launches and every signing action (delete, accept - * crew invite, zap, profile edit) hangs forever. Login works only because it - * goes through the native plugin's startActivityForResult; JS-initiated intents - * were never reaching the OS. On GrapheneOS this is enforced strictly. - * - * The fix: override shouldOverrideUrlLoading. Whenever the WebView tries to load - * an `intent:` or `nostrsigner:` URL, we parse it and call startActivity() - * ourselves — a REAL native launch that opens Amber, exactly like login. The - * result comes back via the app's custom-scheme deep link - * (org.skatespots.app://amber-callback...), handled by DeepLinkHandler / - * resolveAmberIntent in the web layer. - * - * This file is injected into the generated android/ project at build time by - * scripts/inject-main-activity.mjs (android/ is not committed). - */ -public class MainActivity extends BridgeActivity { - - private static final String TAG = "SkateSpotsAmber"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - final WebView webView = getBridge().getWebView(); - if (webView == null) { - return; - } - - final WebViewClient existing = new WebViewClient(); - - webView.setWebViewClient(new WebViewClient() { - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (handleExternalScheme(url)) { - return true; - } - return super.shouldOverrideUrlLoading(view, url); - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, android.webkit.WebResourceRequest request) { - final String url = request.getUrl() != null ? request.getUrl().toString() : null; - if (url != null && handleExternalScheme(url)) { - return true; - } - return super.shouldOverrideUrlLoading(view, request); - } - }); - } - - /** - * If the URL is an Amber/signer intent, launch it natively and return true. - * Returns false for normal in-app URLs so Capacitor handles them as usual. - */ - private boolean handleExternalScheme(String url) { - if (url == null) { - return false; - } - - try { - if (url.startsWith("intent:")) { - // Parse the full Android intent: URI (carries scheme, extras, end). - Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - return true; - } - - if (url.startsWith("nostrsigner:")) { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - return true; - } - } catch (Exception e) { - Log.e(TAG, "Failed to launch external signer intent: " + e.getMessage(), e); - // Fall through — let the WebView try to handle it (will no-op safely). - } - - return false; - } -} diff --git a/package.json b/package.json index 3480127..98accff 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "skate-spots", "private": true, - "version": "1.2.9", + "version": "1.2.10", "type": "module", "homepage": "https://skate-spots.com", "scripts": { @@ -9,11 +9,11 @@ "build": "npm i --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'Project built successfully!'", "test": "npm i --silent && tsc --noEmit && eslint && vitest run --reporter=dot --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'All tests passed!'", "deploy": "npm i --silent && npm run build && npx -y nostr-deploy-cli deploy --skip-setup", - "android:init": "npm run android:build:apk && npx cap add android && npx cap sync android && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs", - "android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs", + "android:init": "npm run android:build:apk && npx cap add android && npx cap sync android && node scripts/inject-amber-queries.mjs", + "android:sync": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs", "android:open": "npx cap open android", "android:version": "node scripts/sync-android-version.mjs", - "android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && node scripts/inject-main-activity.mjs && cd android && ./gradlew assembleRelease", + "android:build": "npm run android:build:apk && npx cap sync android && node scripts/sync-android-version.mjs && node scripts/inject-amber-queries.mjs && cd android && ./gradlew assembleRelease", "android:build:apk": "CAPACITOR_BUILD=1 vite build && sed -i 's|||g' dist/index.html && sed -i 's|