如何在Flutter中监听iOS原生事件通知?以UIKeyboardWillShowNotification为例
Hey there! 要在Flutter里监听iOS的原生通知(比如UIKeyboardWillShowNotification这类系统通知),核心是靠MethodChannel搭建Flutter和iOS原生代码的通信桥——让原生端先监听系统通知,再把拿到的事件数据传递给Flutter侧处理。下面是完整的实现步骤,包你能搞定:
实现步骤
1. Flutter侧:配置MethodChannel并监听事件
首先在Dart代码里创建MethodChannel,然后设置回调来接收原生发来的键盘事件数据。这里以一个简单的demo为例:
import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { // 定义MethodChannel的名称,要和iOS端保持一致 static const MethodChannel _keyboardChannel = MethodChannel('com.example/keyboard_notifications'); double _currentKeyboardHeight = 0.0; @override void initState() { super.initState(); // 监听原生传递过来的方法调用 _keyboardChannel.setMethodCallHandler((MethodCall call) async { switch (call.method) { // 处理键盘即将显示的事件 case 'onKeyboardWillShow': final height = call.arguments['height'] as double; setState(() { _currentKeyboardHeight = height; }); break; // 处理键盘即将隐藏的事件 case 'onKeyboardWillHide': setState(() { _currentKeyboardHeight = 0.0; }); break; default: throw MissingPluginException(); } }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('iOS Keyboard Notification Demo')), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ const TextField( decoration: InputDecoration(hintText: "Tap here to trigger keyboard"), ), const SizedBox(height: 20), Text('Current Keyboard Height: ${_currentKeyboardHeight.toStringAsFixed(2)}'), ], ), ), ), ); } }
2. iOS原生侧:注册通知并传递数据到Flutter
接下来要在iOS的原生代码里(Swift或Objective-C都可以,这里用Swift举例)注册系统键盘通知,拿到键盘高度等信息后,通过MethodChannel传给Flutter。
如果你的项目用的是AppDelegate:
import UIKit import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { // 要和Flutter侧的Channel名称完全一致 private let channelName = "com.example/keyboard_notifications" private var keyboardChannel: FlutterMethodChannel! override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { guard let flutterViewController = window?.rootViewController as? FlutterViewController else { fatalError("Could not get FlutterViewController") } // 初始化MethodChannel keyboardChannel = FlutterMethodChannel(name: channelName, binaryMessenger: flutterViewController.binaryMessenger) // 注册键盘显示/隐藏的通知监听 NotificationCenter.default.addObserver( self, selector: #selector(handleKeyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(handleKeyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil ) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // 处理键盘即将显示的通知 @objc private func handleKeyboardWillShow(_ notification: Notification) { guard let userInfo = notification.userInfo, let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, let flutterView = window?.rootViewController?.view else { return } // 转换键盘frame到当前视图的坐标系,避免安全区影响高度计算 let convertedFrame = flutterView.convert(keyboardFrame, from: nil) let keyboardHeight = convertedFrame.height // 把键盘高度传给Flutter keyboardChannel.invokeMethod("onKeyboardWillShow", arguments: ["height": keyboardHeight]) } // 处理键盘即将隐藏的通知 @objc private func handleKeyboardWillHide(_ notification: Notification) { keyboardChannel.invokeMethod("onKeyboardWillHide", arguments: nil) } // 销毁时移除通知监听,防止内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } }
如果你的项目用的是iOS 13+的SceneDelegate,那把通知注册的逻辑放到scene(_:willConnectTo:options:)方法里即可,其他逻辑一致。
3. 额外注意事项
- 通知参数扩展:除了键盘高度,你还可以从
notification.userInfo里拿到更多数据,比如动画时长(UIResponder.keyboardAnimationDurationUserInfoKey)、动画曲线(UIResponder.keyboardAnimationCurveUserInfoKey),按需传递给Flutter即可。 - 内存泄漏防范:一定要在
deinit(Swift)里移除通知监听,避免内存泄漏。 - 测试环境:这个逻辑只在iOS生效,测试时请使用iOS模拟器或真机,Android端无需处理这些原生通知。
内容的提问来源于stack exchange,提问作者XX Yang
相关产品推荐
相关产品推荐

