Xamarin.Forms WebView iOS端执行Javascript适配WKWebViewRenderer求助
适配iOS WKWebViewRenderer执行JavaScript的解决方案
我刚好处理过这个问题,iOS升级后WKWebView的EvaluateJavaScript API确实改成了异步回调模式,替代了原来同步返回结果的方式,下面是具体的适配方案,完美兼容你原来的调用逻辑:
1. 自定义WKWebView渲染器
首先替换原来的WebViewRenderer为WKWebViewRenderer,并通过TaskCompletionSource将回调式的API包装成Task,这样上层调用时可以保持和Android端一致的异步语法:
using System; using System.Threading.Tasks; using Foundation; using WebKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))] namespace YouriOSProjectNamespace { public class HybridWebViewRenderer : WKWebViewRenderer, IWKScriptMessageHandler { public HybridWebViewRenderer() : base(new WKWebViewConfiguration()) { } protected override void OnElementChanged(VisualElementChangedEventArgs e) { base.OnElementChanged(e); if (e.NewElement is HybridWebView hybridWebView) { // 这里可以添加WKWebView的额外配置,比如脚本消息监听(如果需要和JS交互的话) } } // 包装WKWebView的异步API为Task<string> public Task<string> EvaluateJavaScriptAsync(string script) { var taskCompletionSource = new TaskCompletionSource<string>(); this.EvaluateJavaScript(script, (result, error) => { if (error != null) { // 将iOS原生错误包装成.NET异常 taskCompletionSource.SetException(new Exception(error.LocalizedDescription)); return; } // 处理返回结果:iOS会把JS返回值序列化为JSON格式,字符串会带双引号,需要处理 string jsResult = result?.ToString() ?? string.Empty; if (!string.IsNullOrEmpty(jsResult) && jsResult.StartsWith("\"") && jsResult.EndsWith("\"")) { // 去掉首尾引号并还原转义的双引号 jsResult = jsResult.Substring(1, jsResult.Length - 2).Replace("\\\"", "\""); } taskCompletionSource.SetResult(jsResult); }); return taskCompletionSource.Task; } // 实现IWKScriptMessageHandler接口的方法(如果需要和JS双向交互的话,否则可以忽略) public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message) { // 处理JS发送过来的消息 } } }
2. 自定义Xamarin.Forms WebView类
在共享项目中定义自定义WebView,提供统一的调用方法:
using Xamarin.Forms; public class HybridWebView : WebView { /// <summary> /// 统一的执行JavaScript方法,跨平台调用 /// </summary> public Task<string> EvaluateJavaScriptAsync(string script) { var renderer = Platform.GetRenderer(this) as HybridWebViewRenderer; return renderer?.EvaluateJavaScriptAsync(script) ?? Task.FromResult<string>(null); } }
3. 上层调用方式
现在你可以在共享项目中像原来一样调用,保持跨平台代码一致性:
var result = await yourHybridWebView.EvaluateJavaScriptAsync("your javascript code here");
关键注意点
- 错误处理:通过
TaskCompletionSource将iOS原生的NSError转换为.NET异常,上层可以用try-catch捕获 - 结果格式化:iOS返回的JS结果是JSON序列化后的字符串,比如JS返回
"hello",iOS会返回"\"hello\"",所以需要处理掉多余的引号和转义字符 - 渲染器注册:确保在iOS项目的
AssemblyInfo.cs或者渲染器类上添加ExportRenderer特性,让Xamarin.Forms识别自定义渲染器
内容的提问来源于stack exchange,提问作者user132397
相关产品推荐
相关产品推荐

