Forum Xamarin Xamarin.iOS

Is it possible to intercept post requests from WKWebView and get request body?

When developing an iOS application using Xamarin.iOS, we have a WKWebView that displays our own website inside.

We want to be able to intercept HTTP requests sent from the WKWebView's JS and extract the request body. Specifically for Form Post requests.

I know we can catch the URL for the requests using the WKNavigationDelegate, but is there a way to capture the whole request?

Thanks,
Andy

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    Firstly we need to notify this js post request on native, I find this post talking about this. Here is the js code:

    var s_ajaxListener = new Object();
    s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
    s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
    s_ajaxListener.callback = function () {
      // this.method :the ajax method used
      // this.url    :the url of the requested script (including query string, if any) (urlencoded) 
      // this.data   :the data sent, if any ex: foo=bar&a=b (urlencoded)
    }
    
    XMLHttpRequest.prototype.open = function(a,b) {
      if (!a) var a='';
      if (!b) var b='';
      s_ajaxListener.tempOpen.apply(this, arguments);
      s_ajaxListener.method = a;  
      s_ajaxListener.url = b;
      if (a.toLowerCase() == 'get') {
        s_ajaxListener.data = b.split('?');
        s_ajaxListener.data = s_ajaxListener.data[1];
      }
    }
    
    XMLHttpRequest.prototype.send = function(a,b) {
      if (!a) var a='';
      if (!b) var b='';
      s_ajaxListener.tempSend.apply(this, arguments);
      if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
      s_ajaxListener.callback();
    }
    

    In this callback method, we can pass the data to native. Two ways to achieve that:

    1. Define a method in our project, use js code to call this method and pass the data.
    2. Use window.location='SpecialUrlScheme://?' + this.data; this will open a new page in wkwebView. And you can handle this action using WKNavigationDelegate

    At last we need to inject this js to our WKWebView:

    // This file is what we defined above
    NSData scriptData = NSData.FromUrl(new NSUrl(NSBundle.MainBundle.PathForResource("JSFileName", "js"), false));
    NSString scriptContent = NSString.FromData(scriptData, NSStringEncoding.UTF8);
    var script = new WKUserScript(scriptContent, WKUserScriptInjectionTime.AtDocumentStart, true);
    WKWebViewConfiguration configuration = new WKWebViewConfiguration();
    configuration.UserContentController.AddUserScript(script);
    
    WKWebView webView = new WKWebView(new CGRect(0, 0, 320, 600), configuration);
    View.AddSubview(webView);
    
  • munaalzeermunaalzeer JOMember ✭✭

    after long search what did actually work for me is to edit the form loaded in the wkwebview and make the post with an ajax call.

  • LijuDanielLijuDaniel Member ✭✭
    edited May 20

    POST Request Over Webview
    For WkWebview
    [assembly: ExportRenderer(typeof(PaymentWebview), typeof(PaymentWebViewRenderer))]
    namespace MMFInvestorApp.iOS.Utils
    {
    public class PaymentWebViewRenderer : WkWebViewRenderer
    {
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
    base.OnElementChanged(e);

            if (NativeView != null)
            {
                var request = new NSMutableUrlRequest(new NSUrl(new NSString(paymentwebview.url))); //Your Url
                request.HttpMethod = "POST";
                request.Body = NSData.FromString(paymentwebview.data); //Data for POST
                request["Content-Length"] = req.Body.Length.ToString();
                request["Content-Type"] = "application/x-www-form-urlencoded charset=utf-8";
                LoadRequest(request);
            }
    
        }
    
    
    }
    

    }

    For UIWebview (Deprecated from April 2020
    [assembly: ExportRenderer(typeof(PaymentWebview), typeof(PaymentWebViewRenderer))]
    namespace MMFInvestorApp.iOS.Utils
    {
    public class PaymentWebViewRenderer : WebViewRenderer
    {
    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
    base.OnElementChanged(e);

            if (NativeView != null)
            {
                var paymentwebview = Element as PaymentWebview;
                var request = new NSMutableUrlRequest(new NSUrl(new NSString(paymentwebview.url)));//Your Url
                request.Body = paymentwebview.data; //Data for POST
                request.HttpMethod = "POST";
                LoadRequest(request);
            }
    
        }
    
    
    }
    

    }

Sign In or Register to comment.