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

HybridWebView/WebView - Implement methods for playsinline, autoplay, and other playback configuration options #23747

Open
jonmdev opened this issue Jul 21, 2024 · 0 comments

Comments

@jonmdev
Copy link

jonmdev commented Jul 21, 2024

Description

Now that HybridWebView (fantastic game changing component) is being implemented in .NET 9 (as per Eilon/MauiHybridWebView#70) I have a suggestion.

In order to set videos to play inline and autoplay, the working methods I have found are in current system:

1) iOS

Rewrite the platform view creation as follows using Reflection to access things we don't have access to. Run this anywhere before you create a HybridWebView to reconfigure the default construction.

#if IOS || MACCATALYST

            HybridWebView.HybridWebViewHandler.PlatformViewFactory = (handler) => {
                
                var config = new WKWebViewConfiguration();

                //====================================================
                //CUSTOM CONFIG
                config.AllowsAirPlayForMediaPlayback = true;
                config.AllowsInlineMediaPlayback = true;
                config.AllowsPictureInPictureMediaPlayback = true;
                config.MediaTypesRequiringUserActionForPlayback = WebKit.WKAudiovisualMediaTypes.None;


                Action<Uri, string> MessageReceivedAction = delegate (Uri uri, string message) { // to replace https://github.com/Eilon/MauiHybridWebView/blob/3ca801076a1e3fbe3b8922b2429524df20def6a4/HybridWebView/Platforms/iOS/HybridWebViewHandler.iOS.cs#L40
                    ((HybridWebView.HybridWebView)handler.VirtualView).OnMessageReceived(message);
                };

                //REFLECTION METHOD (https://stackoverflow.com/a/39076814/10305478)
                object CreatePrivateClassInstance(string typeName, object[] parameters) {
                    Type type = AppDomain.CurrentDomain.GetAssemblies().
                             SelectMany(assembly => assembly.GetTypes()).FirstOrDefault(t => t.Name == typeName);
                    return type.GetConstructors()[0].Invoke(parameters);
                }

                IWKScriptMessageHandler webViewScriptMessageHandler = (IWKScriptMessageHandler)CreatePrivateClassInstance("WebViewScriptMessageHandler", [MessageReceivedAction]);
                config.UserContentController.AddScriptMessageHandler(webViewScriptMessageHandler, "webwindowinterop");

                IWKUrlSchemeHandler? wKUrlSchemeHandler = (IWKUrlSchemeHandler?)CreatePrivateClassInstance("SchemeHandler", [handler as HybridWebViewHandler]);
                config.SetUrlSchemeHandler(wKUrlSchemeHandler, urlScheme: "app");
                //============================================


                // Legacy Developer Extras setting.
                var enableWebDevTools = ((HybridWebView.HybridWebView)(handler as HybridWebViewHandler).VirtualView).EnableWebDevTools;
                config.Preferences.SetValueForKey(NSObject.FromObject(enableWebDevTools), new NSString("developerExtrasEnabled"));
                var platformView = new MauiWKWebView(RectangleF.Empty, handler as HybridWebViewHandler, config);

                if (OperatingSystem.IsMacCatalystVersionAtLeast(major: 13, minor: 3) ||
                    OperatingSystem.IsIOSVersionAtLeast(major: 16, minor: 4)) {
                    // Enable Developer Extras for Catalyst/iOS builds for 16.4+
                    platformView.SetValueForKey(NSObject.FromObject(enableWebDevTools), new NSString("inspectable"));
                }

                return platformView;
            };
#endif

2) Windows

From: https://stackoverflow.com/questions/68709227/how-to-enable-media-autoplay-in-microsoft-webview2

#if WINDOWS
     Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--autoplay-policy=no-user-gesture-required");
#endif

Run this anywhere before creating hybridwebview. This one I believe must be set globally only like this, not per element.

3) Android

From: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/webview?view=net-maui-8.0&pivots=devices-android

(i) Create permission manager

#if ANDROID

    internal class MyWebChromeClient : MauiWebChromeClient {
        public MyWebChromeClient(IWebViewHandler handler) : base(handler) {

        }

        //note you need android permissions for android.permission.MODIFY_AUDIO_SETTINGS, android.permission.RECORD_AUDIO, and android.permission.CAMERA
        public override void OnPermissionRequest(PermissionRequest request) {
            Debug.WriteLine("CHECK MYWEBCHROMECLIENT PERMISSION");
            // Process each request
            foreach (var resource in request.GetResources()) {
                // Check if the web page is requesting permission to the camera
                if (resource.Equals(PermissionRequest.ResourceVideoCapture, StringComparison.OrdinalIgnoreCase)) {
                    // Get the status of the .NET MAUI app's access to the camera
                    PermissionStatus status = Permissions.CheckStatusAsync<Permissions.Camera>().Result;

                    // Deny the web page's request if the app's access to the camera is not "Granted"
                    if (status != PermissionStatus.Granted) {
                        request.Deny();
                    }
                    else {
                        request.Grant(request.GetResources());
                    }
                    return;
                }
                if (resource.Equals(PermissionRequest.ResourceAudioCapture, StringComparison.OrdinalIgnoreCase)) {
                    // Get the status of the .NET MAUI app's access to the camera
                    PermissionStatus status = Permissions.CheckStatusAsync<Permissions.Microphone>().Result;

                    // Deny the web page's request if the app's access to the camera is not "Granted"
                    if (status != PermissionStatus.Granted) {

                        request.Deny();
                    }

                    else {
                        request.Grant(request.GetResources());
                    }
                    return;
                }
            }

            base.OnPermissionRequest(request);
        }
    }
#endif

(ii) Apply to WebView via HandlerChanged

            webView.HandlerChanged += delegate {
#if ANDROID
                var platformView = (webView.Handler as HybridWebViewHandler).PlatformView;
                platformView.Settings.MediaPlaybackRequiresUserGesture = false; //this works to force autoplay https://stackoverflow.com/questions/38975229/auto-play-video-in-webview

                //set permission client as per: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/webview?view=net-maui-8.0&pivots=devices-android
                MyWebChromeClient permissionClient = new(webView.Handler as IWebViewHandler);
                platformView.SetWebChromeClient(permissionClient);
#endif
            };

It would be nice if we could allow each HybridWebView to have its own configuration method (or global configuration) built into the system.

Alternatively, I post this here as reference for working methods for anyone trying to configure this, and hope we at least won't lose these working methods in the new rebuild for .NET9 without alternatives to replace it.

Any thoughts @Eilon ?

Thanks again for the great component.

Public API Changes

Can have global static methods like:

HybridWebView.setPlaysInline(true);
HybridWebView.setAutoPlay(true);

or same functions run per webview (but note in iOS once the webview is constructed as above it is already too late unless we can pass in configuration info like a "HybridWebViewConfig" as an optional argument on construction).

Intended Use-Case

Allow autoplay, inline play, other possible platform specific playback features as part of the basic build in function. Or at least continue to be able to use what we have that works without it breaking by .NET 9 changes.

Thanks.

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

No branches or pull requests

2 participants