pichillilorenzo / flutter_inappwebview

A Flutter plugin that allows you to add an inline webview, to use a headless webview, and to open an in-app browser window.
https://inappwebview.dev
Apache License 2.0
3.29k stars 1.62k forks source link

Setting useShouldInterceptAjaxRequest to true can't complete the Ajax the request #404

Closed rbocobo closed 4 years ago

rbocobo commented 4 years ago

Environment

Flutter version: Flutter 1.17.3 Plugin version: ^3.3.0+3 Android version:
iOS version: 9 Xcode version: 11.5 Device information:

Description

Expected behavior: Setting useShouldInterceptAjaxRequest to true should intercept Ajax request and complete the request Current behavior: Setting useShouldInterceptAjaxRequest to true is able to intercept the request in shouldInterceptAjaxRequest but the request won't be completed. onAjaxReadyStateChange and onAjaxProgress will not be called.

Steps to reproduce

InAppWebView(
                        initialUrl: Uri.https(authState.companyData.baseUrl,
                                '/administrator/Web.do')
                            .toString(),
                        initialOptions: InAppWebViewGroupOptions(
                            crossPlatform: InAppWebViewOptions(
                                debuggingEnabled: true,
                                useShouldInterceptAjaxRequest: true),
                            ios: IOSInAppWebViewOptions(
                                sharedCookiesEnabled: true),
                            ),
                        onWebViewCreated: (InAppWebViewController controller) {
                          webView = controller;
                        },
                        onLoadStop: (controller, url) async {
                          if (url.toLowerCase().endsWith('logout.do')) {
                            BlocProvider.of<AdminBloc>(context)
                                .add(AdminPageLogout());
                            // BlocProvider.of<AuthenticationBloc>(context)
                            //     .add(AuthenticationLoggedOut());
                            // BlocProvider.of<AuthenticationBloc>(context)
                            //     .add(AuthenticationStarted());
                          }
                          webView.canGoBack().then((value) {
                            setState(() {
                              canGoBack = value;
                            });
                          });
                          webView.canGoForward().then((value) {
                            setState(() {
                              canGoForward = value;
                            });
                          });
                        },
                        onProgressChanged: (controller, progress) {
                          setState(() {
                            loadingProgress = progress / 100;
                          });
                        },
                        shouldInterceptAjaxRequest:
                            (InAppWebViewController controller,
                                AjaxRequest ajaxRequest) async {
                          print(ajaxRequest.url);
                          ajaxRequest.headers.setRequestHeader("Cookie", authState.setCookie);
                          return ajaxRequest;
                        },
                        onAjaxReadyStateChange:
                            (InAppWebViewController controller,
                                AjaxRequest ajaxRequest) async {
                          print(ajaxRequest.status);
                          return AjaxRequestAction.PROCEED;
                        },
                        onAjaxProgress: (InAppWebViewController controller,
                            AjaxRequest ajaxRequest) async {
                          print(ajaxRequest.status);
                          return AjaxRequestAction.PROCEED;
                        },
                      )

[✓] Flutter (Channel stable, v1.17.3, on Mac OS X 10.15.2 19C57, locale en-PH) • Flutter version 1.17.3 at /Users/rod/Development/flutter • Framework revision b041144f83 (12 days ago), 2020-06-04 09:26:11 -0700 • Engine revision ee76268252 • Dart version 2.8.4

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2) • Android SDK at /Users/rod/Library/Android/sdk • Platform android-29, build-tools 29.0.2 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.5) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.5, Build version 11E608c • CocoaPods version 1.8.4

[✓] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 46.0.2 • Dart plugin version 193.7361 • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[!] IntelliJ IDEA Ultimate Edition (version 2020.1.2) • IntelliJ at /Applications/IntelliJ IDEA.app ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • For information about installing plugins, see https://flutter.dev/intellij-setup/#installing-the-plugins

[✓] Connected device (2 available) • Android SDK built for x86 • emulator-5554 • android-x86 • Android 10 (API 29) (emulator) • iPad Pro (12.9-inch) (4th generation) • 4E79276D-BBFC-43F1-BA51-234B629D807D • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-5 (simulator)

! Doctor found issues in 1 category. Process finished with exit code 0

pichillilorenzo commented 4 years ago

Do you have any errors in the javascript side (using the chrome debugger)?

shouldInterceptAjaxRequest event and the other ones are implemented using javascript, overriding the javascript native XMLHttpRequest object in order to be able to intercept them.

Could you share the javascript ajax code you are using? If you can't, could you make an example that gives to you this error?

