Back to Freedom.Tech Back
All Ledger Live Mobile releasesAll versions
Release Mon, Sep 28, 2026 8 min read

Ledger Live Mobile 4.22.0

Original release notes

4.22.0

Minor Changes

  • #22003 40d296b Thanks @liviuciulinaru! - Record the provider app the Card login redirect names, and send x-us-env on every Card request of a US holder
  • #21741 250c1c0 Thanks @tonykhaov! - Add a mobile card-numbers View/Hide control that flips to the provider numbers image

browser, and the Help row to open the support article externally.

The QR container on the shared receive confirmation screen carried a testID but no accessible prop, so it never joined the accessibility tree. It is now a focusable element with a role and a localized label, instead of being skipped or announced as an unlabeled node.

  • #21747 871e485 Thanks @claudiiafg! - Fix keyboard handling in the mobile Contacts add, edit, and send flows. Input sheets now open at full height with the keyboard, primary actions remain visible in a keyboard-aware QueuedBottomSheet footer, and name fields focus immediately and capitalize each word.
  • #22077 72367fc Thanks @mcayuelas-ledger! - Wire the card onboarding widget to real, derived onboarding data and remove the unused stub endpoint and legacy devtool mock path it replaces
  • #22093 2e94d90 Thanks @LucasWerey! - Fix available balance showing inflated value for DADA cross-network assets (e.g. Tezos + Etherlink)
  • #22218 285b50d Thanks @mcayuelas-ledger! - Open Google Wallet through its launch intent, and show iOS and Android error scenes when the wallet app is unavailable, with a Play Store fallback on Android.

Replaces the ad-hoc messages getTransactionStatus returned for a rejected bond with typed error classes, translated on both clients and now distinguishing a closed validator from an unbonding one. Adds the isValidatorBondable / getMinBondAmount helpers to the coin module, moves the per-network default validator into the Aleo currency config so every client reads the same address, and adds a reusable Aleo bridge mock for Mobile.

The field asked for biometrics with a generic touch symbol, because Lumen had no biometric one when the screen was built. It has since gained FaceId and Fingerprint, so a face device now shows a face and a fingerprint device a fingerprint.

The device reports six kinds and there are two symbols: a touch is a fingertip on either platform, and everything the device reads from the face - iris and Optic ID included - takes the face symbol, since there is no iris symbol and an eye read is nearer a face than a fingertip. The capability is read asynchronously while the affordance comes from stored state, so the generic touch symbol still stands in for the moment before the device has answered, and for a read that fails.

  • #22275 35a5198 Thanks @LucasWerey! - Give a user protected by biometrics alone a way back when their face goes unread.

The unlock screen already retried the prompt when tapped, but nothing said so: with no password set, a face the camera never saw left the Ledger mark on black and no visible way forward. The whole screen being the button is no help to someone who cannot tell there is a button.

A real call to action now sits under the mark - "Unlock Ledger Wallet" - and it appears only once the prompt has gone. While the prompt is up the system dialog owns the screen, and at boot the bare mark is what keeps the handover from the launch screen invisible.

The other half is the OS's and already works: while its dialog is up, the device credential the app asks for makes iOS draw "Try Face ID Again" and "Enter Passcode" itself. It is only after that dialog is cancelled, when nothing will reopen it, that the app has to offer the way back.

  • #22125 795e693 Thanks @LucasWerey! - Make biometrics a protection in its own right: password and biometrics become independent, and either one alone is enough to lock the app.

Biometrics used to require a password. Its Settings row was disabled until one existed and reset itself whenever the password went away, and the legacy lock returned early without a password, so a biometrics-only user was never locked at all. The revamped path now derives the lock from both protections, so enabling biometrics alone locks the app - and Settings offers it with no password set.

The row is hidden where the device has no biometrics, or has the hardware with nothing enrolled, rather than shown disabled: there is nothing the user could do about it from that screen.

Biometrics is asked for before the unlock screen draws a field, so it is the first thing the user meets and the password is the fallback. While the prompt is up the screen stands in for the splash, with the mark at the splash's own size so the handover moves nothing. Only a refusal reveals the password field - and a user protected by biometrics alone never sees it: pressing the screen asks again, which is their only way in.

The prompt is an explicit owner check through BiometricPrompt / LAContext, not a side effect of reading a protected keychain item. A biometry-gated read can resolve without the OS ever showing anything, and Android reports a correct device PIN as a success the keystore item cannot consume - either way the caller is told the user proved something they were never asked for. On Android 11 and above the OS draws its own "use PIN" button in place of the negative one, and every label it shows comes from the app rather than the library's English defaults.

The keychain item is therefore a plain marker, not an authentication step: it records that biometrics is on, which the protection state cannot do on its own, being held in memory only. Enabling proves before it records, and a refusal stores nothing.

The device credential is accepted, because biometrics can now be the only protection: a lockout after failed attempts would otherwise leave the owner with nothing to try. The consequence to accept is that someone who knows the device passcode can open the app - for a user who also set a password, the weaker path.

Protection that outlived its install is destroyed at boot. iOS keeps keychain items when an app is deleted while Android wipes them, so a reinstall found the previous password and demanded it - for data that went with the uninstall, leaving an owner who had forgotten it locked out of an empty app, advised to reinstall, which is what they had just done. A marker in app storage settles which install the protection belongs to, since an uninstall clears that and not the keychain. The cost, worth stating: clearing app data now clears the lock too, which follows from the threat model this epic assumes - opportunistic access control, not data protection - since anyone who can wipe the data can reinstall anyway.

Removing biometrics asks for it too. Removing a password requires typing it, so removing biometrics must cost as much: an unlocked phone in someone else's hands would otherwise strip the protection in one tap, with nothing asked. A refused prompt leaves both the canary and the switch as they were.

The canary accepts the device passcode (BIOMETRY_ANY_OR_DEVICE_PASSCODE), superseding the earlier BIOMETRY_CURRENT_SET choice. That choice was made when biometrics released a key, where invalidating the item on re-enrolment was the right trade. With no key involved, its only remaining effect would be to shut a biometrics-only user out of their own app with nothing left to try - no password to fall back on and no material to recover. The consequence to accept is that someone who knows the device passcode can open the app; for a user who also set a password, that is a weaker path than the password itself.

  • #22163 944bd23 Thanks @LucasWerey! - Tell a user who has forgotten their app-lock password what their options are, from the unlock screen.

The link was already on the unlock screen and the flow package already accepted the callback, but nothing in the app provided it - so the link never rendered and there was no answer to give.

There is no recovery to offer, and that is the point of the scheme: the password is not stored, only a verifier derived from it, so nothing can reverse it. The sheet says so and names the one way back - reinstalling the app, which drops the lock along with the app's data. That advice is only true now that protection outliving its install is destroyed at boot; before, on iOS the keychain survived an uninstall and the reinstall demanded the very password the user had forgotten.

The sheet is absent for a user protected by biometrics alone, who has no password to forget.

The sheet lives in the flow package with the screen that raises it, which needed @shared/ui-info-state to offer ./native and ./web entries beside its conditional root: a features/flow package can only reach the root through the react-native condition, and that condition resolves Lumen to source and demands its whole native peer graph. Existing consumers keep importing the root, and keep the conditions they had.

  • #22045 1badf50 Thanks @LucasWerey! - Hold the app behind the lock on boot and when it comes back from the background, behind lwmPasswordRevamp.

AppLockGate sits above the app, decides once on boot whether protection is configured, and locks again whenever the app is backgrounded. The unlock screen renders over the app rather than replacing it, so nothing below unmounts and the user lands where they left off.