在iOS上为内部导航引发的Xamarin.Forms.WebView.Navigating事件

时间:2016-05-18 11:42:38

标签: c# ios webview xamarin xamarin.forms

假设您要阻止用户从您的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加载源代码时,也会引发Navigating事件,其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视频无法加载!那是因为导航事件会引发嵌入式资源的内部导航,例如iframe甚至外部脚本(如Twitter的<script charset="utf-8" type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>),但仅限于iOS!

我找不到确定Navigating事件是从内部导航引发还是因为用户点击链接的方法。

如何解决这个问题?

2 个答案:

答案 0 :(得分:5)

我不确定是否可以在开箱即用的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表单WebView,这可以说明Navigating事件是来自被点击的链接还是其他内容,尽管是自定义的也需要渲染器。

答案 1 :(得分: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;
                }
            };
        }