unlock_detector
A Flutter plugin that detects foreground/background, idle, and device lock/unlock — ideal for user online/offline presence in chat apps and activity tracking.
Status types
| Status | Meaning | User |
|---|---|---|
foreground |
App is active and visible | online |
idle |
App open but user inactive | away |
background |
User switched away | offline |
locked |
Device screen locked | offline |
unlocked |
Device just unlocked | transitional |
screenOn |
Screen turned on (Android) | transitional |
Helpers on each status: isOnline, isOffline, isIdle, isLocked,
isUnlocked, isForeground, isBackground, isScreenOn.
Platform support
| Platform | foreground / background | idle | lock / unlock |
|---|---|---|---|
| Android | ✅ | ✅ in-app | ✅ + screenOn |
| iOS | ✅ | ✅ in-app | ✅ (data-protection APIs) |
| macOS · Windows · Linux | ✅ window focus | ✅ OS system-wide | — |
| Web | ✅ window focus | ✅ in-app | — |
On web and desktop, foreground/background reflect window focus/blur
(a focused window is online, blurred or minimized is offline) — there is no
device-lock concept there. On desktop, idle follows the OS system-wide
idle time; on mobile and web it follows in-app interaction (see below).
Install
dependencies:
unlock_detector: ^1.4.0
Requires Flutter 3.44 or newer (Dart 3.12). The Android side uses AGP's
built-in Kotlin,
so it no longer applies the Kotlin Gradle Plugin — your app needs AGP 9+.
Stay on 1.3.x if you are on an older Flutter.
One wrinkle worth knowing, and it is not specific to this plugin: AGP 9's
built-in Kotlin resolves KGP 2.2.10, which is below the 2.2.20 Flutter 3.47
requires, so the build stops with "Your project's Kotlin version is lower than
Flutter's minimum supported version". Raise it in your app's
android/settings.gradle — declared, never applied:
plugins {
id "com.android.application" version "9.3.2" apply false
id "org.jetbrains.kotlin.android" version "2.4.10" apply false
}
iOS works with both CocoaPods and Swift Package Manager — no setup needed.
On Linux, building needs the X11 screensaver headers — libxss-dev on Debian
and Ubuntu, libXScrnSaver-devel on Fedora. That extension is the idle-time
source on X11 sessions; under Wayland it cannot see native input, so the
compositor is asked over D-Bus instead (GNOME/Mutter and the freedesktop
screensaver interface are both supported).
Usage
import 'package:unlock_detector/unlock_detector.dart';
// Initialize once. Pass idleTimeout to enable idle detection.
await UnlockDetector.initialize(idleTimeout: const Duration(minutes: 5));
// Listen to status changes.
final sub = UnlockDetector.stream.listen((status) {
if (status.isOnline) {
// user is actively using the app
} else if (status.isIdle) {
// app open, user inactive
} else if (status.isOffline) {
// user left the app or locked the device
}
});
// Read the latest status synchronously (null before the first event).
final now = UnlockDetector.currentStatus;
// One-shot lock check (Android reliable, iOS best-effort).
final locked = await UnlockDetector.isDeviceLocked();
// Clean up when done.
await sub.cancel();
await UnlockDetector.dispose();
Idle detection
Pass idleTimeout to initialize() to get the idle status.
-
Desktop (macOS/Windows/Linux): automatic — idle follows the OS system-wide idle time (any keyboard/mouse input). Nothing else to do.
-
Mobile & web: feed in-app interaction so the timer can reset — call
UnlockDetector.reportActivity()from your input handling, or wrap your app:runApp(UnlockDetector.activityDetector(child: const MyApp()));
Initialization failures throw UnlockDetectorException. Call
UnlockDetector.getPlatformInfo() for a description of platform behavior.
Support
If this plugin helps you, consider supporting development:
License
MIT — see LICENSE.
Libraries
- unlock_detector
- Detects device lock/unlock, app foreground/background, idle and screen state — for user online/offline presence.
- unlock_detector_web