Root cause: the stock nostr-signer-capacitor-plugin (0.0.5) tries Amber's
background ContentProvider first, which GrapheneOS blocks and never returns,
with no clean fallback — so signing hung 90s and Amber never appeared.
Fix (matches Amethyst, the reference NIP-55 client):
- New native Capacitor plugin AmberIntent (android-templates/AmberIntentPlugin.java)
that goes STRAIGHT to a foreground nostrsigner: intent via a properly-registered
ActivityResultLauncher, tracks each request by id, and times out gracefully.
- MainActivity now registers the launcher in onCreate (AndroidX contract) and
hands it to the plugin, while staying a safe stock BridgeActivity (no
WebViewClient override → no black screen).
- inject-main-activity.mjs now installs both MainActivity.java and AmberIntentPlugin.java.
- capacitorAmberSigner.ts rewired to registerPlugin('AmberIntent'); every op is a
user-visible Amber Approve/Reject popup; rejections surface as a friendly message.
- Removed the dead npm nostr-signer-capacitor-plugin dependency (and its phantom
coracle fork spec) plus its vite external entry — signing no longer uses it.
- Delete flow copy updated to the new foreground UX (Approve in Amber / Cancelled
on reject) instead of the diagnostic SIGN/PUBLISH narration.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
53 lines
2.1 KiB
Java
53 lines
2.1 KiB
Java
package org.skatespots.app;
|
|
|
|
import android.content.Intent;
|
|
import android.os.Bundle;
|
|
|
|
import androidx.activity.result.ActivityResultLauncher;
|
|
import androidx.activity.result.contract.ActivityResultContracts;
|
|
|
|
import com.getcapacitor.BridgeActivity;
|
|
|
|
/**
|
|
* SkateSpots launcher activity.
|
|
*
|
|
* SAFE BY DESIGN: this extends the stock Capacitor BridgeActivity and does NOT
|
|
* override the WebViewClient (an earlier custom version did and caused a
|
|
* black-screen crash). The ONLY thing we add is the registration of the
|
|
* ActivityResultLauncher used by AmberIntentPlugin.
|
|
*
|
|
* WHY THE LAUNCHER LIVES HERE
|
|
* ───────────────────────────
|
|
* AndroidX requires registerForActivityResult(...) to be called BEFORE the
|
|
* Activity is STARTED (i.e. during onCreate). A Capacitor Plugin is instantiated
|
|
* too late to register its own launcher, so we create it here and hand it to the
|
|
* plugin via AmberIntentPlugin.setLauncher(). Results are routed straight into
|
|
* AmberIntentPlugin.handleResult().
|
|
*
|
|
* This is the Amethyst NIP-55 pattern: a foreground-intent signer whose result
|
|
* comes back through a properly-registered ActivityResultLauncher — the reliable
|
|
* path that OPENS Amber's Approve/Reject screen and never hangs, on stock Android
|
|
* and on GrapheneOS alike.
|
|
*
|
|
* Injected into the generated android/ project at build time by
|
|
* scripts/inject-main-activity.mjs.
|
|
*/
|
|
public class MainActivity extends BridgeActivity {
|
|
|
|
private ActivityResultLauncher<Intent> amberLauncher;
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
// Register the launcher BEFORE super.onCreate() puts us past STARTED.
|
|
amberLauncher = registerForActivityResult(
|
|
new ActivityResultContracts.StartActivityForResult(),
|
|
result -> AmberIntentPlugin.handleResult(result)
|
|
);
|
|
AmberIntentPlugin.setLauncher(amberLauncher);
|
|
|
|
// Register our native plugin so the WebView can call it.
|
|
registerPlugin(AmberIntentPlugin.class);
|
|
|
|
super.onCreate(savedInstanceState);
|
|
}
|
|
}
|