【问题标题】:WebGL in WebView does not work in UNO build but does work in Xamarin buildWebView 中的 WebGL 在 UNO 构建中不起作用,但在 Xamarin 构建中起作用
【发布时间】:2019-05-03 08:44:23
【问题描述】:

目前我正在开发一个使用 auf UNO 平台的移动应用程序。为了显示 3D 模型,我使用了 WebView 控件和一些 ThreeJS JavaScript 代码。这适用于 UWP 和 WASM。 (WASM 构建中 WebView 的解决方法也可以在 StackOverflow 上找到 here。) 然而,Android 版本让我头疼:HTML 页面加载,调试输出显示 WebGL 脚本部分正在执行,但用户界面没有显示任何内容。

我已经确定(在我看来)使用了正确的 WebView 控件。此外,我使用从“Play Store”(版本 74.x.x.x)下载的“Chrome”中的替代 WebView 进行了测试。 WebView 的 HTTP 用户代理是正确的,所以 WebView 是根据 Android 系统的开发者设置使用的。 Activity 和 AndroidManifest 文件中的硬件加速都设置为“TRUE”。

我还使用开箱即用的“Android-XAML-App”进行了非常简单的测试。立方体几乎立即显示出来。

MainView.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:WebViewTestAndroid"
             x:Class="WebViewTestAndroid.MainPage">
    <Grid>
        <WebView Source="https://threejs.org/examples/?q=cube#webgl_geometry_cube" />        
    </Grid>
</ContentPage>

这是 UNO 主页无法正常工作的示例。页面正在加载,但未显示 3D 立方体。

MainPage.xaml

<Page
    x:Class="UnoWebViewTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UnoWebViewTest"
    xmlns:ios="http://uno.ui/ios"
    xmlns:android="http://uno.ui/android"
    xmlns:xamarin="http://uno.ui/xamarin"
    xmlns:wasm="http://uno.ui/wasm"
    mc:Ignorable="d ios android xamarin wasm"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <android:WebView Source="https://threejs.org/examples/?q=cube#webgl_geometry_cube" />
    </Grid>
</Page>

我比较了清单文件,但到目前为止我还没有得出可以进一步调查的结论。 我希望 UNO 使用的是原生 Android WebView 控件,但可能缺少某些设置或者它甚至不是同一个控件?

【问题讨论】:

标签: c# android xamarin android-webview uno-platform


【解决方案1】:

这确实是由于 Uno 的 WebView 禁用了硬件加速。除此之外,Uno 和 Xamarin.Forms 在后台同样使用 Android.WebKit.WebView。

可以使用附加属性在 Uno 中轻松重新启用硬件加速:

    public static class WebViewHardware
    {
        public static bool GetIsEnabled(WebView obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(WebView obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(WebViewHardware), new PropertyMetadata(false, OnIsEnabledChanged));

        private static void OnIsEnabledChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            var webView = (WebView)dependencyObject;

            var isEnabled = (bool)args.NewValue;

#if __ANDROID__
            webView.Loaded += OnLoaded;

            void OnLoaded(object sender, RoutedEventArgs e)
            {
                webView.Loaded -= OnLoaded;
                var layerType = isEnabled ? Android.Views.LayerType.Hardware : Android.Views.LayerType.Software;

                webView.SetLayerType(layerType, null);
            }
#endif
        }

这可以像这样在 XAML 中使用:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <WebView Source="https://threejs.org/examples/?q=cube#webgl_geometry_cube" local:WebViewHardware.IsEnabled="True"/>
</Grid>

【讨论】:

    【解决方案2】:

    这个问题把我逼疯了,所以我花了一整天的时间下载完整的 Xamarin 和 UNO 源代码并从头开始调试所有东西。

    首先,UNO 将 WebView 控件的“HardwareAcceleration”设置为 false。 其次,缺失的线索是这一行:

    view.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
    

    问题是,实际上不可能从外部设置它,所以我们创建一个继承自 Android.Webkit.WebView 的新类:

    public partial class MyCustomWebView : Android.Webkit.WebView
    {
        protected MyCustomWebView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
            MakeSettings();
        }
    
        public MyCustomWebView(Context context) : base(context)
        {
            MakeSettings();
        }
    
        public MyCustomWebView(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            MakeSettings();
        }
    
        public MyCustomWebView(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
        {
            MakeSettings();
        }
    
        public MyCustomWebView(Context context, IAttributeSet attrs, int defStyleAttr, bool privateBrowsing) : base(context, attrs, defStyleAttr, privateBrowsing)
        {
            MakeSettings();
        }
    
        public MyCustomWebView(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
        {
            MakeSettings();
        }
    
        private void MakeSettings()
        {
            SetLayerType(LayerType.Hardware, null);
            ForceHasOverlappingRendering(true);
    
            SetWebViewClient(new MyCustomWebViewClient(this));
            SetWebChromeClient(new WebChromeClient());
    
            Settings.AllowFileAccessFromFileURLs = true;
            Settings.AllowUniversalAccessFromFileURLs = true;
            Settings.JavaScriptEnabled = true;
            Settings.DomStorageEnabled = true;
            Settings.AllowFileAccess = true;
            Settings.CacheMode = CacheModes.NoCache;
            Settings.MediaPlaybackRequiresUserGesture = false;
            Settings.SetPluginState(WebSettings.PluginState.On);
        }
    
    
        public string HtmlContent
        {
            get { return string.Empty; }
            set { LoadUrl(value); }
        }
    }
    
    public class MyCustomWebViewClient : Android.Webkit.WebViewClient
    {
        public MyCustomWebViewClient(WebView view)
        {
            var test = view.IsHardwareAccelerated;
            view.SetLayerType(LayerType.Hardware, null);
        }
    
        public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
        {
            view.LoadUrl(request.Url.ToString());
            return true;
        }
    
        public override void OnPageStarted(WebView view, string url, Bitmap favicon)
        {
            // The native webview control requires to have LayoutParameters to function properly.
            view.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
    
            base.OnPageStarted(view, url, favicon);
        }
    }
    

    在 XAML 中使用此自定义控件可以在 WebView 中使用硬件加速的 WebGL:

    <android:MyCustomWebView HtmlContent="https://threejs.org/examples/?q=cube#webgl_geometry_cube" />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-18
      • 1970-01-01
      • 2020-09-09
      • 2012-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多