Amber v6.2.0 rejects a plain nostrsigner: navigation as malformed: it
reads the signer parameters from intent extras, which a window.location
navigation cannot set. An intent:// URL lets the launcher pass the event
as the data URI plus type/returnType/appName/callbackUrl as S.* extras,
so Amber accepts the request and shows its sign dialog. The query is also
kept on the data URI for the EXTRA_APPLICATION_ID web flow.
Note: on the emulator with Amber v6.2.0 the post-approval callback did
not always fire (Amber returns via setResult when callingPackage != null);
needs verification on a real device.
Amber v6.2.0 routes nostrsigner: intents by EXTRA_APPLICATION_ID: present
(web flow, reads the event from the URI) vs absent (app-to-app flow,
reads type/event from intent extras → rejects our URI as malformed).
Browsers only attach that extra when the external-app launch comes from a
user gesture, so the auto-redirect on page load always failed. The
launcher now waits for the user to tap "Mit Amber signieren".
Server-side percent-encoding (rawurlencode/http_build_query) produced a
nostrsigner: URI that Amber rejected as malformed. The launcher view now
assembles it in JS with encodeURIComponent(JSON.stringify(event)) — the
exact encoding Amber accepts (verified working earlier in the session).
The controller only passes k1 and the callback URL.
A direct ACTION_VIEW intent to nostrsigner: (Browser::open from the app)
lacks category.BROWSABLE, so Amber routes it into its app-to-app path
and rejects it as malformed. The app instead opens /auth/mobile/nostr in
an in-app browser; that page fires the signer via window.location, so
the intent carries BROWSABLE and Amber uses its web-signing flow. No
visible login UI, local signing, token returned via the App Link.