maui icon indicating copy to clipboard operation
maui copied to clipboard

MAUI BlazorWebView fails to establish WebRTC connection on Android due to insecure host (https://0.0.0.0)

Open steveo555 opened this issue 1 year ago • 12 comments

Description

Description: When creating a MAUI Blazor Hybrid app in .NET 8.0 and setting up a WebRTC connection between devices, the getUserMedia function in JavaScript works as expected on iOS and Windows platforms, allowing the video stream to be set up successfully.

However, on Android, the connection fails despite the necessary permissions being requested and assigned to the app. The issue arises because the BlazorWebView on Android requests access to the device through the host https://0.0.0.0, which Android treats as insecure, causing the connection to be blocked.

For multi-platform apps that require messaging and communication, this makes MAUI currently unsuitable on Android. There is no clear way to signal to Android that this is a secure connection, nor is there an option to override the default host when calling from the BlazorWebView.

Why this is a bug: This is not a feature request but a bug because the WebRTC setup works perfectly on iOS and Windows out of the box. WebRTC is a widely used standard, and MAUI needs to support it consistently across all platforms, including Android.

Expected Behavior:

The getUserMedia function should be able to request the device's media securely on Android, just as it does on iOS and Windows. MAUI should either treat the BlazorWebView as secure on Android or provide a way to override the default host (https://0.0.0.0) used in the WebRTC request.

Steps to Reproduce

Steps to Reproduce:

Create a new MAUI Blazor Hybrid app in .NET 8.0. Implement WebRTC using the getUserMedia function in JavaScript. Test the app on iOS, Windows, and Android devices. Observe that the connection works on iOS and Windows but fails on Android due to the insecure host issue. Environment:

.NET version: 8.0 MAUI version: (insert version) Platform: Android (failing), iOS and Windows (working)

Link to public reproduction project repository

No response

Version with bug

8.0.82 SR8.2

Is this a regression from previous behavior?

No, this is something new

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

14 and up

Did you find any workaround?

No workarounds currently work.

Relevant log output

14:03:20:299	[CameraManagerGlobal] Connecting to camera service
14:03:20:299	[VendorTagDescriptor] addVendorDescriptor: vendor tag id 11706189966126095484 added
14:03:20:299	[VendorTagDescriptor] addVendorDescriptor: vendor tag id 15055940602041719656 added
14:03:20:366	[CameraManagerGlobal] Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 1 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 2 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 20 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 21 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 23 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 3 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client com.samsung.android.smartface API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 4 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 52 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 56 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[DeviceStateManager] handleDeviceStateInfoChanged state=0, baseState=0
14:03:20:366	[CameraManagerGlobal] Camera 58 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 71 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 73 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366	[CameraManagerGlobal] Camera 90 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:422	[chromium] [INFO:CONSOLE(58)] "Error initializing camera: [object DOMException]", source: https://0.0.0.0/js/jsMessage.js (58)

steveo555 avatar Sep 13 '24 13:09 steveo555

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

github-actions[bot] avatar Sep 13 '24 13:09 github-actions[bot]

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

These are either not the same issue or have poor workarounds that have since been removed by losing access to various overloads.

steveo555 avatar Sep 13 '24 14:09 steveo555

Could you provide us with a sample project so we can investigate it further? Looking forward to your reply!

ninachen03 avatar Sep 14 '24 09:09 ninachen03

Please find attached project to test.

Run in Windows mode it will work, deploy to iPhone and it will also work, try deploying to Android phone you will get the error. https://0.0.0.0 is trying to get access to camera and fail.

MAUIBlazorWebRTCTTest.zip

steveo555 avatar Sep 15 '24 14:09 steveo555

@steveo555 How do you know that the use of https://0.0.0.0 is the root issue here?

Running your sample, I looked at that object DOMException and it's a NOT ALLOWED permission error. Your app does request permissions, but that's for the App itself. The webview itself needs to have those permissions set, which should be, I think, done in WebChromeClient (https://github.com/dotnet/maui/blob/b2c1d25f7a71197666c2053c1e40dbdea6049cc7/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs#L15-L98) which isn't happening.

So I think there's a bug here in MAUI with its Blazor Webview, but it seems like a permission error, unrelated to the host. Do you have a way to verify your claim?

drasticactions avatar Sep 17 '24 06:09 drasticactions

Hi Thanks for getting back to me.

@steveo555 How do you know that the use of https://0.0.0.0 is the root issue here?

Running your sample, I looked at that object DOMException and it's a NOT ALLOWED permission error. Your app does request permissions, but that's for the App itself. The webview itself needs to have those permissions set, which should be, I think, done in WebChromeClient (

https://github.com/dotnet/maui/blob/b2c1d25f7a71197666c2053c1e40dbdea6049cc7/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs#L15-L98

) which isn't happening. So I think there's a bug here in MAUI with its Blazor Webview, but it seems like a permission error, unrelated to the host. Do you have a way to verify your claim?

Thanks for the reply. Did you try adding this to the sample I gave and got it to work? I still get the error. Also I have collated the following....

"Android restricts access to certain web APIs, including those for camera access, to secure origins only."

Source: Chromium Security FAQ

"Certain web platform features are restricted to secure contexts. For example, the geolocation API and the getUserMedia API (for accessing the microphone and camera) are only available to secure origins."

Chromium Security FAQ

Android Developers Documentation "For apps targeting Android 6.0 (API level 23) and later, the system considers your app's activities to be secure by default, and secure origins are required for secure content."

https://developer.android.com/guide/webapps/security

Explanation: Android's WebView is based on Chromium and inherits its security policies. Both platforms restrict access to sensitive APIs like the camera to secure origins to protect user privacy and security.

"This means that web pages must be served over HTTPS with a valid certificate from a recognized Certificate Authority (CA)."

Source: W3C Secure Contexts Specification

"A context is considered secure when it is delivered securely and all the resources it loads are also delivered securely."

https://www.w3.org/TR/secure-contexts/#secure-context

MDN Web Docs on getUserMedia() For security reasons, getUserMedia() can only be used from a secure origin (HTTPS or localhost).

https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

Explanation: Secure origins are typically defined as HTTPS connections using valid SSL/TLS certificates issued by recognized CAs. This ensures encrypted communication and verified server identity.

"Using an insecure origin like https://0.0.0.0 will result in Android refusing permission requests for sensitive features like the camera."

Source: IANA Special-Purpose Address Registry "0.0.0.0/8 — This block denotes invalid or unknown addresses."

IANA IPv4 Special-Purpose Address Registry Let's Encrypt Documentation "Let's Encrypt can't issue certificates for 'localhost' or for IP addresses such as '127.0.0.1'." Let's Encrypt - Certificates for localhost

Explanation: The IP address 0.0.0.0 is non-routable and cannot have a valid SSL/TLS certificate issued to it. As a result, any HTTPS connection to 0.0.0.0 is considered insecure, and Android will deny permission requests from such origins. Additional References:

Google Developers on Secure Contexts:

"Starting with Chrome 47, getUserMedia() (for camera and microphone access) is only available from secure origins." Google Developers - Avoiding the Not Secure Warning in Chrome

Web Fundamentals - What is Considered a Secure Context?

"A context is considered secure when it is delivered securely and all the resources it loads are also delivered securely." Web Fundamentals - Secure Contexts

So from API 23 and above Andriod will also black https://0.0.0.0 from access to the camera.

That's why we need another mechanism to serve pages in the blazorwebview that allows either a certificate or localhost as the host.

Let me know what you think.

steveo555 avatar Sep 18 '24 14:09 steveo555

@steveo555 The Android link link you posted above 404s, and I couldn't find it on the Internet Archive.

Yes, by enabling the permissions to go through at the Android WebView level, I could get it to run:

https://github.com/drasticactions/maui/commit/16f9587099ef6a9ef2b9afce4a0e3bae8f740a51

This is because, as I wrote, the Android webview itself (As in, the actual Android WebView) is asking for permissions that would normally need to be handled by the developer with the web view. So you need two levels of permissions, for the app and for the WebView.

The MAUI WebView and Blazor WebView wrapper don't handle this event. With the MAUI WebView (The regular one with no direct Blazor Hybrid support), you can override the handler to pass in your own WebChromeClient, that can handle this event and allow the permissions through. You can't with the Blazor WebView since it's private.

There are conversations about changing 0.0.0.0 to something else, but I believe that's not your issue here. It would work if you were able to handle this event... that said, the code I wrote above is wrong. That, AFAIK, will allow all permission requests to go through, which you would never want to do (And 100% not want in the platform code itself).

So that would require coming up with a way to pass that event up the chain so you, the developer, can handle it. The right thing to do here is let you handle this event so you can see which webpage (since you could have IFrames or other content trying to get access for permissions) to then allow them to go through or not.

So in short:

  • I think this is a bug in MAUI and not your code
  • It involves you not being able to handle permissions in the Blazor/MAUI WebView for Android
  • It is unrelated to 0.0.0.0 (although that should be changed)
  • It would probably require a new API to surface this event (Which, AFAIK, is only in Android) within the MAUI/Blazor WebView.

@Eilon What do you think?

drasticactions avatar Sep 19 '24 17:09 drasticactions

I concur with your points and understand the implications. I apologize for any confusion caused earlier. The key issue is that using 0.0.0.0 as a host is not considered secure, and this approach will need to change if we aim to future-proof any permission-based APIs that Android may leverage in the future.

Ideally, the permissions that have been requested, approved, and applied to the native application should be propagated to the WebView component, as they are on Windows and iOS platforms. Alternatively, there should be an efficient method to obtain the necessary permissions within the WebView context without excessive complexity.

My immediate challenge is that I have an upcoming deadline for the Android version of my project, and I need to find an effective workaround for this issue. It does not create a positive impression to inform users that certain functionality is available only on iOS devices, with Android support "coming soon." Consequently, I may need to temporarily disable the iOS web call functionality to ensure consistency across platforms until a proper solution is implemented.

@drasticactions - Would you be able to modify the sample project I upload with the code you mentioned gets it working please?

steveo555 avatar Sep 20 '24 09:09 steveo555

Moving to the Backlog as a feature request. Specifically, we will consider adding ability to override this behavior in the WebView.

mkArtakMSFT avatar Sep 23 '24 18:09 mkArtakMSFT

MAUIBlazorWebRTCTTest.zip

Any news guys? I need to get this functionality out to the Android test group. I've added the

 public override void OnPermissionRequest(PermissionRequest? request)
		{
			request?.Grant(request.GetResources());
		}

but its still the same error.

Cheers

steveo555 avatar Oct 07 '24 11:10 steveo555

any work around for this issue? thanks

cdaligdig avatar Oct 23 '24 03:10 cdaligdig

any work around for this issue? thanks

Not yet as far as I am aware. .NET 9 preview has same issue.

steveo555 avatar Oct 24 '24 13:10 steveo555

Any news on this. There is still no workaround or way to get it working in Android. iOS still works fine.

steveo555 avatar Apr 16 '25 14:04 steveo555

@mkArtakMSFT anything here? This still exists in .net core 9

cbdg-mitch avatar Apr 20 '25 01:04 cbdg-mitch

@drasticactions @steveo555 Hey guys, just so I'm completely clear... it's not possible for WebRTC to function with MAUI Blazor currently?

soenneker avatar May 14 '25 00:05 soenneker

Just to be clear, it was working in iOS builds but not Android.

HOWEVER, in .NET 9.0 Release, it is now possible. I think they have changed the WebView to use 0.0.0.1 which, for now, the OS is allowing to access permissions as long as you override the WebView and have a custom handler to handle permission requests.

Like this:

#if IOS
using Foundation;
using WebKit;
using Microsoft.AspNetCore.Components.WebView.Maui;
using Microsoft.Maui.Handlers;

namespace ThePathfinderApp.Platforms.iOS;

public class CustomBlazorWebViewHandler : BlazorWebViewHandler
{
    protected override WKWebView CreatePlatformView()
    {
        var webView = base.CreatePlatformView();

        if (webView.Configuration != null)
        {
            webView.Configuration.AllowsInlineMediaPlayback = true;
            webView.Configuration.MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.None;
        }

        webView.AllowsBackForwardNavigationGestures = true;
        webView.ScrollView.Bounces = false;
        webView.AutoresizingMask = UIKit.UIViewAutoresizing.FlexibleDimensions;

        // Disable safe area
        webView.InsetsLayoutMarginsFromSafeArea = false;
        webView.LayoutMargins = new UIKit.UIEdgeInsets(0, 0, 0, 0);
        webView.ScrollView.ContentInsetAdjustmentBehavior = UIKit.UIScrollViewContentInsetAdjustmentBehavior.Never;
      
        return webView;
    }

}
#endif
 

And in your MainProgram.cs:

 builder.UseMauiApp<App>().ConfigureMauiHandlers(handlers => 
{ 
#if ANDROID handlers.AddHandler<BlazorWebView, CustomBlazorWebViewHandler>(); 
#endif 
}); 

Then, as long as the user has granted permission, it will work. You'll need a TURN server for video because mobile devices mess around with DNS and ports, but once you set that up, it will work at last.

It's not a long-term solution — we really need the ability to set the WebView to have a secure context with our app's proper address and certificate — but it's a start, I guess.

I hope that helps you. It's taken me a year to get it working 👍

steveo555 avatar May 14 '25 09:05 steveo555

@steveo555 Thank you, I appreciate your thorough write up!

soenneker avatar May 14 '25 10:05 soenneker

Hi, good day. Any updates on this? I need to implement WebRTC in MAUI BlazorWebView on Android. @mkArtakMSFT @jfversluis @jamesmontemagno

Jsrc1990 avatar Jul 17 '25 15:07 Jsrc1990

Just to be clear, it was working in iOS builds but not Android.

HOWEVER, in .NET 9.0 Release, it is now possible. I think they have changed the WebView to use 0.0.0.1 which, for now, the OS is allowing to access permissions as long as you override the WebView and have a custom handler to handle permission requests.

Like this:

#if IOS using Foundation; using WebKit; using Microsoft.AspNetCore.Components.WebView.Maui; using Microsoft.Maui.Handlers;

namespace ThePathfinderApp.Platforms.iOS;

public class CustomBlazorWebViewHandler : BlazorWebViewHandler { protected override WKWebView CreatePlatformView() { var webView = base.CreatePlatformView();

    if (webView.Configuration != null)
    {
        webView.Configuration.AllowsInlineMediaPlayback = true;
        webView.Configuration.MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.None;
    }

    webView.AllowsBackForwardNavigationGestures = true;
    webView.ScrollView.Bounces = false;
    webView.AutoresizingMask = UIKit.UIViewAutoresizing.FlexibleDimensions;

    // Disable safe area
    webView.InsetsLayoutMarginsFromSafeArea = false;
    webView.LayoutMargins = new UIKit.UIEdgeInsets(0, 0, 0, 0);
    webView.ScrollView.ContentInsetAdjustmentBehavior = UIKit.UIScrollViewContentInsetAdjustmentBehavior.Never;
  
    return webView;
}

} #endif

And in your MainProgram.cs:

builder.UseMauiApp<App>().ConfigureMauiHandlers(handlers => { #if ANDROID handlers.AddHandler<BlazorWebView, CustomBlazorWebViewHandler>(); #endif }); Then, as long as the user has granted permission, it will work. You'll need a TURN server for video because mobile devices mess around with DNS and ports, but once you set that up, it will work at last.

It's not a long-term solution — we really need the ability to set the WebView to have a secure context with our app's proper address and certificate — but it's a start, I guess.

I hope that helps you. It's taken me a year to get it working 👍

Yes mate, see this 👆🏻

steveo555 avatar Jul 17 '25 15:07 steveo555