Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tap events on iframe don't work on Android 10+ #465

Closed
tneotia opened this issue Dec 1, 2020 · 8 comments
Closed

Tap events on iframe don't work on Android 10+ #465

tneotia opened this issue Dec 1, 2020 · 8 comments

Comments

@tneotia
Copy link
Collaborator

tneotia commented Dec 1, 2020

If I have an iframe that displays a webview component on Android 10+, scrolling and tapping are both broken. The webview Container seems to respond to scroll events using this fix (the rest of the page doesn't scroll if you scroll on the webview "box"), however the webview itself still does not scroll.
Secondly, the webview doesn't even respond to tap events. Tapping on "images" or the google logo does nothing in the example app.

What's strange is that tap events work fine on my Android 9 device (Galaxy S8), but on my Android 10/11 device (Galaxy S10+), it doesn't work.

I also tried using customRender and a different webview plugin like this to achieve a custom youtube/actual iframe rendering method (replace any iframe tags with iframe1 otherwise the attributes come back as null):

"iframe1": (RenderContext context, Widget child, attributes, _) {
//check internet connection
  if (!result) {
    return Container(
      child: ListTile(
        leading: Icon(Icons.error, color: Colors.red),
        title: Text("Cannot load iframe. You are offline, please check connection and try again.")
      )
    );
  } else if (attributes != null) {
    double width = double.tryParse(attributes['width'] ?? "");
    double height = double.tryParse(attributes['height'] ?? "");
    print(attributes['src']);
//return a different sort of webview depending on whether it is an embedded youtube video or an actual iframe
    return Container(
      width: width ?? (height ?? 150) * 2,
      height: height ?? (width ?? 300) / 2,
      child: InAppWebView(
        initialUrl: attributes['src'].contains("youtube.com/embed") ? attributes['src'].startsWith("//") ? "https:${attributes['src']}" : attributes['src'] : attributes['src'],
        initialOptions: InAppWebViewGroupOptions(
          crossPlatform: InAppWebViewOptions(
            javaScriptEnabled: true,
            cacheEnabled: false,
//disable capturing scrolling events if yt video (allows user to scroll on webview container and the whole page scrolls along too)
            disableVerticalScroll: attributes['src'].contains("youtube.com/embed") ? true : false,
            disableHorizontalScroll: attributes['src'].contains("youtube.com/embed") ? true : false,
            useShouldOverrideUrlLoading: true,
          ),
          ios: IOSInAppWebViewOptions(
            allowsLinkPreview: false,
          ),
          android: AndroidInAppWebViewOptions(
//use new platformview rendering method if device is on Android 10+
            useHybridComposition: int.parse(Main.androidBuild.version.release) > 9 ? true : false,
          )
        ),
        gestureRecognizers: {
          Factory(() => VerticalDragGestureRecognizer())
        },
        shouldOverrideUrlLoading: (controller, request) async {
//do not allow other urls to load if embedded yt video, otherwise allow other urls
          if (attributes['src'].contains("youtube.com/embed")) {
            if (!request.url.contains("youtube.com/embed")) {
              return ShouldOverrideUrlLoadingAction.CANCEL;
            } else {
              return ShouldOverrideUrlLoadingAction.ALLOW;
            }
          } else {
            return ShouldOverrideUrlLoadingAction.ALLOW;
          }
        },
      ),
    );
//if no attributes, then don't display anything
  } else {
    return Container(height: 0);
  }
}

In this case, vertical drags are handled correctly on Android 10+ but tap events still don't work. I've tried a lot of different things with GestureRecognizers and removing/switching out the webview options but to no avail. There aren't any issues with the official webview_flutter or flutter_inappwebview plugins either AFAIK. Does anyone know how this can be fixed?
The only thing I can think of is that something is attaching itself to a TapGestureRecognizer (or something similar) and thus the webview can't attach itself to it... I could be wrong though.

@tneotia tneotia changed the title Tap events on iFrame don't work on Android 10+ Tap events on iframe don't work on Android 10+ Dec 1, 2020
@praharshbhatt
Copy link

Same issue in iFrame for me as well.

Although the image and links taps work perfectly. Please note that the click events are thrown in the logs, and you need to react to the clicks from your end.

@erickok erickok closed this as completed Jan 21, 2021
@erickok erickok reopened this Jan 21, 2021
@erickok
Copy link
Collaborator

erickok commented Jan 21, 2021

Will investigate, because it works for me in the minimal example app. Can you provide a minimal reproducible example? Are you using the Html widget in some particular other scroll container? And are you using the new Hybrid Composition or older platform view implementation?

@tneotia
Copy link
Collaborator Author

tneotia commented Jan 21, 2021

@erickok my Html widget is in a CustomScrollView > SliverList. I don't think this is affecting it because it works fine on Android 9 and below.
I think the thing causing it is the fact that I'm using Hybrid Composition in my full-screen webview, and maybe hybrid composition doesn't work in a container of that size. As I said in OP I tried setting hybrid composition on and off to no success via customRender. The one thing I didn't try is disabling hybrid composition in the rest of the app and seeing if that fixes it.

@erickok
Copy link
Collaborator

erickok commented Feb 8, 2021

I can't reproduce this (Android 11, Pixel 3). Even when I run on Hybrid Composition for the webview.

class _MyHomePageState extends State<MyHomePage> {

  @override
  void initState() {
    super.initState();
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(
        title: Text('flutter_html Example'),
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        child: Html(
          data: """
<p>HeadLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<p>HeadLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
      <h3>IFrame support:</h3>
      <iframe src="https://google.com" width='300' height='300'></iframe>
<p>HeadLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<p>HeadLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
""",
        ),
      ),
    );
  }
}

