You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Android自定义渲染器WebView始终显示空白屏问题

问题分析与解决方案

核心问题原因

  1. 自定义渲染器逻辑错误:你在OnElementChanged中重新创建了Android原生WebView并替换原有的Control,此时ViewModel的InitializeAsync尚未执行,WebView.Source还未被绑定赋值,导致e.NewElement.Source为null。
  2. 未监听Source属性变化:替换原生控件后,后续ViewModel通过绑定更新Source时,渲染器没有监听属性变化,无法触发页面重新加载。

修复后的自定义渲染器代码

using Android.App;
using Android.Webkit;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms;
using Android.Content;
using Xamarin.Essentials;
using System.IO;
using System;
using MPS.Libertas.Mobile.Droid.Renderers;

[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyWebView))]
namespace MPS.Libertas.Mobile.Droid.Renderers
{
    internal class MyWebView : WebViewRenderer
    {
        public MyWebView(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                // 配置现有原生WebView,而非重新创建
                ConfigureWebView(Control);
                
                // 加载初始Source(如果有的话)
                LoadUrlFromSource(Element.Source);
            }

            // 监听Element的属性变化,尤其是Source
            if (e.OldElement != null)
            {
                e.OldElement.PropertyChanged -= OnElementPropertyChanged;
            }
            if (e.NewElement != null)
            {
                e.NewElement.PropertyChanged += OnElementPropertyChanged;
            }
        }

        private void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(Xamarin.Forms.WebView.Source))
            {
                LoadUrlFromSource(Element.Source);
            }
        }

        private void ConfigureWebView(global::Android.Webkit.WebView webView)
        {
            webView.SetWebViewClient(new WebViewClient());
            webView.SetWebChromeClient(new WebChromeClient());
            WebSettings webSettings = webView.Settings;
            webSettings.JavaScriptEnabled = true;
            // 启用缩放功能
            webSettings.SetSupportZoom(true);
            webSettings.BuiltInZoomControls = true;
            webSettings.DisplayZoomControls = false; // 可选:隐藏默认缩放控件
            webView.SetDownloadListener(new CustomDownloadListener());
        }

        private void LoadUrlFromSource(WebViewSource source)
        {
            if (source is UrlWebViewSource urlSource && !string.IsNullOrEmpty(urlSource.Url))
            {
                Control.LoadUrl(urlSource.Url);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && Element != null)
            {
                Element.PropertyChanged -= OnElementPropertyChanged;
            }
            base.Dispose(disposing);
        }
    }

    public class CustomDownloadListener : Java.Lang.Object, IDownloadListener
    {
        public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength)
        {
            try
            {
                DownloadManager.Request request = new DownloadManager.Request(Android.Net.Uri.Parse(url));
                request.AllowScanningByMediaScanner();
                request.SetNotificationVisibility(DownloadVisibility.VisibleNotifyCompleted);
                
                string downloadDir = Path.Combine(FileSystem.AppDataDirectory, "download");
                if (!Directory.Exists(downloadDir))
                    Directory.CreateDirectory(downloadDir);
                
                // 修正路径参数,确保下载文件保存到正确位置
                request.SetDestinationInExternalFilesDir(Context, Android.OS.Environment.DirectoryDownloads, Path.GetFileName(url));
                
                DownloadManager dm = (DownloadManager)Context.GetSystemService(Android.App.Application.DownloadService);
                dm.Enqueue(request);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"下载失败: {ex.Message}");
            }
        }
    }
}

额外检查项

  • 确认ViewModel实现:确保你的ViewModel继承了INotifyPropertyChanged接口,OnPropertyChanged方法正确触发属性变更通知。
  • 验证URL有效性:检查linkPecasPJe是否包含http://或https://前缀,WebView无法加载无协议的URL。
  • Android权限配置:在AndroidManifest.xml中添加必要权限:
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 若需下载到外部存储,添加以下权限(Android 13+需调整) -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    

内容的提问来源于stack exchange,提问作者Lucas Ribeiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:55:25