Fix Amber native login in APK: reliable Capacitor detection (v1.1.7)
Root cause: LoginDialog and useCurrentUser detected the native app via
window.Capacitor, which is unreliable inside the WebView (false at mount / not
attached in some builds). So the ZapStore APK fell into the web intent:// redirect
flow and never opened Amber ("Waiting for Amber…" hang).
Fix: add isNativeAmberAvailable() in capacitorAmberSigner.ts using the imported
@capacitor/core Capacitor + native plugin presence, and use it (evaluated at
click time) in LoginDialog.handleAmberLogin and in useCurrentUser's signer
selection. The APK now calls getAmberPublicKeyViaPlugin() → native intent → Amber
opens directly, no redirects.
Bump version to 1.1.7.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
3dea1e42dc
commit
c6372742a9
4 changed files with 25 additions and 9 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "skate-spots",
|
"name": "skate-spots",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.1.6",
|
"version": "1.1.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"homepage": "https://skate-spots.com",
|
"homepage": "https://skate-spots.com",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -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 } from '@/lib/capacitorAmberSigner';
|
import { getAmberPublicKeyViaPlugin, isNativeAmberAvailable } from '@/lib/capacitorAmberSigner';
|
||||||
|
|
||||||
|
|
||||||
interface LoginDialogProps {
|
interface LoginDialogProps {
|
||||||
|
|
@ -45,9 +45,6 @@ export const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLog
|
||||||
|
|
||||||
const isAndroid = /Android/i.test(navigator.userAgent);
|
const isAndroid = /Android/i.test(navigator.userAgent);
|
||||||
|
|
||||||
// Detect if running inside a Capacitor native app
|
|
||||||
const isCapacitor = !!(window as unknown as { Capacitor?: { isNativePlatform?: () => boolean } }).Capacitor?.isNativePlatform?.();
|
|
||||||
|
|
||||||
// Step 1: open Amber
|
// Step 1: open Amber
|
||||||
// - On Capacitor (ZapStore APK): use the native plugin — direct Promise, no redirects needed
|
// - On Capacitor (ZapStore APK): use the native plugin — direct Promise, no redirects needed
|
||||||
// - On web/PWA: use intent:// URL with callbackUrl so Amber redirects back
|
// - On web/PWA: use intent:// URL with callbackUrl so Amber redirects back
|
||||||
|
|
@ -55,7 +52,11 @@ export const LoginDialog: React.FC<LoginDialogProps> = ({ isOpen, onClose, onLog
|
||||||
setAmberStep('loading');
|
setAmberStep('loading');
|
||||||
setAmberError('');
|
setAmberError('');
|
||||||
|
|
||||||
if (isCapacitor) {
|
// Decide native-vs-web at CLICK TIME using the reliable Capacitor check from
|
||||||
|
// the signer module (imported @capacitor/core), NOT window.Capacitor which
|
||||||
|
// can be false at mount inside the WebView — that mismatch was causing the
|
||||||
|
// APK to fall into the web redirect flow and never actually open Amber.
|
||||||
|
if (isNativeAmberAvailable()) {
|
||||||
// ── Native path (ZapStore/Capacitor APK) ────────────────────────────────
|
// ── Native path (ZapStore/Capacitor APK) ────────────────────────────────
|
||||||
// Attempt login directly — skip isExternalSignerInstalled() check because
|
// Attempt login directly — skip isExternalSignerInstalled() check because
|
||||||
// Android 11+ package visibility rules can make it return false even when
|
// Android 11+ package visibility rules can make it return false even when
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { useAuthor } from './useAuthor.ts';
|
import { useAuthor } from './useAuthor.ts';
|
||||||
import { AmberSigner } from '@/lib/amber';
|
import { AmberSigner } from '@/lib/amber';
|
||||||
import { CapacitorAmberSigner } from '@/lib/capacitorAmberSigner';
|
import { CapacitorAmberSigner, isNativeAmberAvailable } from '@/lib/capacitorAmberSigner';
|
||||||
import type { AmberLoginType } from './useLoginActions';
|
import type { AmberLoginType } from './useLoginActions';
|
||||||
|
|
||||||
/** Extended login type that includes Amber */
|
/** Extended login type that includes Amber */
|
||||||
|
|
@ -27,8 +27,8 @@ export function useCurrentUser() {
|
||||||
// On Capacitor (ZapStore APK) use the native plugin signer so all
|
// On Capacitor (ZapStore APK) use the native plugin signer so all
|
||||||
// signing operations go through Amber via native intents.
|
// signing operations go through Amber via native intents.
|
||||||
// On web/PWA fall back to the URL-redirect based AmberSigner.
|
// On web/PWA fall back to the URL-redirect based AmberSigner.
|
||||||
const isCapacitor = !!(window as unknown as { Capacitor?: { isNativePlatform?: () => boolean } }).Capacitor?.isNativePlatform?.();
|
// Use the reliable module-level Capacitor check (not window.Capacitor).
|
||||||
const signer = isCapacitor
|
const signer = isNativeAmberAvailable()
|
||||||
? new CapacitorAmberSigner(amberLogin.pubkey)
|
? new CapacitorAmberSigner(amberLogin.pubkey)
|
||||||
: new AmberSigner(amberLogin.pubkey);
|
: new AmberSigner(amberLogin.pubkey);
|
||||||
return new NUser('x-amber', amberLogin.pubkey, signer);
|
return new NUser('x-amber', amberLogin.pubkey, signer);
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,21 @@ export class CapacitorAmberSigner implements NostrSigner {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when we're running inside the native Capacitor app AND the native
|
||||||
|
* NostrSigner bridge is usable. This is the ONLY reliable native check —
|
||||||
|
* reading `window.Capacitor` from a component can be false at mount time or in
|
||||||
|
* builds where Capacitor doesn't attach itself to `window`. Always call this at
|
||||||
|
* the moment of the action (e.g. inside the login click handler), not at render.
|
||||||
|
*/
|
||||||
|
export function isNativeAmberAvailable(): boolean {
|
||||||
|
try {
|
||||||
|
return !!Capacitor?.isNativePlatform?.() && !!getNativeSigner();
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is an external signer (Amber) installed on this device?
|
* Is an external signer (Amber) installed on this device?
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue