Flutter中如何检测iOS设备的锁屏与解锁状态?
Got it, since the screen_state plugin only works on Android and you need to detect actual lock/unlock events on iOS (not just app lifecycle changes), here's how you can implement this using Flutter's MethodChannel to bridge to iOS native APIs that specifically track these system events:
Step 1: Set Up the MethodChannel in Flutter
First, create a helper class in Flutter to handle communication with the iOS native layer and expose a stream for lock state updates:
import 'package:flutter/services.dart'; class LockStateDetector { static const MethodChannel _channel = MethodChannel('lock_state_channel'); static final StreamController<bool> _lockStateController = StreamController.broadcast(); // Stream to subscribe for lock/unlock state changes static Stream<bool> get lockStateStream => _lockStateController.stream; static Future<void> initialize() async { // Listen for messages from iOS _channel.setMethodCallHandler((call) async { if (call.method == 'onLockStateChanged') { final bool isLocked = call.arguments as bool; _lockStateController.add(isLocked); } }); // Tell iOS to start listening for lock events await _channel.invokeMethod('startListening'); } // Clean up resources when done static void dispose() { _lockStateController.close(); } }
Step 2: Implement iOS Native Listener
On iOS, we'll use system notifications that specifically trigger for lock/unlock actions (not app backgrounding). These are UIProtectedDataWillBecomeUnavailableNotification (locks) and UIProtectedDataDidBecomeAvailableNotification (unlocks) — these are tied to the device's security state, so they won't fire when the app is just minimized.
Update AppDelegate.swift (iOS Runner):
import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { private let channelName = "lock_state_channel" private var flutterChannel: FlutterMethodChannel! override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller = window?.rootViewController as! FlutterViewController flutterChannel = FlutterMethodChannel(name: channelName, binaryMessenger: controller.binaryMessenger) // Handle Flutter's request to start listening flutterChannel.setMethodCallHandler { [weak self] call, result in guard let self = self else { return } if call.method == "startListening" { self.setupLockStateListeners() result(nil) } else { result(FlutterMethodNotImplemented) } } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func setupLockStateListeners() { // Listen for device lock event NotificationCenter.default.addObserver( self, selector: #selector(onDeviceLocked), name: UIApplication.protectedDataWillBecomeUnavailableNotification, object: nil ) // Listen for device unlock event NotificationCenter.default.addObserver( self, selector: #selector(onDeviceUnlocked), name: UIApplication.protectedDataDidBecomeAvailableNotification, object: nil ) } @objc private func onDeviceLocked() { flutterChannel.invokeMethod("onLockStateChanged", arguments: true) } @objc private func onDeviceUnlocked() { flutterChannel.invokeMethod("onLockStateChanged", arguments: false) } // Clean up observers when the delegate is deinitialized deinit { NotificationCenter.default.removeObserver(self) } }
Step 3: Use the Detector in Your Flutter App
Now you can subscribe to the lock state stream in any Flutter widget to react to lock/unlock events:
class LockMonitorPage extends StatefulWidget { const LockMonitorPage({super.key}); @override State<LockMonitorPage> createState() => _LockMonitorPageState(); } class _LockMonitorPageState extends State<LockMonitorPage> { bool _isDeviceLocked = false; @override void initState() { super.initState(); // Initialize the detector LockStateDetector.initialize(); // Subscribe to lock state updates LockStateDetector.lockStateStream.listen((isLocked) { setState(() { _isDeviceLocked = isLocked; }); }); } @override void dispose() { LockStateDetector.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Device Lock State")), body: Center( child: Text( _isDeviceLocked ? "Device is Locked" : "Device is Unlocked", style: const TextStyle(fontSize: 20), ), ), ); } }
Key Details
- Why These Notifications?: Unlike app lifecycle events, the
UIProtectedDatanotifications are directly tied to the device's security state. They only trigger when the device is locked/unlocked, not when the app is sent to the background by the user. - Permissions: No extra iOS permissions are needed to use these notifications.
- Memory Management: Always remember to clean up the notification observers in iOS and close the Flutter StreamController to avoid memory leaks.
内容的提问来源于stack exchange,提问作者Adnan Kazi

