簡體   English   中英

如何從Javascript調用Navigation.PopAsync()

[英]How to call Navigation.PopAsync() from Javascript

我在Xamarin Forms內容中有一個Web視圖,我在其中使用純html div ,我想導航至div onClick()上的另一個頁面( Navigation.PopAsyncNavigation.PushAsync onClick() ,是否可以不實現任何渲染器或混合視圖?

您可以創建一個HybridWebView來實現您的功能。

HybridWebView.cs:

public class HybridWebView : View
{
    Action<string> action;

    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 Cleanup ()
    {
        action = null;
    }

    public void InvokeAction (string data)
    {
        if (action == null || data == null) {
            return;
        }
        action.Invoke (data);
    }
}

Xaml.cs中使用

<local:HybridWebView x:Name="hybridWebView" Uri="index.html" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />

然后在Android中 ,創建HybridWebViewRenderer.cs

public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
    const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
    Context _context;

    public HybridWebViewRenderer(Context context) : base(context)
    {
        _context = context;
    }

    protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            Control.RemoveJavascriptInterface("jsBridge");
            var hybridWebView = e.OldElement as HybridWebView;
            hybridWebView.Cleanup();
        }
        if (e.NewElement != null)
        {
            if (Control == null)
            {
                var webView = new Android.Webkit.WebView(_context);
                webView.Settings.JavaScriptEnabled = true;
                webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
                SetNativeControl(webView);
            }
            Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
            Control.LoadUrl($"file:///android_asset/Content/{Element.Uri}");
        }
    }
}

Renderer中的JavascriptWebViewClient.cs如下:

public class JavascriptWebViewClient : WebViewClient
{
    string _javascript;

    public JavascriptWebViewClient(string javascript)
    {
        _javascript = javascript;
    }

    public override void OnPageFinished(WebView view, string url)
    {
        base.OnPageFinished(view, url);
        view.EvaluateJavascript(_javascript, null);
    }
}

還需要JSBridge處理JavaScript:

public class JSBridge : Java.Lang.Object
{
    readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;

    public JSBridge (HybridWebViewRenderer hybridRenderer)
    {
        hybridWebViewRenderer = new WeakReference <HybridWebViewRenderer> (hybridRenderer);
    }

    [JavascriptInterface]
    [Export ("invokeAction")]
    public void InvokeAction (string data)
    {
        HybridWebViewRenderer hybridRenderer;

        if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget (out hybridRenderer)) 
        {
            hybridRenderer.Element.InvokeAction (data);
        }
    }
}

Okey, index.html示例如下:

<html>
<body>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<h1>HybridWebView Test</h1>
<br/>
Enter name: <input type="text" id="name">
<br/>
<br/>
<button type="button" onclick="javascript:invokeCSCode($('#name').val());">Invoke C# Code</button>
<br/>
<p id="result">Result:</p>
<script type="text/javascript">
function log(str)
{
    $('#result').text($('#result').text() + " " + str);
}

function invokeCSCode(data) {
    try {
        log("Sending Data:" + data);
        invokeCSharpAction(data);
    }
    catch (err){
        log(err);
    }
}
</script>
</body>
</html>

運行后,視圖如下:

在此處輸入圖片說明

最后,我們從JavaScript調用函數的地方是ContenPage:

hybridWebView.RegisterAction ( data => { Navigation.PushModalAsync(new PageNext()); });

IOS HybridWebViewRenderer.cs類如下:

public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
{
    const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
    WKUserContentController userController;

    protected override void OnElementChanged (ElementChangedEventArgs<HybridWebView> e)
    {
        base.OnElementChanged (e);

        if (e.OldElement != null) {
            userController.RemoveAllUserScripts ();
            userController.RemoveScriptMessageHandler ("invokeAction");
            var hybridWebView = e.OldElement as HybridWebView;
            hybridWebView.Cleanup ();
        }
        if (e.NewElement != null) {
            if (Control == null)
            {
                userController = new WKUserContentController();
                var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
                userController.AddUserScript(script);
                userController.AddScriptMessageHandler(this, "invokeAction");

                var config = new WKWebViewConfiguration { UserContentController = userController };
                var webView = new WKWebView(Frame, config);
                SetNativeControl(webView);
            }

            string fileName = Path.Combine (NSBundle.MainBundle.BundlePath, string.Format ("Content/{0}", Element.Uri));
            Control.LoadRequest (new NSUrlRequest (new NSUrl (fileName, false)));
        }
    }

    public void DidReceiveScriptMessage (WKUserContentController userContentController, WKScriptMessage message)
    {
        Element.InvokeAction (message.Body.ToString ());
    }
}

這里也有官方樣品供參考。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM