dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.01k stars 1.72k forks source link

HTML5 video not working on MAUI WebView #4807

Closed RaspeR87 closed 1 year ago

RaspeR87 commented 2 years ago

Description

If I want to add video in my MAUI Blazor App I have a problem with rendering this video on iOS. On Android works well. I think the problem is in BlazorWebView component.

UPDATE This applies to all MAUI webviews, so is not Blazor-specific.

Steps to Reproduce

  1. Create a new blank .NET MAUI Blazor App

  2. Add some sample video mp4 file into the wwwroot/videos folder image

  3. Replace content of Index.razor page with content below:

    
    @page "/"

Hello, world!

Welcome to your new app.


3. Run app on Android. All good.
![image](https://user-images.githubusercontent.com/14901702/154914975-ef4909e1-85cc-4076-8693-83e583abd40a.png)

4. Run app on iPhone 12 (iOS 15.2) and nothing is shown where video could be.
![image](https://user-images.githubusercontent.com/14901702/154915088-3557e812-6048-464d-a553-d32a8402aa63.png)

### Version with bug

Preview 13 (current)

### Last version that worked well

Unknown/Other

### Affected platforms

iOS

### Affected platform versions

iPhone 12 iOS 15.2, Xcode 13.2.1, VS 17.2.0 Preview 1.0

### Did you find any workaround?

No

### Relevant log output

```shell
Nothing
jfversluis commented 2 years ago

Thanks for the report @RaspeR87 ! It would greatly help us if you were able to provide a little sample project demonstrating this issue in the form of a GitHub repository. Thanks!

RaspeR87 commented 2 years ago

@jfversluis of course, no problem. Here is simple sample: https://github.com/RaspeR87/MAUI/tree/main/Maui_Blazor_Html5_Video

jfversluis commented 2 years ago

Thank you for that! Had a quick look and here is the weird thing... If I add the controls attribute to the video to show the controls and actually click the play button it works just fine. So it seems like there is something preventing it from playing automatically. Not sure if this is a bug on our side then though.

RaspeR87 commented 2 years ago

@jfversluis is maybe something related with mediaTypesRequiringUserActionForPlayback? https://github.com/xamarin/xamarin-macios/issues/3137 https://docs.microsoft.com/es-es/dotnet/api/webkit.wkwebviewconfiguration.mediatypesrequiringuseractionforplayback?view=xamarin-ios-sdk-12

jfversluis commented 2 years ago

Yeah I tried that as well. And it seems important to set that before you change these values before assigning the config to the WKWebView, so I tried this in my own handler:

public class MyBlazorWebViewHandler : BlazorWebViewHandler
    {
        protected override WKWebView CreateNativeView()
        {
            var webview = base.CreateNativeView();

            var config = webview.Configuration;
            config.AllowsInlineMediaPlayback = true;
            config.MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.None;
            config.MediaPlaybackRequiresUserAction = false;

            return new WKWebView(RectangleF.Zero, config)
            {
                BackgroundColor = UIColor.Clear,
                AutosizesSubviews = true
            };
        }
    }

But it all seemingly has no effect.

One thing that stands out to me is that when I press the play button it loads for a relatively long time, so it seems the video is not even loaded yet. It doesn't even to attempt to load or autoplay. Not sure what that means, but it might be a hint for someone

SteveSandersonMS commented 2 years ago

@jfversluis @raspeR87 Would it be possible for you to try this with a plain MAUI WebView (not BlazorWebView) and see if the same issue occurs?

ghost commented 2 years ago

Hi @RaspeR87. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

RaspeR87 commented 2 years ago

@SteveSandersonMS @jfversluis no, it's not working on iOS platform with plain MAUI WebView too. It's working only on Android. Here is MAUI (not Blazor) sample with WebView: https://github.com/RaspeR87/MAUI/tree/main/Maui_Html5_Video

On iOS: Simulator Screen Shot - iPhone 12 Pro Max - 2022-02-23 at 13 41 21

On Android: Screenshot_1645620139

Does anyone have any idea?

jfversluis commented 2 years ago

Removed the Blazor label as it doesn't seem Blazor specific then.

It's interesting though, if you go to this URL from a WebView: https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_video_autoplay it doesn't work. But if you add the muted attribute and click the button to submit, it does work.

However, if you go to this page: https://googlechrome.github.io/samples/muted-autoplay/ which has the muted attribute it doesn't work.

RaspeR87 commented 2 years ago

@jfversluis I already have muted attribute on my example on github: https://github.com/RaspeR87/MAUI/tree/main/Maui_Html5_Video

I think in your example, when you add the muted attribute and click the button to submit, you make input action with this so you are OK with mediaPlaybackRequiresUserAction. And I think exactly the same is when you add controls attribute and you click play. But we want to have autoplay works on iOS too for example when you have video as background on your app.

v-longmin commented 2 years ago

Verifed reproes. repro project: [MauiApp1.zip](\mlangfs1\Public\dotnet maui\Repro Project)

vhj1995 commented 2 years ago

Verifed reproes. repro project: [MauiApp1.zip](\mlangfs1\Public\dotnet maui\Repro Project)

Hi, I am Glad you verified it. I too hit the same thing. Any idea on when a fix would publish?

vhj1995 commented 2 years ago

@jfversluis

Thank you.

When will next release be published?

How frequently are new releases is published in general? I need to have some expectations in terms of when apps can use local resources (Play mp4 on WebView), in particular loading from local disk.

jfversluis commented 2 years ago

@vhj1995 during the previews right now it has been once a month. After .NET MAUI goes GA, there will only be new versions once a year, every November together with the net .NET version.

rob-ack commented 2 years ago

There is maybe one hint that adds some additional value here.

(Its probably another issue i have and im not using latest MAUI but an early project version of Blazor Hybrid from which MAUI was invented from. But its probably related.)

MCF3389 commented 2 years ago

I've tried many ways to implement a video player with (a self-programmed) autoplay with blazor MAUI. It has been a very frustrating experience. Chromium is blocking a lot of actions (even though I tried to change it's properties), and other problems also arose on the way (e.g. not being able to trigger "onended" events). I'm now giving blazor MAUI a last shot by using the exo player (https://github.com/dotnet/maui/discussions/6026, https://www.nuget.org/packages/Xam.Plugins.Android.ExoPlayer.Ima/ ), but soon I will turn to a native solution and implement the Android App either with Java or another language.

If someone has found a good solution to implement autoplay on Android please let me know how.

dmccolloughOneGas commented 2 years ago

@jfversluis Gerald,

In reference to your comment about new version will only be once a year after GA.

If there are bugs that are fixed in maui after GA, are you saying that we won't receive any kind of release for fixed bugs but once a year?

Thanks

jfversluis commented 2 years ago

@dmccolloughOneGas lets try to not derail this issue with another topic, but that isn't the case. We have service released throughout the year. Bigger new features (mostly the rule of thumb is: whenever there is API changes or breaking changes) will only come once a year. Bugfixes will come throughout the year. For example, yesterday a new Visual Studio was released which has a new version of .NET MAUI with bugfixes!

Rahaaaa commented 2 years ago

Any update on this? I am creating an app with maui blazor, that has a camera recording feature,I am using RecordRTC(javascript library) I am able to record with the camera however I am running into the same issue on IOS, as soon as I assign the camera stream to the video tag, the video pops up into fullscreen mode, I've tried everything like playsinline, autoplay, muted and ...nothing works. I've seen some mentioned about a flag "allowsInlineMediaPlayback" that helps in this situation but I don't know how I can set it in BalzorWebView

MollsAndHersh commented 2 years ago

@MCF3389 @Rahaaaa... not sure if this aids either of you, but I just local video play working via these instructions: https://github.com/dotnet/maui/pull/7672. Autoplay is not working though.

MCF3389 commented 2 years ago

@MollsAndHersh @everybody : I've now switched to XAMARIN forms and am developing the app with the media element. Developing with xaml feels a bit different to using MAUI with web elements, but I'm making progress. At least I can now render the video with native UI and don't get into trouble. I hope that MAUI will also soon incorporate the media element (from the community toolkit), so that I can move the project to MAUI in the future.

cvalerio commented 2 years ago

Hi guys, I've banged my head on this issue for the last few days, because I really need my MAUI app to be able to play some videos (in my case the videos are downloaded and served via a custom IFileProvider like the InMemoryFileProvider in the samples, but had the same issues with videos embedded in the APK), but nothing worked. Until half an hour ago, when I've had an epiphany: I've said to myself "let's try to get the video through the fetch API, get the blob, then get the corresponding object URL and try to set THAT as the video source":

fetch('bunny.mp4')
   .then(async r => b = await r.blob())
   .then(b => document.querySelector('video').src = URL.createObjectURL(b));

Well, interestingly enough, this works :\

Checking the requests in DevTools, the only difference between the fetch request and the normal request that the video element does when setting the video in src attribute is that the latter adds these three headers to the request:

Accept-Encoding: identity;q=1, *;q=0
chrome-proxy: frfr
Range: bytes=0-

Range: bytes=0- basically, for what I know, are used by normal webservers for "chunking" the video request, allowing the video element to start the playback earlier, instead of waiting for all the video to have been downloaded. So it seems that the video element is expecting the "web server" to return a correct set of headers to play the video, but this doesn't happen. With fetch, instead, the whole video is retrieved and the blob object URL is served without the need of chunking.

Since I don't know if the video element has an attribute that prevents it's default chunking behavior, the only workaround for this issue that comes to my mind is as follows:


<video id="player" defer-src="bunny.mp4" autoplay loop muted></video>

<script>
   async function loadDeferred() {
      var player = document.querySelector('#player');
      var srcUrl = player.getAttribute('defer-src');
      var r = await (fetch(srcUrl);
      var blob = await r.blob();
      var blobUrl = URL.createObjectURL(blob);
      player.src = blobUrl;
   }

   loadDeferred();
</script>

Hope this helps.
ghost commented 2 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

KSemenenko commented 1 year ago

@cvalerio thanks for code snippet!

Redth commented 1 year ago

For iOS, it looks like we need to set some properties on the configuration object here: https://github.com/dotnet/maui/blob/0a07dab607fba5839ad31d7165bfea070229455d/src/Core/src/Platform/iOS/MauiWKWebView.cs#L108

Unfortunately you need to set these before you pass the configuration object to the web view constructor. Setting them after this will not work.

One idea is to create a builder configuration pattern to specify a delegate and have an opportunity to configure the WKWebViewConfiguration object before it's used in the ctor: ie: builder.ConfigureWebView(c => AllowsInlineMediaPlayback = true);

Alternatively (or in addition to), we can set some defaults on the web view configuration out of the box:

config.AllowsPictureInPictureMediaPlayback = true;
config.AllowsInlineMediaPlayback = true;
config.MediaTypesRequiringUserActionForPlayback = WebKit.WKAudiovisualMediaTypes.None;

There's more to investigate but that's the idea.

Redth commented 1 year ago

In the meantime, if you're looking to make this work today, in .NET 7, you can customize the platform view factory or WebViewHandler like this:

#if IOS || MACCATALYST
Microsoft.Maui.Handlers.WebViewHandler.PlatformViewFactory = (handler) =>
{
    var config = Microsoft.Maui.Platform.MauiWKWebView.CreateConfiguration();
    config.AllowsAirPlayForMediaPlayback = true;
    config.AllowsInlineMediaPlayback = true;
    config.AllowsPictureInPictureMediaPlayback = true;
    config.MediaTypesRequiringUserActionForPlayback = WebKit.WKAudiovisualMediaTypes.None;

    var wv = new Microsoft.Maui.Platform.MauiWKWebView(
        CoreGraphics.CGRect.Empty,
        handler as Microsoft.Maui.Handlers.WebViewHandler,
        config);

    return wv;
};
#endif
ghost commented 1 year ago

Hello lovely human, thank you for your comment on this issue. Because this issue has been closed for a period of time, please strongly consider opening a new issue linking to this issue instead to ensure better visibility of your comment. Thank you!

RNaves84 commented 1 year ago

how could i use this in blazorwebview?

In the meantime, if you're looking to make this work today, in .NET 7, you can customize the platform view factory or WebViewHandler like this:

if IOS || MACCATALYST

Microsoft.Maui.Handlers.WebViewHandler.PlatformViewFactory = (handler) => { var config = Microsoft.Maui.Platform.MauiWKWebView.CreateConfiguration(); config.AllowsAirPlayForMediaPlayback = true; config.AllowsInlineMediaPlayback = true; config.AllowsPictureInPictureMediaPlayback = true; config.MediaTypesRequiringUserActionForPlayback = WebKit.WKAudiovisualMediaTypes.None;

var wv = new Microsoft.Maui.Platform.MauiWKWebView(
    CoreGraphics.CGRect.Empty,
    handler as Microsoft.Maui.Handlers.WebViewHandler,
    config);

return wv;

};

endif