【问题标题】:Xamarin.Forms.WebView.Navigating event raised on iOS for internal navigation在 iOS 上引发 Xamarin.Forms.WebView.Navigating 事件以进行内部导航
【发布时间】:2016-09-14 21:06:36
【问题描述】:

假设您想阻止用户从您的 Xamarin.Forms.WebView 导航到外部页面。

public App ()
{
    var webView = new WebView
    {
        Source = new HtmlWebViewSource
        {
            Html = "<h1>Hello world</h1><a href='http://example.com'>Can't escape!</a><iframe width='420' height='315' src='https://www.youtube.com/embed/oHg5SJYRHA0' frameborder='0' allowfullscreen></iframe>"
        }
    };
    webView.Navigating += WebView_Navigating;

    MainPage = new ContentPage {
        Content = webView
    };
}

private void WebView_Navigating(object sender, WebNavigatingEventArgs e)
{
    // we don't want to navigate away from our page
    // open it in a new page instead etc.
    e.Cancel = true;
}

这在 Windows 和 Android 上运行良好。但在 iOS 上,它根本不加载!

在 iOS 上,即使从 HtmlWebViewSource 加载源代码也会引发导航事件,其 URL 类似于 file:///Users/[user]/Library/Developer/CoreSimulator/Devices/[deviceID]/data/Containers/Bundle/Application/[appID]/[appName].app/

好的,所以你可以通过以下方式解决这个问题:

private void WebView_Navigating(object sender, WebNavigatingEventArgs e)
{
    if (e.Url.StartsWith("file:") == false)
        e.Cancel = true;
}

页面最终在 iOS 上加载。耶。可是等等!嵌入的 YouTube 视频无法加载!这是因为 Navigating 事件会针对 iframe 甚至外部脚本(如 Twitter 的 &lt;script charset="utf-8" type="text/javascript" src="http://platform.twitter.com/widgets.js"&gt;&lt;/script&gt;)等嵌入式资源的内部导航引发,但仅限于 iOS!

我找不到方法来确定 Navigating 事件是由内部导航引发还是因为用户单击了链接。

如何解决这个问题?

【问题讨论】:

    标签: c# ios webview xamarin xamarin.forms


    【解决方案1】:

    我不确定是否可以在开箱即用的 Xamarin Forms 中进行检测,但使用自定义渲染器可以轻松确定导航类型。在您的自定义 iOS 渲染器中,分配一个 WebViewDelegate 并在该 Delegate 类中覆盖 ShouldStartLoad(),如下所示:

    public class CustomWebViewRenderer : WebViewRenderer {
    
        #region Properties
    
        public CustomWebView CustomWebViewItem { get { return Element as CustomWebView; } }
    
        #endregion
    
        protected override void OnElementChanged(VisualElementChangedEventArgs e) {
            base.OnElementChanged(e);
    
            if(e.OldElement == null) {
                Delegate = new CustomWebViewDelegate(); //Assigning the delegate
            }
        }
    }
    internal class CustomWebViewDelegate : UIWebViewDelegate {
    
        public override bool ShouldStartLoad(UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) {
    
            if(navigationType == UIWebViewNavigationType.LinkClicked) {
                //To prevent navigation when a link is click, return false
                return false;
            }
    
            return true;
        }
    }
    

    您还可以将 bool 属性甚至枚举备份到您的 Xamarin Forms WebView,这将说明 Navigating 事件是来自被单击的链接还是来自其他内容,尽管需要自定义渲染器也是如此。

    【讨论】:

    • 谢谢你,效果很好。您对如何使用 android 的自定义渲染器不礼貌有任何想法吗?因为我使用了自定义渲染器和自定义 WebViewClient,所以不再触发来自 WebView 的 OnNavigating 事件。
    • @Nk54 您可以简单地用自定义渲染器中触发的OnNavigating 覆盖WebView 的当前OnNavigating。这可能更适合新问题,但这很烦人,所以我将指向一个链接,显示正在创建的自定义 OnNavigating 属性 here。然后,如果您查看here,我只需将单词new 添加到将覆盖默认OnNavigating 的属性中
    • @Nk54 所以属性会变成public new event WebViewNavigatingHandler Navigating;。只需确保在CookieWebView.cs 中包含所有其他事件接线代码。如果您需要更多帮助,请告诉我。
    • @hvaughan3 请给出解释。 CustomWebViewRenderer 类写在 ios 里面的渲染类它 customwebview 得到错误以及如何从表单和 xaml 文件中调用也给出解释
    • @BhuvaneshwaranVellingiri 您是否在问如何创建自定义渲染器本身? Xamarin Forms 文档中应该有关于如何做到这一点的指南。
    【解决方案2】:
    private bool isNavigated = false;
            public CustomWebView()
            {
                if (Device.OS == TargetPlatform.Android)
                {
                    // always true for android
                    isNavigated = true;
                }
    
                Navigated += (sender, e) =>
                {
                    isNavigated = true;
                };
                Navigating += (sender, e) =>
                {
                    if (isNavigated)
                    {
                        try
                        {
                            var uri = new Uri(e.Url);
                            Device.OpenUri(uri);
                        }
                        catch (Exception)
                        {
                        }
    
                        e.Cancel = true;
                    }
                };
            }
    

    【讨论】:

    • 欢迎来到 StackOverflow!请描述您的代码,以便查看此问题的其他用户更容易理解。
    • 这段小代码帮助我解决了类似的问题。
    猜你喜欢
    • 2022-01-21
    • 2017-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    相关资源
    最近更新 更多