From 6fb7314f6c8403a5e43d34035cba825089787019 Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Thu, 27 Aug 2026 14:29:35 +0700 Subject: [PATCH] Fix real Amber login hang: skip package-name so getPublicKey uses the intent, not the stalling ContentProvider (v1.1.9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause found in the plugin's native getPublicKey (NostrSignerPlugin.java): when a packageName is set, it FIRST tries Amber's ContentProvider (background, no-UI). On GrapheneOS that cross-app ContentResolver query is blocked and never returns, so it never falls through to startActivityForResult(nostrsigner:) — the branch that actually opens Amber's approval UI. Result: eternal "Waiting for Amber". Fix: getAmberPublicKeyViaPlugin no longer calls setPackageName and no longer passes packageName; it passes only the get_public_key permission. With no package name the plugin skips the content-resolver branch and launches the intent directly, opening Amber's UI. Amber returns both pubkey and its package, so later signing still works. Paired with the auto-injected manifest block so the OS can resolve the intent in the first place. Co-authored-by: shakespeare.diy --- src/lib/capacitorAmberSigner.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/lib/capacitorAmberSigner.ts b/src/lib/capacitorAmberSigner.ts index c654d3e..8533870 100644 --- a/src/lib/capacitorAmberSigner.ts +++ b/src/lib/capacitorAmberSigner.ts @@ -147,10 +147,24 @@ async function getPlugin(): Promise { * handle both hex and real npub just in case. */ export async function getAmberPublicKeyViaPlugin(): Promise { - const plugin = await getPlugin(); + // Get the raw native bridge directly. CRITICALLY we do NOT call + // setPackageName here and we do NOT pass packageName to getPublicKey. + // + // WHY: the native getPublicKey first tries Amber's ContentProvider (a + // background, no-UI query) whenever a packageName is known. On GrapheneOS that + // cross-app ContentResolver query is blocked/stalls and never returns cleanly, + // so the code never falls through to the intent that actually opens Amber's + // approval screen → eternal "Waiting for Amber". By omitting packageName, the + // plugin skips the content-resolver branch and goes STRAIGHT to + // startActivityForResult(nostrsigner:) which launches Amber's UI. Amber returns + // both the pubkey AND its package, so subsequent signing still works. + const plugin = getNativeSigner(); + if (!plugin) { + throw new Error('Amber signing is only available in the SkateSpots Android app.'); + } const result = await withTimeout( - plugin.getPublicKey({ packageName: AMBER_PACKAGE }), + plugin.getPublicKey({ permissions: JSON.stringify([{ type: 'get_public_key' }]) }), 'login', );