maui icon indicating copy to clipboard operation
maui copied to clipboard

[regression/8.0.3] [iOS] [SDK 17] Touch events are not working on WebView when a PDF is displayed.

Open DevDachi opened this issue 1 year ago • 16 comments

Description

With iOS Sdk 17 / XCode 15, the WebView on iOS doesn't respond to any touch events (no zoom or scroll is possible) with PDF file. Works fine with any other html content.

Steps to Reproduce

  1. Create a new Maui App
  2. Add a web view control under a Grid Element to the Xaml
        <Grid>
            <WebView Grid.Row="0" x:Name="WebView"
                Source="https://www.africau.edu/images/default/sample.pdf">
             </WebView>
       </Grid>
  1. Launch the App on iOS (16 or 17)

Actual: PDF file is rendered but no touch events are working on WebView (No scroll, no Zoom).

Expected: Should be able to zoom or scroll.

Notes:

  • Rendering a webpage works fine without any issue (e.g. www.bing.com)
  • This worked fine before updating to Microsoft.iOS SDK / XCode 15 for SDK 17
  • Tested on .Net Maui Workload (8.0.0-rc.2.9511, 8.0.0-rc.2.9530) and both are impacted.

Link to public reproduction project repository

No response

Version with bug

8.0.0-rc.2.9511

Is this a regression from previous behavior?

Yes, this used to work in .NET MAUI

Last version that worked well

8.0.0-rc.2.9373

Affected platforms

iOS

Affected platform versions

iOS (All versions)

Did you find any workaround?

No :(

Relevant log output

No response

DevDachi avatar Nov 13 '23 17:11 DevDachi

Trying this on Catalyst, it happens there as well. It also happens when wrapping the webview inside of other controls (Grid, StackLayout, etc), but seems fine inside ContentView. If the WebView is the root of the page, it should also work. It's specifically when incase in other views.

PDF embedding generates a special UIKit view, one of the other elements could be capturing the touch contents and not passing them forward.

drasticactions avatar Nov 14 '23 20:11 drasticactions

Thanks @drasticactions for the confirmation. This is a regression from RC2 to GA. Can you help get this triaged?

DevDachi avatar Nov 16 '23 05:11 DevDachi

@rolfbjarne Does this look like an iOS change?

samhouts avatar Dec 07 '23 19:12 samhouts

@rolfbjarne Does this look like an iOS change?

No, not if it happens on both iOS 16 and 17:

Launch the App on iOS (16 or 17)

I don't think it's a bug on our side either, I can't remember any relevant changes this late in the .NET 8 time frame.

@drasticactions does this happen in a plain iOS (non-MAUI) project?

rolfbjarne avatar Dec 11 '23 07:12 rolfbjarne

@rolfbjarne I couldn't reproduce it in one. If I have the RootViewController to contain a WKWebView, and load the PDF, touch events pass through and it works. Within MAUI it also works if the WebView is the top most level view. It's when you nest it within other controls (Like Grid) where it breaks, which leads me to think this is an MAUI issue with how it handles touch events.

drasticactions avatar Dec 11 '23 08:12 drasticactions

@PureWeen is this maybe related to your mac gestures fixes?

mattleibow avatar Dec 11 '23 15:12 mattleibow

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

ghost avatar Dec 11 '23 15:12 ghost

i have the exactly same problem on my side. Inside a grid or any other layout it is not working to interact with the webview presenting a PDF. As i move it out to the root, its working.

This was working with SDK 8.0.100-rc.2. After update to SDK 8.0.100 this bug appears.

stoff99 avatar Jan 08 '24 14:01 stoff99

@DevDachi did you found any workaround here? I open a popup (Maui Community Toolkit) to show the PDF. So i need a Close button as well. In this case i cannot place the webview in the root ... My release is fully blocked now with this bug ...

stoff99 avatar Jan 08 '24 14:01 stoff99

For everybody struggle with the same issue, i created now a ViewHandler for the iOS WebView and placed a close UIButton there. In this case i can keep the outer structure flat and place only the WebView inside of the popup. If you need detailed infos just write me a pm.

stoff99 avatar Jan 10 '24 15:01 stoff99

@stoff99 could you please share how you solved the problem?

thanks

last-Programmer avatar Jan 12 '24 11:01 last-Programmer

Hello @last-Programmer ,

i created a ViewHandler for iOS: Here is the Code:

`using CoreGraphics; using Foundation; using Microsoft.Maui.Handlers; using PlentycoMaui.Logger; using UIKit; using WebKit;

namespace PlentycoMaui.iOS;

public class PdfViewHandler : ViewHandler<IPdfView, WKWebView> { private static readonly PropertyMapper<IPdfView, PdfViewHandler> PfgViewMapper = new(ViewMapper); private WKWebView _wkWebView; private UIButton _closeButton; private const int ButtonSize = 50; public PdfViewHandler() : base(PfgViewMapper) { }

protected override WKWebView CreatePlatformView()
{
    try
    {
        if (_wkWebView == null)
        {
            var wkWebViewConfiguration = new WKWebViewConfiguration();
            _wkWebView = new WKWebView(CGRect.Empty, wkWebViewConfiguration)
            {
                AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
            };

            _wkWebView.Configuration.Preferences.SetValueForKey(Foundation.NSObject.FromObject(true), (Foundation.NSString)"allowFileAccessFromFileURLs");
        }

        // We implemented this solution on the 10.01.2024 because if we put the close button and the pdf view inside any grid or layout, the touch events are gone in the pdf view. 
        // We can revert this solution when the ticket is fixed https://github.com/dotnet/maui/issues/18716
        CreateCloseButton();

        var url = new NSUrl(VirtualView.PdfUri, false);
        _wkWebView.LoadFileUrl(url, url);
    }
    catch (Exception e)
    {
        Log.Error(e.Message, e.StackTrace, e);
    }


    return _wkWebView;
}

private void CreateCloseButton()
{
    if (_closeButton != null)
    {
        return;
    }

    _closeButton = new UIButton(UIButtonType.Custom);
    _closeButton.Frame = new CGRect(UIScreen.MainScreen.Bounds.Width - ButtonSize - 4, 4, ButtonSize, ButtonSize);
    _closeButton.BackgroundColor = FromHex("#D71065");

    _closeButton.Layer.CornerRadius = ButtonSize / 2;

    var label = new UILabel(new CGRect(0, 0, _closeButton.Frame.Width, _closeButton.Frame.Height));
    label.Text = "X";
    label.TextColor = UIColor.White;
    label.Font = UIFont.SystemFontOfSize(24);
    label.TextAlignment = UITextAlignment.Center;
    label.Center = new CGPoint(_closeButton.Frame.Width / 2, _closeButton.Frame.Height / 2);

    _closeButton.AddSubview(label);
    _wkWebView.Add(_closeButton);
    _closeButton.TouchDown += CloseButtonTouchDown;
    _closeButton.TouchUpOutside += CloseButtonTouchUpOutside;
    _closeButton.TouchUpInside += CloseButtonTouchUpInside;
}


private void CloseButtonTouchDown(object sender, EventArgs ev)
{
    if (_closeButton == null)
    {
        return;
    }

    try
    {
        _closeButton.Alpha = 0.7f;
    }
    catch (Exception e)
    {
        Log.Error(e.Message, e.StackTrace, e);
    }
}

private void CloseButtonTouchUpOutside(object sender, EventArgs e)
{
    if (_closeButton == null)
    {
        return;
    }

    try
    {
        _closeButton.Alpha = 1.0f;
    }
    catch (Exception ex)
    {
        Log.Error(ex.Message, ex.StackTrace, ex);
    }
}

private void CloseButtonTouchUpInside(object sender, EventArgs ev)
{
    try
    {
        if (VirtualView.Close != null)
        {
            VirtualView.Close();
        }

        if (_closeButton == null)
        {
            return;
        }

        _closeButton.Alpha = 1.0f;
    }
    catch (Exception e)
    {
        Log.Error(e.Message, e.StackTrace, e);
    }
}

public override Size GetDesiredSize(double widthConstraint, double heightConstraint)
{
    try
    {
        if (_closeButton != null)
        {
            _closeButton.Frame = new CGRect(widthConstraint / 2 - ButtonSize / 2, heightConstraint - ButtonSize - 4, ButtonSize, ButtonSize);
        }
    }
    catch (Exception e)
    {
        Log.Error(e.Message, e.StackTrace, e);
    }

    return base.GetDesiredSize(widthConstraint, heightConstraint);
}

protected override void DisconnectHandler(WKWebView platformView)
{
    base.DisconnectHandler(platformView);

    try
    {
        if (_closeButton != null)
        {
            _closeButton.TouchDown -= CloseButtonTouchDown;
            _closeButton.TouchUpInside -= CloseButtonTouchUpInside;
            _closeButton.TouchUpOutside -= CloseButtonTouchUpOutside;
        }

        _wkWebView?.Dispose();
    }
    catch (Exception e)
    {
        Log.Error(e.Message, e.StackTrace, e);
    }
}

private UIColor FromHex(string hex)
{
    hex = hex.TrimStart('#');

    if (hex.Length == 6)
    {
        int r = int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
        int g = int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
        int b = int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);

        return UIColor.FromRGB(r, g, b);
    }

    return UIColor.Red;
}

}`

stoff99 avatar Jan 12 '24 11:01 stoff99

i don't know why the code is not correctly formatted here ...

Just keep in mind that i load local pdf's, not hosted once. So in this case you have to change the call of _wkWebView.LoadFileUrl(url, url);

stoff99 avatar Jan 12 '24 12:01 stoff99

You can use pdfjshttps://github.com/mozilla/pdf.js.

Workground for me


寄件者: last-Programmer @.> 寄件日期: 2024年1月12日 下午 07:55 收件者: dotnet/maui @.> 副本: ea543 @.>; Manual @.> 主旨: Re: [dotnet/maui] [regression/8.0.3] [iOS] [SDK 17] Touch events are not working on WebView when a PDF is displayed. (Issue #18716)

@stoff99https://github.com/stoff99 could you please share how you solved the problem?

thanks

— Reply to this email directly, view it on GitHubhttps://github.com/dotnet/maui/issues/18716#issuecomment-1888977929, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AHMICZJ73CY5TTH4TEAUIULYOEQDBAVCNFSM6AAAAAA7JRMB2CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOBYHE3TOOJSHE. You are receiving this because you are subscribed to this thread.

ea543 avatar Jan 12 '24 17:01 ea543

A slightly more involved solution, but I ended up resolving this by creating a custom control that implements PDFView from PDFKit instead of using WkWebView for iOS.

This solution provides an equal user experience and allows you to leverage the other features of PDFKit if needed.

This repo by @vitalii-vov has a great example on how you can implement this: https://github.com/vitalii-vov/Maui.PDFView/blob/master/Maui.PDFView/Platforms/iOS/PdfViewHandler.cs


For the Android implementation of this control, I used a WebView with pdf.js by Mozilla.

This blog outlines how you can implement pdf.js in Xamarin.Forms: https://medium.com/medialesson/show-pdf-files-in-your-xamarin-android-app-3718148de1c0

These steps can be adapted to use .NET MAUI handlers fairly simply.


I didn't need to implement this control for Mac or Windows but imagine PDFKit would work the same for Mac and a similar WebView solution would work for Windows.

For more info on creating custom controls from scratch see Create a custom control using handlers.

eth-ellis avatar Feb 15 '24 11:02 eth-ellis

I am migrating from Xamarin to .NET MAUI 8.0.2. I use the WebView for viewing local pdf files in iOS and it used to work fine. The WebView is the only control inside a ContentPage. Scrolling didn't work now in MAUI. Wrapping the WebView inside a Grid didn't work either. But luckily I read the comment of @drasticactions that it seems to work when wrapping it inside a ContentView. And I can confirm it indeed works. So that saved me from creating a new control like @eth-ellis did (although nice to learn the preferred way create such control)

JaapMosselman avatar Mar 13 '24 14:03 JaapMosselman

I can confirm that it is fixed in 8.060 nightly build.

last-Programmer avatar May 15 '24 23:05 last-Programmer