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

iOS 18下Flutter InAppWebView上下文菜单触发UICommand崩溃问题及相关技术咨询

iOS 18下Flutter InAppWebView上下文菜单触发UICommand崩溃问题及相关技术咨询

问题背景

我在iOS 18设备上遇到一个崩溃问题:当点击flutter_inappwebview内部的原生上下文菜单项时,App会崩溃,崩溃日志指向UIKitCore中的UICommand performWithSender:target:方法。以下是详细的崩溃信息、相关代码和核心疑问。

崩溃日志(摘录)

Crashed: com.apple.main-thread
0 ??? 0x103bf400c (Missing)
1 UIKitCore 0x136b698 -[UICommand performWithSender:target:] + 172
2 UIKitCore 0x1550e64 -[UIEditMenuInteraction _editMenuPresentation:didSelectMenuLeaf:completion:] + 316
3 UIKitCore 0x146c1d8 -[_UIEditMenuContentPresentation editMenuListView:didSelectMenuElement:] + 244
4 UIKitCore 0xc76bf4 -[_UIEditMenuListView _selectItemAtIndexPath:] + 280
...
30 MyAppName 0x19430 main + 120 (AppDelegate.swift:120)

相关代码片段

var style = "";

Widget build(BuildContext context) {
  return BlocConsumer<myCubit, myState>(
    bloc: myCubit,
    listener: (context, state) {
    },
    builder: (context, state) {
      return Scaffold(
        backgroundColor: context.theme.appColors.white,
        body: Listener(
          onPointerDown: gestureHandler.onPointerDown,
          onPointerMove: gestureHandler.onPointerMove,
          onPointerUp: gestureHandler.onPointerUp,
          behavior: HitTestBehavior.translucent,
          child: InAppWebView(
            gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
              Factory<LongPressGestureRecognizer>(
                () => LongPressGestureRecognizer(),
              ),
            },
            contextMenu: _createContextMenu(),
            initialUrlRequest: URLRequest(
              url: WebUri("//$readerPath"),
            ),
            initialSettings: InAppWebViewSettings(
              javaScriptEnabled: true,
              disableContextMenu: false,
              // ... other settings
            ),
            onWebViewCreated: (controller) {
              myCubit.webViewController = controller;
              controller.setContextMenu(_createContextMenu());
            },
          ),
        ),
      );
    },
  );
}

ContextMenu _createContextMenu() {
  return ContextMenu(
    menuItems: [
      ContextMenuItem(id: 1, title: CONTEXT_MENU_1),
      // Other items...
    ],
    settings: ContextMenuSettings(hideDefaultSystemContextMenuItems: true),
    onCreateContextMenu: (hitTestResult) async {
      isContextMenuOpen.value = true;
      // Show custom menu...
    },
    onContextMenuActionItemClicked: (menuItem) async {
      _menuItemClicked(menuItem.id);
    },
  );
}

void _menuItemClicked(int itemId) {
  try {
    switch (itemId) {
      case 1:
        style = InterfaceConst.OPTION_1;
    }
  }
}

核心疑问

  1. 这个崩溃是否和iOS 18中UIEditMenuInteraction的变化有关?
  2. 如何安全地在InAppWebView中覆盖或扩展iOS原生上下文菜单?
  3. 使用flutter_inappwebview时,同时使用原生+自定义菜单是否有已知问题或临时解决方案?

问题解答

1. 崩溃是否与iOS 18的UIEditMenuInteraction变化相关?

是的。iOS 18对UIEditMenuInteraction的内部回调逻辑、菜单选择后的事件传递流程做了不少底层调整。你使用的flutter_inappwebview 6.1.5是一个相对老旧的版本,没有适配iOS 18的这些新变化,导致原生层的UICommand performWithSender:target:调用与Flutter侧的手势识别、自定义菜单回调逻辑发生冲突——比如手势识别器拦截了原生菜单的事件,或者自定义菜单的回调没有正确绑定到原生层的处理逻辑,最终触发了异常调用(崩溃日志中的Missing帧也侧面说明原生符号与Flutter侧的交互出现了不兼容)。

2. 如何安全覆盖/扩展iOS原生上下文菜单?

可以从以下几个方面优化:

  • 优先升级依赖版本:尽快升级flutter_inappwebview到最新稳定版(比如v7.x系列,该系列已经针对iOS 18做了适配),新版本通常会修复这类系统版本适配问题。
  • 避免手势识别器冲突:你自定义的LongPressGestureRecognizer可能和iOS原生上下文菜单的长按触发逻辑冲突。可以尝试调整手势的延迟时间(比如LongPressGestureRecognizer(duration: const Duration(milliseconds: 500))),或者通过gestureRecognizers的配置,让原生菜单的长按事件优先被处理。
  • 规范上下文菜单回调逻辑:确保onCreateContextMenu和onContextMenuActionItemClicked中的操作是异步安全的,比如更新isContextMenuOpen这类状态时,要保证在Flutter UI线程执行;不要在回调中做阻塞UI的同步操作。
  • 选择合适的菜单实现方式:如果需要完全自定义菜单,建议设置disableContextMenu: true,直接使用Flutter原生的PopupMenu或自定义弹窗,彻底避免与iOS原生菜单的交互冲突;如果需要保留部分原生菜单功能,不要设置hideDefaultSystemContextMenuItems: true后又依赖原生菜单的未实现逻辑。

3. 已知问题与临时解决方案

  • 已知问题:flutter_inappwebview v6.x系列在iOS 18上,当同时配置自定义手势识别器和自定义上下文菜单时,容易出现事件传递冲突,触发原生层崩溃。
  • 临时解决方案:
    • 临时移除自定义的LongPressGestureRecognizer,改用InAppWebView原生的长按触发逻辑,验证是否还会崩溃。如果问题消失,说明手势冲突是核心原因,再调整手势的优先级或范围。
    • 暂时将disableContextMenu设为true,完全切换到Flutter侧的自定义菜单,绕过原生菜单的适配问题。
    • 在_menuItemClicked方法中完善异常处理:当前的try块没有捕获任何异常类型,也没有catch分支,建议补充catch (e)逻辑,避免未处理的异常从Flutter侧渗透到原生层导致崩溃。
    • 调整Listener的HitTestBehavior:将translucent改为HitTestBehavior.deferToChild,确保InAppWebView能优先接收原生事件,避免事件被Listener拦截。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 13:08:08