Otherwise, for me, it is impossible to debug it.

rbocobo commented 4 years ago

this is the js code to override:


var open = window.XMLHttpRequest.prototype.open,
    send = window.XMLHttpRequest.prototype.send,
    onReadyStateChange;

function openReplacement(method, url, async, user, password) {
    console.log('new data22');
    var syncMode = async !== false ? 'async' : 'sync';
    return open.apply(this, arguments);
}

function sendReplacement(data) {
    console.log('Sending HTTP request data : ', data);

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

function onReadyStateChangeReplacement() {
    console.log('HTTP request ready state changed : ' + this.readyState + ' ' + this.readyState + ' ' + XMLHttpRequest.DONE);
    if (this.readyState === XMLHttpRequest.DONE) {
        if (this.responseText !== "" && this.responseText !== null) {
        var oData = JSON.stringify({'data': this.responseText});
                            console.log('new data');
                            console.log(oData);
           window.flutter_inappwebview.callHandler('myHandler', {foo: oData}).then(function(result) {
                               console.log(result, typeof result);
                               console.log(JSON.stringify(result));
                           })

        }
     }
    if (this._onreadystatechange) {
        return this._onreadystatechange.apply(this, arguments);
    }
}
console.log(openReplacement.toString());
window.XMLHttpRequest.prototype.open = openReplacement;
window.XMLHttpRequest.prototype.send = sendReplacement;

InAppWebView

InAppWebView(
                        initialUrl: Uri.https(authState.companyData.baseUrl,
                                '/administrator/Web.do')
                            .toString(),
                        initialOptions: InAppWebViewGroupOptions(
                          crossPlatform: InAppWebViewOptions(
                              debuggingEnabled: true,
                              useShouldInterceptAjaxRequest: true),
                          android: AndroidInAppWebViewOptions(
                              domStorageEnabled: true),
                          ios: IOSInAppWebViewOptions(
                              sharedCookiesEnabled: true),
                        ),
                        onWebViewCreated:
                            (InAppWebViewController controller) async {
                          webView = controller;
                          await webView.injectJavascriptFileFromAsset(
                              assetFilePath: 'assets/scripts/override.js');
                          webView.addJavaScriptHandler(
                              handlerName: 'myHandler',
                              callback: (params) {
                                print(params);
                              });
                        },
                        onLoadStop: (controller, url) async {
                          if (url.toLowerCase().endsWith('logout.do')) {
                            BlocProvider.of<AdminBloc>(context)
                                .add(AdminPageLogout());
                          }
                          webView.canGoBack().then((value) {
                            setState(() {
                              canGoBack = value;
                            });
                          });
                          webView.canGoForward().then((value) {
                            setState(() {
                              canGoForward = value;
                            });
                          });
                        },
                        onProgressChanged: (controller, progress) {
                          setState(() {
                            loadingProgress = progress / 100;
                          });
                        },
                        shouldInterceptAjaxRequest:
                            (InAppWebViewController controller,
                                AjaxRequest ajaxRequest) async {
                          print(ajaxRequest.url);
                          return ajaxRequest;
                        },
                        onAjaxReadyStateChange:
                            (InAppWebViewController controller,
                                AjaxRequest ajaxRequest) async {
                          print(ajaxRequest.status);
                          return AjaxRequestAction.PROCEED;
                        },
                        onAjaxProgress: (InAppWebViewController controller,
                            AjaxRequest ajaxRequest) async {
                          print(ajaxRequest.status);
                          return AjaxRequestAction.PROCEED;
                        },
                      )
pichillilorenzo commented 4 years ago

You are injecting your javascript too soon. You need to call

await webView.injectJavascriptFileFromAsset(assetFilePath: 'assets/scripts/override.js');

inside the onLoadStop event, otherwise, your js won't work.

However, why are you overriding window.XMLHttpRequest object? This is already done by the plugin. You can use the onAjaxReadyStateChange event.

pichillilorenzo commented 4 years ago

Also, an ajax example is available inside the example/test_driver folder: https://github.com/pichillilorenzo/flutter_inappwebview/blob/master/example/test_driver/in_app_webview_ajax_test.dart

The corresponding server-side (Node.js) that manages the ajax request is here: https://github.com/pichillilorenzo/flutter_inappwebview/blob/f569e369f433d218dac78f43462c83be1c5c4b1d/nodejs_server_test_auth_basic_and_ssl/index.js#L164

github-actions[bot] commented 4 days ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug and a minimal reproduction of the issue.