SkateSpots/scripts/inject-main-activity.mjs
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

59 lines
2.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Ensure the correct (stock) MainActivity.java exists in the generated Android
* project.
*
* The AndroidManifest launches org.skatespots.app.MainActivity. If that class is
* missing or wrong, the app crashes on launch (black screen). We keep the stock
* source of truth in android-templates/MainActivity.java and copy it in on every
* build so the launcher class is ALWAYS present and correct — even after
* `rm -rf android` or `cap add` regenerate things.
*
* This version does NOT override the WebViewClient (a previous custom version
* did and broke startup). Idempotent. Exits quietly if android/ isn't generated.
*/
import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
const targetDir = join(root, 'android', 'app', 'src', 'main', 'java', 'org', 'skatespots', 'app');
const templatesDir = join(root, 'android-templates');
// Native Java sources kept as the source of truth in android-templates/ and
// copied into the generated project on every build. MainActivity registers the
// Amber ActivityResultLauncher; AmberIntentPlugin is the Amethyst-style NIP-55
// foreground signer that opens Amber's Approve/Reject screen and never hangs.
const files = ['MainActivity.java', 'AmberIntentPlugin.java'];
// If the android/ project hasn't been generated yet, do nothing.
if (!existsSync(join(root, 'android', 'app'))) {
console.log('[inject-main-activity] android/ not generated yet — skipping.');
process.exit(0);
}
if (!existsSync(targetDir)) {
mkdirSync(targetDir, { recursive: true });
}
for (const file of files) {
const template = join(templatesDir, file);
const target = join(targetDir, file);
if (!existsSync(template)) {
console.error(`[inject-main-activity] template android-templates/${file} missing — aborting.`);
process.exit(1);
}
const desired = readFileSync(template, 'utf8');
const current = existsSync(target) ? readFileSync(target, 'utf8') : null;
if (current === desired) {
console.log(`[inject-main-activity] ${file} already correct.`);
continue;
}
copyFileSync(template, target);
console.log(`[inject-main-activity] ✓ Ensured ${file} is present (Amber foreground signer + safe launcher).`);
}