SkateSpots/android-templates/MainActivity.java
shakespeare.diy 63db160b80 fix(amber): Amethyst-style foreground-intent signer to end the GrapheneOS sign hang
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>
2026-09-07 12:39:00 +07:00

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);
}
}