Two concrete root causes for the eternal "Waiting for Amber…": 1. setPackageName could hang forever on GrapheneOS. getPlugin() awaited it with no timeout, so getPublicKey() (and its 90s timeout) was never even reached. Now setPackageName races a 3s timeout and continues regardless — the Amber package is passed explicitly on every call anyway, so it's non-essential. 2. AndroidManifest.xml had no <queries> block. On Android 11+/GrapheneOS the OS silently blocks the nostrsigner intent without it, so Amber never opens. Added scripts/inject-amber-queries.mjs (idempotent) and wired it into android:init / android:sync / android:build so the block is guaranteed present in every APK, surviving cap sync regeneration. Bump version to 1.1.9. Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
59 lines
2.4 KiB
JavaScript
59 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Inject the Amber (NIP-55) <queries> block into the Android manifest.
|
|
*
|
|
* WHY THIS EXISTS
|
|
* ───────────────
|
|
* On Android 11+ (and GrapheneOS enforces this strictly), an app can only see
|
|
* or launch another app if it declares a matching <queries> entry. Without it,
|
|
* the nostrsigner intent that opens Amber is SILENTLY blocked by the OS and the
|
|
* native signer call hangs forever — the classic "Waiting for Amber…" bug.
|
|
*
|
|
* Capacitor regenerates android/app/src/main/AndroidManifest.xml on `cap add`
|
|
* and can touch it on sync, so hand-editing is fragile. This script is
|
|
* idempotent and runs automatically as part of the android build, guaranteeing
|
|
* the block is always present in the APK we ship.
|
|
*
|
|
* If android/ hasn't been generated yet (fresh checkout), it exits quietly.
|
|
*/
|
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, join } from 'node:path';
|
|
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const manifestPath = join(root, 'android', 'app', 'src', 'main', 'AndroidManifest.xml');
|
|
|
|
if (!existsSync(manifestPath)) {
|
|
console.log('[inject-amber-queries] android/ not generated yet — skipping.');
|
|
process.exit(0);
|
|
}
|
|
|
|
let manifest = readFileSync(manifestPath, 'utf8');
|
|
|
|
if (manifest.includes('android:scheme="nostrsigner"')) {
|
|
console.log('[inject-amber-queries] <queries> already present — nothing to do.');
|
|
process.exit(0);
|
|
}
|
|
|
|
const queriesBlock = ` <!-- REQUIRED for Amber (NIP-55) on Android 11+ / GrapheneOS.
|
|
Without this the OS blocks the nostrsigner intent and the signer call
|
|
hangs forever ("Waiting for Amber"). Injected by scripts/inject-amber-queries.mjs -->
|
|
<queries>
|
|
<intent>
|
|
<action android:name="android.intent.action.VIEW" />
|
|
<data android:scheme="nostrsigner" />
|
|
</intent>
|
|
<package android:name="com.greenart7c3.nostrsigner" />
|
|
</queries>
|
|
`;
|
|
|
|
// Insert right before the closing </manifest> tag.
|
|
if (!manifest.includes('</manifest>')) {
|
|
console.error('[inject-amber-queries] No closing </manifest> tag found — aborting.');
|
|
process.exit(1);
|
|
}
|
|
|
|
manifest = manifest.replace('</manifest>', `${queriesBlock}</manifest>`);
|
|
writeFileSync(manifestPath, manifest);
|
|
|
|
console.log('[inject-amber-queries] ✓ Injected Amber <queries> block into AndroidManifest.xml');
|