lock_screen_pin
A customizable PIN lock screen for Flutter. It gives you a numeric keypad, PIN dots, wrong-PIN feedback, and optional biometric hooks.
Features
- Numeric keypad with clear and backspace keys
- PIN dots with accepted and rejected colors
- Wrong-PIN dialog with configurable text
- Biometric entry hooks: fingerprint area and automatic success
- Attempt lockout with
maxAttemptsandlockoutDuration - PIN codec hook: keep only a hash with
PinCodecandexpectedCode - Haptic feedback on accepted and rejected entries
- Accessibility labels on the keypad keys and the PIN dots
- Theming with
PinLockTheme, also as aThemeExtension - Localizable labels with
PinLockStrings
Install
flutter pub add lock_screen_pin
Usage
import 'package:flutter/material.dart';
import 'package:lock_screen_pin/lock_screen_pin.dart';
class PinPage extends StatelessWidget {
const PinPage({super.key});
@override
Widget build(BuildContext context) {
return LockScreen(
title: 'Enter your PIN',
passLength: 4,
passCodeVerify: (code) async => code.join() == '1234',
onSuccess: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Unlocked')),
);
},
);
}
}
Set showWrongPassDialog to true to show the wrong-PIN dialog. Pass
PinLockStrings to strings to change its text.
Biometrics
The app verifies biometric data. The package never shows a biometric prompt.
Keep fingerVerify at false and run your own prompt, for example with
local_auth. Set fingerVerify to true only after the prompt succeeds. The
lock screen then calls onSuccess. To show a tappable fingerprint area, set
showFingerPass to true and provide fingerPrintImage. A tap calls
fingerFunction, where you start your prompt.
Warning: If you set
fingerVerifytotruebefore your prompt succeeds, the lock screen callsonSuccessimmediately and skips the PIN.
Lockout
Set maxAttempts to limit the number of wrong entries. After the limit the
keypad disables for lockoutDuration, the dots reset, and onLockoutStart
fires once. The keypad enables again after the duration and onLockoutEnd
fires once. A correct entry resets the attempt counter.
LockScreen(
title: 'Enter your PIN',
passLength: 4,
maxAttempts: 3,
lockoutDuration: const Duration(seconds: 30),
onLockoutStart: () => debugPrint('Keypad locked'),
onLockoutEnd: () => debugPrint('Keypad unlocked'),
passCodeVerify: (code) async => code.join() == '1234',
onSuccess: () {},
);
lockoutDuration defaults to 30 seconds. When maxAttempts is null, the
lock screen never locks out. Read remainingAttempts and isLockedOut from
a GlobalKey<LockScreenState>:
final lockScreenKey = GlobalKey<LockScreenState>();
LockScreen(
key: lockScreenKey,
title: 'Enter your PIN',
passLength: 4,
maxAttempts: 3,
passCodeVerify: (code) async => code.join() == '1234',
onSuccess: () {},
);
final attemptsLeft = lockScreenKey.currentState?.remainingAttempts;
final locked = lockScreenKey.currentState?.isLockedOut ?? false;
PIN codec
Store only a hash of the PIN code with expectedCode and codec. The
IdentityPinCodec default compares the stored value as plain text.
LockScreen(
title: 'Enter your PIN',
passLength: 4,
expectedCode: storedHash,
codec: const IdentityPinCodec(),
onSuccess: () {},
);
Implement PinCodec to hash with a real algorithm:
class ReversedPinCodec implements PinCodec {
const ReversedPinCodec();
@override
String hash(String pin) => pin.split('').reversed.join();
@override
bool verify(String pin, String expected) => hash(pin) == expected;
}
The widget calls verify with the entered digits and the stored value. When
both passCodeVerify and expectedCode are set, passCodeVerify wins. One
of the two is required.
Haptics
hapticsEnabled defaults to true. The lock screen fires a light impact on
success and a heavy impact on a wrong entry. Biometric success fires no
haptics. Set hapticsEnabled to false to disable haptics.
Accessibility
The keypad keys announce labels such as "Digit 5". The code panel announces
the entered digit count, for example "PIN entry, 3 of 6 digits entered". The
clear and backspace labels come from PinLockStrings.
Configuration
passLengthaccepts values from 1 to 8. Other values fail an assertion.- Provide
passCodeVerifyorexpectedCode.passCodeVerifywins when both are set. maxAttemptssets the wrong-entry limit;lockoutDurationdefaults to 30 seconds.hapticsEnableddefaults totrue.stylesonLockScreentakes precedence over aPinLockThemeinThemeData.extensions.PinLockStringssets the labels for the clear key, the backspace key, and the wrong-PIN dialog.
Example
The example/ app shows a four-digit PIN lock screen.
Libraries
- lock_screen_pin
- A customizable PIN/passcode lock screen with keypad, code dots, optional biometrics entry, attempt lockout, a PIN codec hook, haptics, and themeable colors and strings.