Flutter Webview — перехват событий touchstart на Android

Эта ошибка, опубликованная на Github, похоже, предполагает, что touch events намеренно скрыты в реализации Android якобы чтобы включить обнаружение longpresses для целей копирования/вставки.

Моему собственному приложению абсолютно необходимо иметь возможность перехватывать события касания, а выделение текста при длительном нажатии не имеет никакого значения. Я думал, что сделаю это, используя локальную копию кода реализации Flutter webview, а затем отключив фильтр longpress. Соответствующий код в webview_android.dart читается

Мы предотвращаем выделение текста, перехватывая событие длительного нажатия. Это временная задержка из-за проблем с выделением текста на Android: https://github.com/flutter/flutter/issues/24585 — диалог выбора текста не реагирует на сенсорные события. https://github.com/flutter/flutter/issues/24584 — текст ручки выбора не отображаются. TODO (амирх): удалите это, когда проблемы, описанные выше, будут устранены. onLongPress: () {},

С этой целью я загрузил исходный код Flutter и убедился, что webview_flutter доступен в папке с этим именем на два уровня ниже корневой папки моего проекта Flutter. После изменения pubspec.yaml для чтения

  webview_flutter:
    path: ../../webview_flutter

и при запуске flutter clean && flutter run APK был создан и установлен на моем тестовом устройстве. Однако затем сообщалось

Настройка FlutterEngine. D/FlutterActivityAndFragmentDelegate(24999): предпочтительный FlutterEngine не указан. Создание нового FlutterEngine для этого FlutterFragment. W/FlutterEngine(24999): Попытка автоматически зарегистрировать плагины с помощью FlutterEngine (io.flutter.embedding.engine.FlutterEngine@9480b1a), но не удалось найти и вызвать GeneratedPluginRegistrant.

Я не понимаю это сообщение. Я был бы очень признателен всем, кто мог бы сказать мне, как/можно ли это исправить.


person DroidOS    schedule 08.04.2020    source источник


Ответы (2)


Теперь я случайно наткнулся на выход из проблемы «события без касания в Android», которую собака Flutter Webview. Вместо того, чтобы удалять мой вопрос, я подумал, что другим будет полезнее оставить его здесь с решением, которое я нашел.

Я начал с намерения самостоятельно перехватывать события Touch во Flutter, а затем передавать их в WebView через evaluateJavascript. С этой целью я изменил структуру своего виджета, чтобы обернуть WebView в прослушиватель. Весь код моего конструктора виджетов показан ниже.

@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 проблем. Мне непонятно только, почему это должно происходить - может быть, кто-то еще здесь объяснит.

Несколько замечаний по моему коду выше

  • Я использую WebViews, которые занимают весь экран устройства в ландшафтном формате — как на iOS, так и на Android
  • Я использую WidgetsApp, а не MaterialApp, чтобы обеспечить основные леса
  • SafeArea гарантирует, что приложение использует пространство, доступное ему на законных основаниях.
  • Прослушиватель — это то, что делает волшебство здесь и делает события Touch доступными в WebView даже на Android.
  • WebView является основным игроком, в котором происходит все действие. Во внешнем JavaScript вам просто нужно захватить события touchstart, touchmove и touchend в файле document.body.

Вы можете прочитать больше о различных виджетах, которые я использовал здесь, в Flutter Docs< /а>.

person DroidOS    schedule 08.04.2020

Вот что я обнаружил: насколько я могу судить, официальное веб-представление Flutter — заброшенный приемный ребенок. Есть ошибки трехлетней давности, которым уделялось мало внимания. Некоторые из его «функций», такие как longPress подавление/обнаружение, совершенно нелепы.

Я переключился на использование плагина Flutter Webview, который устраняет большинство проблем, с которыми я столкнулся. Только не забудьте включить withzoom:true. Я обнаружил, что веб-просмотр автоматически не перехватывает события 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, а приведенный выше код находится в классе с отслеживанием состояния, который он использует с with WidgetsBindingObserver.

person DroidOS    schedule 26.04.2020