Unable to view Custom Webview inside an application with elevated privileges Xamarin C#

I am working on an application that is set as a system app on Android 10 inside a set top box, the application is given system privileges and originally the Rom that is running on the STB was using Android.System.WebView version 74.X. We now want to run new applications on this STB which use React, but the version of webview does not support javascript. So we upgraded to 114.X version of the webview. Now the react application works flawlessly, however the original system app which has the ability to show html pages and pdf pages inside our app no longer works. It displays a white screen always.

I spent time and removed all custom controls on the custom webview inside the app, but no errors are being thrown. I removed all references of reflection which was used previously and the webview just will not work inside the system app.

I then used the exact same application but sideloaded it as a release app but not system, the only difference it does not have the elevated privileges and it works as expected. I have the exact same AndroidManifest for the system app and Release app. Only difference is the use of android:sharedUserId="android.uid.system"

I have read that the reason it is being blocked is because of the security concern of a system app being made vulnerable when opening webviews.

Is there something to do to get this working as I have tried everything I can find online, including removing all custom controls and just displaying a basic google page.

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="APPNAME.app" android:sharedUserId="android.uid.system" android:versionCode="42" android:versionName="2024.6.21.10" android:installLocation="auto">
    <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="29" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
    <uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.BATTERY_STATS" />
    <uses-permission android:name="android.permission.DEVICE_POWER" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.SET_WALLPAPER" />
    <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.BIND_APPWIDGET" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.HDMI_CEC" />
    <uses-permission android:name="APPNAME.app.CLIENT_ADMIN_COMMUNICATION" />
    <application android:label="APPNAME" android:icon="@drawable/ic_launcher" android:usesCleartextTraffic="true" />
</manifest>

using System.ComponentModel;
using Android.Content;
using Android.Views;
using Android.Views.InputMethods;
using Android.Webkit;
REMOVING CUSTOM USING TO HIDE APP NAME
using Serilog;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using WebView = Xamarin.Forms.WebView;

[assembly: ExportRenderer(typeof(HtmlView), typeof(HtmlViewRenderer))]

namespace APP.Renderers
{
    public class HtmlViewRenderer : WebViewRenderer
    {
        private const string JsBridgeName = "jsBridge";

        private HtmlWebViewClient _htmlWebViewClient;
        private IInputMethodManagerWrapper _inputMethodManagerWrapper;
        private IWindowWrapper _windowWrapper;

        public HtmlViewRenderer(Context context)
            : base(context)
        {
            var logger = Log.ForContext<HtmlViewRenderer>();
            //WebViewHookHelper.HookWebView(logger);

            PropertiesResolverHelper.ResolveProperties(this);
        }

        [Inject]
        public IApiGatewayHttpClientProvider ApiGatewayHttpClientProvider { get; set; }

        [Inject]
        public IClientSettings ClientSettings { get; set; }

        public IWebViewController ElementController => Element;

        public HtmlView HtmlView => Element as HtmlView;

        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            // this prevents loading page in base.OnElementChanged(e) until custom HtmlWebViewClient getting set
            var source = Element.Source;
            Element.Source = null;

            base.OnElementChanged(e);
            

            if (e.OldElement != null)
            {
                Control.RemoveJavascriptInterface(JsBridgeName);
                var hybridJsWebView = e.OldElement as HtmlView;
                hybridJsWebView?.Cleanup();
            }

            if (e.OldElement == null)
            {
                _htmlWebViewClient = new HtmlWebViewClient(this);
                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.AllowFileAccess = true;
                Control.Settings.AllowContentAccess = true;
                _htmlWebViewClient.OnLoadError += HtmlWebViewClientOnLoadError;
                _htmlWebViewClient.OnHttpError += HtmlWebViewOnHttpError;

                Control.ClearCache(true);
            }

            if (Control != null)
            {
                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.AllowFileAccess = true;
                Control.Settings.AllowContentAccess = true;
                Control.SetWebViewClient(_htmlWebViewClient);
                Control.SetWebChromeClient(new WebChromeClient());
                Control.LongClickable = false;
                Control.SetOnLongClickListener(new DisabledLongClickListener());
                Control.SetBackgroundColor(HtmlView.BackgroundColor.ToAndroid());
            }

            if (e.NewElement != null)
            {
                Control?.AddJavascriptInterface(new JsBridge(this), JsBridgeName);

                if (e.NewElement is HtmlView htmlView)
                {
                    _inputMethodManagerWrapper = htmlView.InputMethodManagerWrapper;
                    _windowWrapper = htmlView.WindowWrapper;
                    Control.Settings.JavaScriptEnabled = true;
                    Control.Settings.DomStorageEnabled = true;
                }
            }

