Fix Amber "not installed" false positive - skip isExternalSignerInstalled() check

Android 11+ package visibility rules cause isExternalSignerInstalled() to
return false even when Amber is installed, unless <queries> is declared in
AndroidManifest.xml. Skip the pre-check and attempt login directly instead,
with better error messages for cancel vs not-found vs other errors.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-07-09 11:49:16 +07:00
parent 6230948383
commit ef22eb2de7

View file

@ -16,7 +16,7 @@ import { useLoginActions } from '@/hooks/useLoginActions';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { openAmberForLogin, subscribeToAmberReturn } from '@/lib/amber'; import { openAmberForLogin, subscribeToAmberReturn } from '@/lib/amber';
import { getAmberPublicKeyViaPlugin, isAmberInstalled } from '@/lib/capacitorAmberSigner'; import { getAmberPublicKeyViaPlugin } from '@/lib/capacitorAmberSigner';
interface LoginDialogProps { interface LoginDialogProps {
@ -54,23 +54,23 @@ export const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLog
if (isCapacitor) { if (isCapacitor) {
// ── Native path (ZapStore/Capacitor APK) ──────────────────────────────── // ── Native path (ZapStore/Capacitor APK) ────────────────────────────────
// Check Amber is installed first for a clear error message // Attempt login directly — skip isExternalSignerInstalled() check because
const installed = await isAmberInstalled(); // Android 11+ package visibility rules can make it return false even when
if (!installed) { // Amber IS installed (requires <queries> in AndroidManifest.xml).
setAmberError('Amber is not installed. Install it from the ZapStore or GitHub.');
setAmberStep('error');
return;
}
try { try {
// This opens Amber natively, user approves, pubkey comes back as a Promise // This opens Amber natively, user approves, pubkey comes back as a Promise
const pubkey = await getAmberPublicKeyViaPlugin(); const pubkey = await getAmberPublicKeyViaPlugin();
completeAmberLogin(pubkey); completeAmberLogin(pubkey);
} catch (e: unknown) { } catch (e: unknown) {
// User cancelled or Amber threw
const msg = (e as Error)?.message ?? 'Amber login failed'; const msg = (e as Error)?.message ?? 'Amber login failed';
setAmberError(msg.includes('cancelled') || msg.includes('cancel') // Distinguish: user cancelled vs Amber not installed vs other error
? 'Login cancelled. Tap "Open Amber" to try again.' if (msg.toLowerCase().includes('cancel') || msg.toLowerCase().includes('denied')) {
: msg); setAmberError('Login cancelled. Tap "Open Amber" to try again.');
} else if (msg.toLowerCase().includes('not found') || msg.toLowerCase().includes('no activity') || msg.toLowerCase().includes('resolve')) {
setAmberError('Amber not found. Make sure Amber is installed from the ZapStore.');
} else {
setAmberError(msg);
}
setAmberStep('error'); setAmberStep('error');
} }
return; return;