Flutter Webview - 在 Android 上捕获 touchstart 事件
Flutter Webview - trapping touchstart events on Android
在 Github 上发布的这个 issue 似乎暗示 touch events
在 Android 实现中被故意抑制,表面上是为了能够检测 longpresses
copy/paste 的目的。
我自己的应用程序绝对需要能够捕获触摸事件 - 长按文本选择没有任何相关性。我想我会通过使用 Flutter webview implementation code 的本地副本,然后抑制 longpress
过滤器来做到这一点。 webview_android.dart
中的相关代码为
We prevent text selection by intercepting the long press event.
This is a temporary stop gap due to issues with text selection on Android:
https://github.com/flutter/flutter/issues/24585 - the text selection
dialog is not responding to touch events.
https://github.com/flutter/flutter/issues/24584 - the text selection
handles are not showing.
TODO(amirh): remove this when the issues above are fixed.
onLongPress: () {},
为此,我下载了 Flutter 源代码,并确保 webview_flutter
在我的 Flutter 项目根文件夹下两层的文件夹中可用。将pubspec.yaml
修改为
后
webview_flutter:
path: ../../webview_flutter
和 运行 flutter clean && flutter run
APK 已构建并安装在我的测试设备上。然而,它随后报告
Setting up FlutterEngine.
D/FlutterActivityAndFragmentDelegate(24999): No preferred FlutterEngine was provided. Creating a new
FlutterEngine for this FlutterFragment.
W/FlutterEngine(24999): Tried to automatically register plugins with FlutterEngine
(io.flutter.embedding.engine.FlutterEngine@9480b1a) but could not find and invoke the
GeneratedPluginRegistrant.
我不明白这条消息。如果有人能告诉我 how/whether 它可以修复,我将不胜感激。
我现在偶然发现了解决 Flutter Webview 问题的方法 "no touch events in Android"。我觉得与其删除我的问题,不如将其与我找到的解决方案一起留在这里对其他人更有用。
我开始打算自己在 Flutter 中捕获 Touch 事件,然后通过 evaluateJavascript
将它们传输到 WebView。为此,我更改了 Widget 结构,以便将 WebView 包装在 Listener 中。我的整个 Widget 构建器代码如下所示。
@override Widget build(BuildContext context)
{
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
return WidgetsApp
(
onGenerateRoute:makeWebView,
color:Color.fromRGBO(0,128,255,1.0)
);
}
Route makeWebView(RouteSettings settings)
{
return new PageRouteBuilder
(
pageBuilder:(BuildContext context,Animation<double> animation,Animation<double>
secondaryAnimation)
{
return SafeArea
(
child:Listener
(
child: SizedBox.expand
(
child:WebView
(
debuggingEnabled:true,
initialUrl:'',
javascriptMode:JavascriptMode.unrestricted,
onWebViewCreated:registerController,
javascriptChannels:Set.from
([JavascriptChannel(name:'JSBridge',onMessageReceived:handleMessage)]),
),
),
)
);
});
}
令我惊讶的是,仅仅这样做就可以使封装的 Flutter WebView 响应 touch#
事件,而不会遇到任何令人讨厌的 LongPress
问题。我不清楚为什么会发生这种情况 - 也许这里的其他人可以解释。
关于我上面的代码的几点说明
- 我使用以横向格式占据整个设备屏幕的 WebView - iOS 和 Android
- 我使用 WidgetsApp 而不是 MaterialApp 来提供基本的脚手架
- SafeArea 确保该应用使用合法可用的 space
- Listener 是这里的魔法所在,它使 Touch 事件在 WebView 中可用,即使在 Android
上也是如此
- WebView 是所有操作发生的主要参与者。在前端 JavaScript 你只需要在
document.body
. 上捕获 touchstart
、touchmove
和 touchend
事件
您可以在 Flutter Docs.
中阅读更多关于我在这里使用的各种小部件的信息
以下是我的发现:据我所知,官方 Flutter webview 是一个被忽视的继子。有些错误可以追溯到三年前,但很少受到关注。它的一些 "features" 例如 longPress
suppression/detection 是彻头彻尾的荒谬。
我改用 Flutter Webview plugin 解决了我遇到的大部分问题。请记住启用 withzoom:true
。我发现 webview 不会自动捕获 onPause
和 onResume
事件。我是这样处理的
@override void didChangeAppLifecycleState(AppLifecycleState state)
{
setState(()
{
appState = state;
switch(state)
{
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
FlutterWebviewPlugin.evalJavascript('callBack()');break;//onPause
case AppLifecycleState.resumed:
FlutterWebviewPlugin.evalJavascript('callBack()');break;//onResume
}
});
}
您必须确保
- 您有一个适当初始化的
FlutterWebviewPlugin
单例 实例
- 在您的 Javascript 中您定义了
callBack
我应该提一下,我是从 WidgetsApp
开始的,上面的代码在有状态 class 中,它与 with WidgetsBindingObserver
一起使用
在 Github 上发布的这个 issue 似乎暗示 touch events
在 Android 实现中被故意抑制,表面上是为了能够检测 longpresses
copy/paste 的目的。
我自己的应用程序绝对需要能够捕获触摸事件 - 长按文本选择没有任何相关性。我想我会通过使用 Flutter webview implementation code 的本地副本,然后抑制 longpress
过滤器来做到这一点。 webview_android.dart
中的相关代码为
We prevent text selection by intercepting the long press event. This is a temporary stop gap due to issues with text selection on Android: https://github.com/flutter/flutter/issues/24585 - the text selection dialog is not responding to touch events. https://github.com/flutter/flutter/issues/24584 - the text selection handles are not showing. TODO(amirh): remove this when the issues above are fixed. onLongPress: () {},
为此,我下载了 Flutter 源代码,并确保 webview_flutter
在我的 Flutter 项目根文件夹下两层的文件夹中可用。将pubspec.yaml
修改为
webview_flutter:
path: ../../webview_flutter
和 运行 flutter clean && flutter run
APK 已构建并安装在我的测试设备上。然而,它随后报告
Setting up FlutterEngine. D/FlutterActivityAndFragmentDelegate(24999): No preferred FlutterEngine was provided. Creating a new FlutterEngine for this FlutterFragment. W/FlutterEngine(24999): Tried to automatically register plugins with FlutterEngine (io.flutter.embedding.engine.FlutterEngine@9480b1a) but could not find and invoke the GeneratedPluginRegistrant.
我不明白这条消息。如果有人能告诉我 how/whether 它可以修复,我将不胜感激。
我现在偶然发现了解决 Flutter Webview 问题的方法 "no touch events in Android"。我觉得与其删除我的问题,不如将其与我找到的解决方案一起留在这里对其他人更有用。
我开始打算自己在 Flutter 中捕获 Touch 事件,然后通过 evaluateJavascript
将它们传输到 WebView。为此,我更改了 Widget 结构,以便将 WebView 包装在 Listener 中。我的整个 Widget 构建器代码如下所示。
@override Widget build(BuildContext context)
{
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
return WidgetsApp
(
onGenerateRoute:makeWebView,
color:Color.fromRGBO(0,128,255,1.0)
);
}
Route makeWebView(RouteSettings settings)
{
return new PageRouteBuilder
(
pageBuilder:(BuildContext context,Animation<double> animation,Animation<double>
secondaryAnimation)
{
return SafeArea
(
child:Listener
(
child: SizedBox.expand
(
child:WebView
(
debuggingEnabled:true,
initialUrl:'',
javascriptMode:JavascriptMode.unrestricted,
onWebViewCreated:registerController,
javascriptChannels:Set.from
([JavascriptChannel(name:'JSBridge',onMessageReceived:handleMessage)]),
),
),
)
);
});
}
令我惊讶的是,仅仅这样做就可以使封装的 Flutter WebView 响应 touch#
事件,而不会遇到任何令人讨厌的 LongPress
问题。我不清楚为什么会发生这种情况 - 也许这里的其他人可以解释。
关于我上面的代码的几点说明
- 我使用以横向格式占据整个设备屏幕的 WebView - iOS 和 Android
- 我使用 WidgetsApp 而不是 MaterialApp 来提供基本的脚手架
- SafeArea 确保该应用使用合法可用的 space
- Listener 是这里的魔法所在,它使 Touch 事件在 WebView 中可用,即使在 Android 上也是如此
- WebView 是所有操作发生的主要参与者。在前端 JavaScript 你只需要在
document.body
. 上捕获
touchstart
、touchmove
和 touchend
事件
您可以在 Flutter Docs.
中阅读更多关于我在这里使用的各种小部件的信息以下是我的发现:据我所知,官方 Flutter webview 是一个被忽视的继子。有些错误可以追溯到三年前,但很少受到关注。它的一些 "features" 例如 longPress
suppression/detection 是彻头彻尾的荒谬。
我改用 Flutter Webview plugin 解决了我遇到的大部分问题。请记住启用 withzoom:true
。我发现 webview 不会自动捕获 onPause
和 onResume
事件。我是这样处理的
@override void didChangeAppLifecycleState(AppLifecycleState state)
{
setState(()
{
appState = state;
switch(state)
{
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
FlutterWebviewPlugin.evalJavascript('callBack()');break;//onPause
case AppLifecycleState.resumed:
FlutterWebviewPlugin.evalJavascript('callBack()');break;//onResume
}
});
}
您必须确保
- 您有一个适当初始化的
FlutterWebviewPlugin
单例 实例
- 在您的 Javascript 中您定义了
callBack
我应该提一下,我是从 WidgetsApp
开始的,上面的代码在有状态 class 中,它与 with WidgetsBindingObserver