The iframe accepts scrolls and clicks and text input just fine. Can anyone produce a reproducible example?

@erickok
Copy link
Collaborator

erickok commented Mar 16, 2021

Please let us know if this problem persists, even in the example I supplied above. Or alternatively if you can provide a reproducable example of the issue, that would be great.

@erickok erickok closed this as completed Mar 16, 2021
@tneotia
Copy link
Collaborator Author

tneotia commented Mar 16, 2021

Sorry I keep forgetting about this one. My dev phone is android 9 (my personal phone is android 11 so I'll test on there).

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 17, 2021

@erickok the problem still persists for me. Simply add <iframe src="https://google.com"/> to the end of the example app HTML and try scrolling or tapping on the webview, and nothing happens.

Device:
Galaxy S10+, Android 11

Flutter doctor -v
[√] Flutter (Channel beta, 2.0.1, on Microsoft Windows [Version 10.0.19042.844], locale en-US)
    • Flutter version 2.0.1 at C:\flutter
    • Framework revision c5a4b4029c (12 days ago), 2021-03-04 09:47:48 -0800
    • Engine revision 40441def69
    • Dart version 2.12.0

[√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at C:\Users\tanay\AppData\Local\Android\sdk
    • Platform android-30, build-tools 30.0.2
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    • All Android licenses accepted.

[X] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[√] Android Studio (version 4.1.0)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

[√] VS Code (version 1.52.1)
    • VS Code at C:\Users\tanay\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.18.0

[√] Connected device (1 available)
    • Edge (web) • edge • web-javascript • Microsoft Edge 89.0.774.54

Edit: I tested on flutter_html master.

@praharshbhatt
Copy link

This issue still persists.
flutter_html_issues_465

I am trying to tap pause the youtube video, and start the vimeo video. The taps are only about 20% registered. When the taps are actually registered, the location of taps are also misread.

The youtube video is handled by YoutubePlayer widget.
The vimeo video is handled by WebView widget.

    return Html(
      data: html,
      customRenders: {
        iframeMatcher(): CustomRender.widget(widget: (renderContext, buildChildren) {
          final attributes = renderContext.tree.element?.attributes ?? {};
          final sources = <String?>[
            if (attributes['src'] != null) attributes['src'],
            ...ReplacedElement.parseMediaSources(
                renderContext.tree.element!.children),
          ];
          if (sources.first!.contains('youtube.com')) {
            return Container(
              width: MediaQuery.of(context).size.width * 0.8,
              height: MediaQuery.of(context).size.width * 0.8 * 9 / 16,
              child: YoutubePlayer(
                aspectRatio: 16 / 9,
                controller: YoutubePlayerController.fromVideoId(
                  videoId: YoutubePlayerController.convertUrlToId(sources.first!) ?? '',
                ),
              ),
            );
          }

          return SizedBox(
            height: MediaQuery.of(context).size.width,
            child: WebView(
              initialUrl: 'about:blank',
              javascriptMode: JavascriptMode.unrestricted,
              onWebViewCreated: (WebViewController webViewController) {
                print(sources);

                webViewController.loadHtmlString('<iframe src = "${sources.first}" />');
              },
            ),
          );
        }),
    );```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants