Flutter Web自动填充触发Unexpected null value错误求助
在Flutter Web端(Safari或Chrome)使用表单自动填充时,会触发Unexpected null value错误。经排查,浏览器将自动填充操作识别为键盘事件,但keyboard_binding.dart第369行的_handleEvent方法期望事件对象包含键盘按键信息,而自动填充触发的事件缺少该信息,导致空值检查失败。
环境信息
- Flutter版本:3.7.5
- 操作系统:MacOS 13.2.1
- 浏览器版本:Chrome 111.0.5563.64
复现代码
import 'package:flutter/material.dart'; void main() { runApp(const CommonFieldsScreen()); } class CommonFieldsScreen extends StatelessWidget { const CommonFieldsScreen({super.key}); @override Widget build(BuildContext context) { final formKey = GlobalKey<FormState>(); final firstNameController = TextEditingController(); final lastNameController = TextEditingController(); return MaterialApp( home: Scaffold( body: Center( child: SizedBox( width: 330, child: Form( key: formKey, child: AutofillGroup( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ TextFormField( controller: firstNameController, decoration: const InputDecoration(hintText: 'First Name'), autofillHints: const [AutofillHints.givenName], validator: _requiredValidator, ), TextFormField( controller: lastNameController, decoration: const InputDecoration( hintText: 'Last Name'), autofillHints: const [AutofillHints.familyName], validator: _requiredValidator), Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: ElevatedButton( onPressed: () { if (formKey.currentState?.validate() ?? false) { firstNameController.clear(); lastNameController.clear(); } }, child: const Text('Submit Form'), ), ), ], ))))))); } String? _requiredValidator(String? value) { if (value == null || value.isEmpty) return 'Required'; return null; } }
错误日志
[+141363 ms] Error: Unexpected null value.
dart-sdk/lib/internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 561:63 nullCheck
lib/_engine/engine/keyboard_binding.dart 369:38 [_handleEvent]
lib/_engine/engine/keyboard_binding.dart 582:7 handleEvent
lib/_engine/engine/keyboard_binding.dart 97:25
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 367:37 _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 372:39 dcall
lib/_engine/engine/keyboard_binding.dart 139:23 loggedHandler
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 367:37 _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 372:39 dcall
[ +21 ms] Error: Unexpected null value.
dart-sdk/lib/internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 561:63 nullCheck
lib/_engine/engine/keyboard_binding.dart 369:38 [_handleEvent]
lib/_engine/engine/keyboard_binding.dart 582:7 handleEvent
lib/_engine/engine/keyboard_binding.dart 100:25
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 367:37 _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 372:39 dcall
lib/_engine/engine/keyboard_binding.dart 139:23 loggedHandler
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 367:37 _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 372:39 dcall
1. 升级Flutter版本
该问题属于Flutter Web的内部Bug,在Flutter 3.10及以上版本中已被修复。执行以下命令升级到稳定版:
flutter upgrade
升级后重新运行项目,自动填充触发的错误应该会消失。
2. 临时 workaround(无法升级时)
如果暂时无法升级Flutter版本,可以通过dart:js拦截浏览器的自动填充相关事件,避免触发Flutter的键盘事件处理逻辑。具体实现如下:
在项目中添加一个工具类,用于拦截事件:
import 'dart:js' as js; void setupAutofillFix() { // 监听输入框的input事件,过滤自动填充触发的无按键事件 js.context['document'].callMethod('addEventListener', ['input', (js.JsEvent event) { // 判断是否是自动填充触发的事件(无key相关属性) if (event['key'] == null && event['code'] == null) { // 阻止事件冒泡到Flutter的键盘绑定处理 event.callMethod('stopPropagation'); } }]); }
然后在main函数中调用这个方法:
void main() { setupAutofillFix(); runApp(const CommonFieldsScreen()); }
这个方法会拦截浏览器自动填充触发的无按键信息的input事件,阻止它被Flutter的键盘事件处理逻辑捕获,从而避免空值错误。
补充说明
KeyboardListener无法检测到自动填充事件是因为自动填充并非由真实键盘输入触发,浏览器不会生成标准的键盘事件,而是直接修改输入框值。- 上述workaround仅针对Web端,不会影响移动端的正常功能。
内容的提问来源于stack exchange,提问作者D_M_

