Xamarin iOS HybridWebView 不执行 iOS 15> iPad 的 JavaScript 文件



我正在开发一个跨平台应用程序,该应用程序具有HybridWebView并显示本地html文件。我有一个wwwroot文件夹,其中包含html文件、css文件、js文件和所有其他资源。我已经将完整的文件夹构建为BundleResource。我还用EmbeddIO启动了一个本地web服务器。当我在iPad(iOS 15>(上启动该应用程序时,它不会执行JavaScript文件。在iPhone(iOS 15>(上,该应用程序运行良好。同样在iOS 12的iPad上,该应用程序也能正常工作。此外,无论使用何种设备,该应用程序都能在Safari上运行。

我已经在info.plistNSAppTransportSecurity中添加了NSAllowsArbitraryLoads=true。此外,我还开发了一个带有WebView的Swift应用程序,并尝试使用Xamarin.iOS应用程序的本地web服务器在那里展示该应用程序。但同样,JavaScript没有被执行(我还设置了关于JavaScript的首选项(。

我的问题:

我不明白为什么这个应用程序可以在Safari、iPhone和旧iPad上运行,但不能在新iPad上运行。我怀疑您必须启用JavaScript,但找不到相应的解决方案。

值得一提的是:

我在index.html中只加载一个js文件。这个js文件依次加载其他js文件(如上所述,这适用于除新iPad之外的所有设备(。

下面我添加了HybridWebView.cs、HybridWebView Renderer.cs、MainPage.xaml.cs和MainPage.xaml.

主页.xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:extensions="clr-namespace:Viewer.Extensions;assembly=Viewer"
x:Class="Viewer.MainPage">
<StackLayout>
<extensions:HybridWebView x:Name="HybridWebView" Uri="{Binding WebViewSource}" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>

主页.xaml.cs:

namespace Viewer
{
[DesignTimeVisible(false)]
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
private readonly LocalWebServer _server = new LocalWebServer();
private string _webViewSource;
public string WebViewSource
{
get => _webViewSource;
set
{
_webViewSource = value;
OnPropertyChanged(nameof(WebViewSource));
}
}
public MainPage()
{
InitializeComponent();
BindingContext = this;
NavigationPage.SetHasNavigationBar(this, false);
HybridWebView.RegisterAction(data =>
{
DisplayAlert("Alert", "Hello " + data, "OK");
});
HybridWebView.RegisterQRAction(() =>
{
try
{
ZXingScannerPage scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) =>
{
scanPage.IsScanning = false;
Device.BeginInvokeOnMainThread(async () =>
{
await Navigation.PopAsync();
var barcode = result.Text.ParseBarcode();
switch (barcode.BarcodeType)
{
case BarcodeType.Hotspot:
{
await HybridWebView.EvaluateJavaScriptAsync(
$"javascript:doLoadHS('{barcode.Datamodule}.html', '{barcode.Hotspot.figureId}', '{barcode.Hotspot.hotspotId}');");
break;
}
case BarcodeType.Datamodule:
default:
{
await HybridWebView.EvaluateJavaScriptAsync(
$"javascript:doLoad('{barcode.Datamodule}.html');");
break;
}
}
});
};
Device.BeginInvokeOnMainThread(() =>
{
Navigation.PushAsync(scanPage);
});
}
catch (Exception ex)
{
DisplayAlert("QR", $"Error while reading qr code: {ex.Message}", "OK");
}
});
HybridWebView.RegisterProjectSelectionAction(() =>
{
_server.Dispose();
Navigation.PopToRootAsync();
});
var docpath = Helper.PathAddBackslash(Path.Combine(DependencyService.Get<IApplicationConfigurationService>().DocumentationRootPath, Init.NAME_DIR_WWWROOT));        
_server.StartWebServer(docpath, false, false);
WebViewSource = $"{LocalWebServer.Url}/index.html";

NavigationPage.SetHasBackButton(this, false);
}
protected override bool OnBackButtonPressed()
{
return true;
}
}
}

HybridWebView.cs:

using System;
using Xamarin.Forms;
namespace Viewer.Extensions
{
public class HybridWebView : WebView
{
Action<string> action;
Action qrAction;
Action projectSelectionAction;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void RegisterQRAction(Action callback)
{
qrAction = callback;
}
public void RegisterProjectSelectionAction(Action callback)
{
projectSelectionAction = callback;
}
public void Cleanup()
{
action = null;
qrAction = null;
projectSelectionAction = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
public void InvokeQRAction()
{
qrAction?.Invoke();
}
public void InvokeProjectSelectionAction()
{
projectSelectionAction?.Invoke();
}
}
}

HybridWebViewRenderer.cs:

[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace Viewer.iOS.Views
{
public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}" +
"function invokeCSharpQRAction(data){window.webkit.messageHandlers.invokeQRAction.postMessage(data);}";
WKUserContentController userController;
public HybridWebViewRenderer() : this(new WKWebViewConfiguration())
{
}
public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
userController = config.UserContentController;
var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript(script);
userController.AddScriptMessageHandler(this, "invokeAction");
userController.AddScriptMessageHandler(this, "invokeQRAction");
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
userController.RemoveScriptMessageHandler("invokeQRAction");
HybridWebView hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
LoadRequest(new NSUrlRequest(new NSUrl(((HybridWebView)Element).Uri)));
}
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
var eventArgs = message.Body.ToString().ParseEventArgs();
switch (eventArgs.name)
{
case "invokeAction":
((HybridWebView)Element).InvokeAction(eventArgs.payload);
break;
case "invokeQRAction":
((HybridWebView)Element).InvokeQRAction();
break;
}
}
}
}

这里的问题可能是您的Javascript。

移动设备和较旧的设备通常会抑制Javascript的控制台错误,而不是错误页面或异常,进一步的Javascript不会执行,而且看起来根本没有执行。

特别是对于有许多using和引用的复杂Javascript,如果一个引用有问题就足够了,所以你什么都看不到。

在这里,它可以帮助简化Javascript,并一点一点地重建它以定位错误。

最新更新