            source?.Load(this);
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (HtmlView == null)
            {
                return;
            }

            if (e.PropertyName == nameof(HtmlView.DesktopMode) && HtmlView.DesktopMode && Control.Settings != null)
            {
                Control.Settings.UserAgentString = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1";
                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.LoadWithOverviewMode = true;
                Control.Settings.AllowFileAccess = true;
                Control.Settings.AllowContentAccess = true;
                Control.Settings.UseWideViewPort = true;
                Control.Settings.SetSupportZoom(true);
                Control.Settings.BuiltInZoomControls = true;
                Control.Settings.DisplayZoomControls = true;
            }

            if (e.PropertyName == nameof(HtmlView.BackgroundColor))
            {
                Control.SetBackgroundColor(HtmlView.BackgroundColor.ToAndroid());
            }

            if (e.PropertyName == nameof(HtmlView.ForceKeyboardVisible))
            {
                if (HtmlView.ForceKeyboardVisible)
                {
                    ShowKeyboard();
                }
                else
                {
                    HideKeyboard();
                }
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && Control != null)
            {
                Control.LoadUrl("about:blank");
                Control.ClearCache(true);
                Control.Destroy();
                _htmlWebViewClient.OnLoadError -= HtmlWebViewClientOnLoadError;
                _htmlWebViewClient.OnHttpError -= HtmlWebViewOnHttpError;
                _htmlWebViewClient?.Dispose();

                if (HtmlView.ForceKeyboardVisible)
                {
                    HideKeyboard();
                }
            }

            base.Dispose(disposing);
        }

        private void HtmlWebViewClientOnLoadError(object sender, WebResourceError e)
        {
            HtmlView.HasError = true;
        }

        private void HtmlWebViewOnHttpError(object sender, WebResourceResponse e)
        {
            HtmlView.HasError = true;
        }

        private void ShowKeyboard()
        {
            if (Control != null)
            {
                _inputMethodManagerWrapper?.ShowSoftInput(Control, (int)ShowFlags.Forced);
            }
        }

        private void HideKeyboard()
        {
            if (Control != null)
            {
                _inputMethodManagerWrapper?.HideSoftInputFromWindow(Control.WindowToken, (int)HideSoftInputFlags.None);
            }

            _windowWrapper?.SetSoftInputMode((int)SoftInput.StateHidden);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using Android.Graphics;
using Android.Net.Http;
using Android.Runtime;
using Android.Webkit;
using Serilog;
using Serilog.Core;
using Xamarin.Forms;
using WebView = Android.Webkit.WebView;

namespace APPNAME.Controls
{
    internal class HtmlWebViewClient : Android.Webkit.WebViewClient
    {
        private readonly HtmlViewRenderer _htmlViewRenderer;

        public HtmlWebViewClient(HtmlViewRenderer htmlViewRenderer)
        {
            _htmlViewRenderer = htmlViewRenderer;
        }

        protected HtmlWebViewClient(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {
        }

        public event EventHandler<WebResourceError> OnLoadError;

        public event EventHandler<WebResourceResponse> OnHttpError;

        public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest request)
        {
            if (_htmlViewRenderer != null && request.Url != null && _htmlViewRenderer.HtmlView.IsAuthenticationEnabled && request.Url.Port == _htmlViewRenderer.ClientSettings.ApiGatewayPort)
            {
                return AuthenticateApiGatewayRequest(request.Url.ToString(), request.Method, request.RequestHeaders, () => base.ShouldInterceptRequest(view, request));
            }

            return base.ShouldInterceptRequest(view, request);
        }

        public override void OnReceivedError(WebView view, IWebResourceRequest request, WebResourceError error)
        {
            base.OnReceivedError(view, request, error);
            OnLoadError?.Invoke(this, error);
        }

        public override void OnReceivedHttpError(WebView view, IWebResourceRequest request, WebResourceResponse errorResponse)
        {
            base.OnReceivedHttpError(view, request, errorResponse);
            if (request.Url != null && view.Url == request.Url.ToString())
            {
                OnHttpError?.Invoke(this, errorResponse);
            }
        }

        public override void OnPageStarted(WebView view, string url, Bitmap favicon)
        {
            if (_htmlViewRenderer == null)
            {
                return;
            }

            var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
            _htmlViewRenderer.ElementController.SendNavigating(args);

            if (args.Cancel)
            {
                _htmlViewRenderer.Control.StopLoading();
            }
            else
            {
                base.OnPageStarted(view, url, favicon);
            }
        }

        public override void OnPageFinished(WebView view, string url)
        {
            if (_htmlViewRenderer == null)
            {
                return;
            }

            base.OnPageFinished(view, url);

            var source = new UrlWebViewSource { Url = url };
            var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, WebNavigationResult.Success);
            _htmlViewRenderer.ElementController.SendNavigated(args);
        }

        private WebResourceResponse AuthenticateApiGatewayRequest(string url, string httpMethod, IDictionary<string, string> requestHeaders, Func<WebResourceResponse> originalRequest)
        {
            try
            {
                // since this method is not called in UI thread, executing async methods in a sync way wouldn't block the UI
                var cts = new CancellationTokenSource(_htmlViewRenderer.ClientSettings.ApiGatewayTimeout);
                var httpClient = _htmlViewRenderer.ApiGatewayHttpClientProvider.GetApiGatewayClient(cancellationToken: cts.Token).Result.HttpClient;
                var requestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), url);
                var result = httpClient.SendAsync(requestMessage, cts.Token).Result;
                var resultHeader = result.Content.Headers;
                var stream = result.Content.ReadAsStreamAsync().Result;

                return new WebResourceResponse(resultHeader.ContentType?.MediaType, resultHeader.ContentType?.CharSet, (int)result.StatusCode, result.ReasonPhrase, requestHeaders, stream);
            }
            catch (Exception ex)
            {
                Log.Logger.Error($"Error requesting {url} from webview. Error message: {ex.Message}");
                return originalRequest();
            }
        }
    }
}

