Xamarin Android自定义渲染器WebView始终显示空白屏问题
问题分析与解决方案
核心问题原因
- 自定义渲染器逻辑错误:你在
OnElementChanged中重新创建了Android原生WebView并替换原有的Control,此时ViewModel的InitializeAsync尚未执行,WebView.Source还未被绑定赋值,导致e.NewElement.Source为null。 - 未监听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
相关产品推荐
相关产品推荐

