I encountered this silly problem in 2022, trying to run fullscreen embedded youTube and vimeo inside a webview in Android. And it took me days to solve...
My understanding is the webview in Android does not handle the 'go fullscreen' action of an embedded video out of the box like iOS does.
In the Android project, you need to write your own WebChromeClient that handles the OnShowCustomView and OnHideCustomView methods. Debug your app and you'll see these are fired when a user taps the fullscreen mode action inside the video frame.
I tried to implement a solution based on:
Webview and iFrame Video full screen issue
which sets the visibility of the customView and hides the content but it didn't quite work for the structure of the client's existing page
This answer fitted much better for me: Youtube Fullscreen without Iframe and allowed me to write xamarin code to push the fullscreen video into a modal and pop it out when you're done.
Grab their repo for lots more useful xamarin code!
Here are my code highlights. I hope they help you too!
Xamarin project:
public class HybridWebView : WebView
{
// ...
#region Fullscreen video on Android support
public static readonly BindableProperty EnterFullScreenCommandProperty =
BindableProperty.Create(
nameof(EnterFullScreenCommand),
typeof(ICommand),
typeof(FormBuilderWebView),
defaultValue: new Command(async (view) => await DefaultEnterAsync((View)view)));
public static readonly BindableProperty ExitFullScreenCommandProperty =
BindableProperty.Create(
nameof(ExitFullScreenCommand),
typeof(ICommand),
typeof(FormBuilderWebView),
defaultValue: new Command(async (view) => await DefaultExitAsync()));
/// <summary>
/// Gets or sets the command executed when the web view content requests entering full-screen.
/// The command is passed a <see cref="View"/> containing the content to display.
/// The default command displays the content as a modal page.
/// </summary>
public ICommand EnterFullScreenCommand
{
get => (ICommand)GetValue(EnterFullScreenCommandProperty);
set => SetValue(EnterFullScreenCommandProperty, value);
}
/// <summary>
/// Gets or sets the command executed when the web view content requests exiting full-screen.
/// The command is passed no parameters.
/// The default command pops a modal page off the navigation stack.
/// </summary>
public ICommand ExitFullScreenCommand
{
get => (ICommand)GetValue(ExitFullScreenCommandProperty);
set => SetValue(ExitFullScreenCommandProperty, value);
}
/// <summary>
/// Push the view into a page then as modal into the nav stack
/// </summary>
private static async Task DefaultEnterAsync(View view)
{
ContentPage page = new ContentPage
{
Content = view
};
await Application.Current.MainPage.Navigation.PushModalAsync(page);
}
/// <summary>
/// Pop the modal page from the nav stack
/// </summary>
private static async Task DefaultExitAsync()
{
await Application.Current.MainPage.Navigation.PopModalAsync();
}
#endregion
}
Android project:
public class MyWebChromeClient : global::Android.Webkit.WebChromeClient
{
// ...
#region For Full screen video...
/// <summary>
/// Triggered when the content requests full-screen.
/// </summary>
public event EventHandler<EnterFullScreenRequestedEventArgs> EnterFullscreenRequested;
/// <summary>
/// Triggered when the content requests exiting full-screen.
/// </summary>
public event EventHandler ExitFullscreenRequested;
/// <inheritdoc />
public override void OnHideCustomView()
{
ExitFullscreenRequested?.Invoke(this, EventArgs.Empty);
}
/// <inheritdoc />
public override void OnShowCustomView(Android.Views.View view, ICustomViewCallback callback)
{
EnterFullscreenRequested?.Invoke(this, new EnterFullScreenRequestedEventArgs(view));
}
#endregion
}
HybridWebViewRenderer.cs
public class HybridWebViewRenderer : WebViewRenderer
{
Context _context;
public HybridWebViewRenderer(Context context) : base(context)
{
_context = context;
}
HybridWebView webView;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
global::Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
if (e.NewElement != null)
{
webView = e.NewElement as HybridWebView;
Control.Settings.JavaScriptEnabled = true;
Control.Settings.AllowFileAccess = true;
Control.Settings.AllowContentAccess = true;
Control.Settings.AllowFileAccessFromFileURLs = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.SetWebViewClient(new MyWebViewClient());
Control.SetWebChromeClient(GetWebChromeClient());
}
}
/// <summary>
/// Creates a <see cref="MyWebChromeClient"/> that implements the necessary callbacks to support
/// full-screen operation.
/// </summary>
protected MyWebChromeClient GetWebChromeClient()
{
MyWebChromeClient client = new MyWebChromeClient();
client.EnterFullscreenRequested += OnEnterFullscreenRequested;
client.ExitFullscreenRequested += OnExitFullscreenRequested;
return client;
}
/// <summary>
/// Executes the full-screen command on the <see cref="FullScreenEnabledWebView"/> if available. The
/// Xamarin view to display in full-screen is sent as a command parameter.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="eventArgs">The event arguments.</param>
private void OnEnterFullscreenRequested(
object sender,
EnterFullScreenRequestedEventArgs eventArgs)
{
if (webView.EnterFullScreenCommand != null && webView.EnterFullScreenCommand.CanExecute(null))
{
webView.EnterFullScreenCommand.Execute(eventArgs.View.ToView());
}
}
/// <summary>
/// Executes the exit full-screen command on the <see cref="FullScreenEnabledWebView"/> if available.
/// The command is passed no parameters.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="eventArgs">The event arguments.</param>
private void OnExitFullscreenRequested(object sender, EventArgs eventArgs)
{
if (webView.ExitFullScreenCommand != null && webView.ExitFullScreenCommand.CanExecute(null))
{
webView.ExitFullScreenCommand.Execute(null);
}
}
}