The original webhook which is not going to work due to reflection but said i would include it anyway

using Android.OS;
using Java.Lang;
using Java.Lang.Reflect;
using Serilog;

namespace APPNAME.Helpers
{
    internal static class WebViewHookHelper
    {
        private const string WebViewFactory = "android.webkit.WebViewFactory";
        private const string ProviderInstance = "sProviderInstance";
        private const string WebViewDelegate = "android.webkit.WebViewDelegate";
        private const string GetProviderClass = "getProviderClass";
        private const string GetFactoryClass = "getFactoryClass";

        public static void HookWebView(ILogger logger)
        {
            try
            {
                var factoryClass = Class.ForName(WebViewFactory);
                var field = factoryClass?.GetDeclaredField(ProviderInstance);
                if (field != null)
                {
                    field.Accessible = true;
                    Object sProviderInstance = field.Get(null);
                    if (sProviderInstance == null)
                    {
                        var getProviderClassMethod = GetProviderClassMethod(factoryClass, logger);

                        if (getProviderClassMethod != null)
                        {
                            //TryToSetProviderInstance(getProviderClassMethod, factoryClass, field, logger);
                            logger.Information("HI here");
                        }
                    }
                    else
                    {
                        logger.Debug($"{ProviderInstance} isn't null");
                    }
                }

                logger.Debug("Hook done!");
            }
            catch (Throwable e)
            {
                logger.Error(e, "WebView hook failed.");
            }
        }

        private static Method GetProviderClassMethod(Class factoryClass, ILogger logger)
        {
            Method getProviderClassMethod = null;
            if (Build.VERSION.SdkInt > BuildVersionCodes.LollipopMr1)
            {
                getProviderClassMethod = factoryClass.GetDeclaredMethod(GetProviderClass);
            }
            else if (Build.VERSION.SdkInt == BuildVersionCodes.LollipopMr1)
            {
                getProviderClassMethod = factoryClass.GetDeclaredMethod(GetFactoryClass);
            }
            else
            {
                logger.Information("Don't need to Hook WebView");
            }

            return getProviderClassMethod;
        }

        private static void TryToSetProviderInstance(Method getProviderClassMethod, Class factoryClass, Field field, ILogger logger)
        {
            var delegateClass = Class.ForName(WebViewDelegate);
            if (delegateClass != null)
            {
                getProviderClassMethod.Accessible = true;
                var providerClass = getProviderClassMethod.Invoke(factoryClass) as Class;
                var providerConstructor = providerClass?.GetDeclaredConstructor(delegateClass);
                if (providerConstructor != null)
                {
                    Object providerInstance = null;
                    providerConstructor.Accessible = true;
                    var declaredConstructor = delegateClass.GetDeclaredConstructor();
                    if (declaredConstructor != null)
                    {
                        declaredConstructor.Accessible = true;
                        var newInstance = declaredConstructor.NewInstance();
                        if (newInstance != null)
                        {
                            providerInstance = providerConstructor.NewInstance(newInstance);
                        }
                    }

                    logger.Debug("sProviderInstance:{}", providerInstance);
                    field.Set(ProviderInstance, providerInstance);
                }
            }
        }
    }
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật