2

This issue posted on Github seems to suggest that touch events are deliberately suppressed in the Android implementation ostensibly to enable the detection of longpresses for the purposes of copy/paste.

My own application absolutely needs to be able to trap touch events - and longpress text selections have no relevance whatsoever. I thought I would do this by using a local copy of the Flutter webview implementation code, and then suppressing the longpress filter. The relevant code in webview_android.dart reads

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: () {},

To that end I downloaded the Flutter source and ensured that webview_flutter was available in a folder bearing that name two levels below my Flutter project root folder. After modifying pubspec.yaml to read

  webview_flutter:
    path: ../../webview_flutter

and running flutter clean && flutter run the APK was built and installed on my test device. However, it then reported

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.

I do not understand this message. I'd be most obliged to anyone who might be able to tell me how/whether it can be fixed.

DroidOS
  • 8,530
  • 16
  • 99
  • 171

2 Answers2

0

I have now accidentally stumbled upon a way out of the "no touch events in Android" issue that dog Flutter Webview. Rather than delete my question I felt it would be more useful to others to leave it here with the solution I have found.

I started off with the intention of trapping Touch events in Flutter myself and then transmitting them to the WebView via evaluateJavascript. To that end I changed my Widget structure so as to wrap the WebView in a Listener. My entire Widget builder code is shown below.

@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)]),
      ),
     ),
    )
   );
  });
 }

Much to my surprise simply doing this made the encpasulated Flutter WebView respond to touch# events with no pesky LongPress issues getting in the way. It is not clear to me just why this should happen - perhaps someone else here can explain.

A few notes on my code above

  • I use WebViews that take up the entire device screen in landscape format - both on iOS and on Android
  • I use WidgetsApp rather than MaterialApp to provide the basic scaffolding
  • SafeArea ensures that the app consumes space that is legitimately available to it
  • Listener is what does the magic here and makes Touch events available in WebView, even on Android
  • WebView is the main player here where all the action happens. In front end JavaScript you just need to capture touchstart, touchmove and touchend events on the document.body.

You can read up more on the various widgets I have used here in the Flutter Docs.

DroidOS
  • 8,530
  • 16
  • 99
  • 171
0

Here is what I have found: as far as I can tell the official Flutter webview is a neglected step child. There are bugs dating back three years that have received little attention. Some of its "features" such as longPress suppression/detection are downright ridiculous.

I switched to using Flutter Webview plugin which fixes most of the issues I had encountered. Just remember to enable withzoom:true. I found that the webview does not automatically trap onPause and onResume events. I handled this as follows

 @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 
   }
  });
 }

You will have to ensure that

  • You have a suitably initialized instance of the FlutterWebviewPlugin singleton
  • In your Javascript you have defined callBack

I should mention that I start from WidgetsApp and the above code is in the stateful class it uses with with WidgetsBindingObserver

halfer
  • 19,824
  • 17
  • 99
  • 186
DroidOS
  • 8,530
  • 16
  • 99
  • 171