You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:07:07