roughike / flutter_facebook_login

A Flutter plugin for allowing users to authenticate with native Android & iOS Facebook login SDKs.
BSD 2-Clause "Simplified" License
405 stars 331 forks source link

Plugin is forbidding usage of AJAX interception in webview #213

Open gibbsvjy007 opened 4 years ago

gibbsvjy007 commented 4 years ago

We are using flutter webview (e.g - inappbrowser, flutter_webview etc) in Android and we are injecting the following Javascript code to intercept AJAX network call. It is working fine with most of the plugins and intercepting network call as expected. But as soon as we integrate this plugin it stops intercepting and we get the following error.

Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.

Injected Javascript Code:

var open = window.XMLHttpRequest.prototype.open;
var send = window.XMLHttpRequest.prototype.send;
var onReadyStateChange;
var index = 0;
function openReplacement(method, url, async, user, password) {
    var syncMode = async !== false ? 'async' : 'sync';
    return open.apply(this, arguments);
}

function sendReplacement(data) {
    if (this.onreadystatechange) {
        this._onreadystatechange = this.onreadystatechange;
    }
    this.onreadystatechange = onReadyStateChangeReplacement;
    return send.apply(this, arguments);
}

function onReadyStateChangeReplacement() {
    if (this.readyState === XMLHttpRequest.DONE) {
        if (this.responseType === 'text') {
            if (this.responseText !== '' && this.responseText !== null) {
              if (window.Android && window.Android.postMessage) {
                Android.postMessage(this.responseText);
              }
            }
        }
        if (this.responseType === 'json') {
               var res = JSON.stringify(this.response);
               if (res !== '' && res !== null) {

                   if (window.Android && window.Android.postMessage) {
                        Android.postMessage(res);
                   }
               }
     }
    if (this._onreadystatechange) {
        return this._onreadystatechange.apply(this, arguments);
    }
}

window.XMLHttpRequest.prototype.open = openReplacement;
window.XMLHttpRequest.prototype.send = sendReplacement;

We are injecting the Javascript code as Below:

InAppWebView(
  initialUrl: hitUrl,
  initialOptions: {
    'javaScriptEnabled': true,
    'supportZoom': true,
    "domStorageEnabled": true,
    "useOnLoadResource": true,
  },
  onLoadStart: (InAppWebViewController controller, String url) {
    print("started $url");
  },
  onWebViewCreated:
  (InAppWebViewController controller) async {
    webView = controller;
    webView.setOptions({'javaScriptEnabled': true});
    /// injecting the above javascript code here.
    await webView.injectScriptCode(widget.jsCode);
    webView.addJavaScriptHandler('zaboHandler', onZaboHandlerCallback);
  },
  onConsoleMessage: (InAppWebViewController controller,
                     ConsoleMessage consoleMessage) {
    print(consoleMessage.message);
  },
)
WebView(
  initialUrl: hitUrl,
  javascriptMode: JavascriptMode.unrestricted,
  onWebViewCreated: (WebViewController webViewController) {
    webViewController.evaluateJavascript(widget.jsCode);
    _controller.complete(webViewController);
  },
  javascriptChannels: <JavascriptChannel>[
    _toasterJavascriptChannel(context),
  ].toSet(),
  navigationDelegate: (NavigationRequest request) {
    if (request.url.startsWith('https://www.youtube.com/')) {
      print('blocking navigation to $request}');
      return NavigationDecision.prevent;
    }
    print('allowing navigation to $request');
    return NavigationDecision.navigate;
  },
  onPageFinished: (String url) {
    print('Page finished loading: $url');
  },
);