Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not Getting callbacks from javascriptHandler in android #2431

Closed
1 of 2 tasks
Febinjohnson96 opened this issue Nov 26, 2024 · 13 comments
Closed
1 of 2 tasks

Not Getting callbacks from javascriptHandler in android #2431

Febinjohnson96 opened this issue Nov 26, 2024 · 13 comments
Labels
bug Something isn't working

Comments

@Febinjohnson96
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Im using inappwebview communication with javascript handler. But The handler is not getting callbacks.

Expected Behavior

Expecting to get the value from web to flutter.

Steps with code example to reproduce

Code of javascript handler used
 onWebViewCreated: (controller) {
                    debugPrint("onWebViewCreated $controller");
                    webViewController = controller;
                    webViewController?.addJavaScriptHandler(
                      handlerName: 'ResponseChannel',
                      callback: (arguments) {
                        debugPrint("Data received from Angular : $arguments");
                        if (arguments.isNotEmpty) {
                          debugPrint(
                              "Data received from Angular: ${arguments[0]}");
                        } else {
                          debugPrint("No data received from Angular");
                        }
                      },
                    );
                  },

Stacktrace/Logs

Stacktrace/Logs
no log

Flutter version

v3.24.5

Operating System, Device-specific and/or Tool

Android (Emulator)

Plugin version

v6.1.5

Additional information

I was able to find this reading documentation. Is this the correct method? When using webiew_flutter im able to get the result im expected .

Self grab

  • I'm ready to work on this issue!
@Febinjohnson96 Febinjohnson96 added the bug Something isn't working label Nov 26, 2024
@Febinjohnson96 Febinjohnson96 changed the title Not Getting callbacks from javascriptHandler Not Getting callbacks from javascriptHandler in android Nov 26, 2024
@pichillilorenzo
Copy link
Owner

Do you call the callback correctly on JavaScript side? How do you call it?

@Febinjohnson96
Copy link
Author

Febinjohnson96 commented Nov 26, 2024

This is how i call on the web side

  if (window.flutter_inappwebview) {
    console.log('Calling flutter_inappwebview');
    window.flutter_inappwebview.callHandler(
      'ResponseChannel',
      data
    );
    console.log('Data sent via flutter_inappwebview');
    return;
  }

@pichillilorenzo
Copy link
Owner

Ok, please post some logs. Also, you mentioned Android but not the Android version. Please, add that info.

@Febinjohnson96
Copy link
Author

Android 33 and im getting a console log in this. But not on the callback


I/chromium(12580): [INFO:CONSOLE(8)] "Form submitted: [object Object]", source: http://{url}/main-J2BN3GQX.js (8)
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: Form submitted: [object Object]}
I/chromium(12580): [INFO:CONSOLE(8)] "Status Code: 200", source: http://{url}/main-J2BN3GQX.js (8)
I/chromium(12580): [INFO:CONSOLE(8)] "Message posted successfully", source: http://{url}/main-J2BN3GQX.js (8)
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: Status Code: 200}
I/chromium(12580): [INFO:CONSOLE(8)] "Response Body: [object Object]", source: http://{url}/main-J2BN3GQX.js (8)
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: Message posted successfully}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onConsoleMessage" using {messageLevel: 1, message: Response Body: [object Object]}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadResource" using [{url: http://{url}/api/v1/students/new, initiatorType: xmlhttprequest, startTime: 17505.699999999255, duration: 339.1000000014901}]

@pichillilorenzo
Copy link
Owner

Are you sure you are reaching that specific code? There is no console log about Calling flutter_inappwebview that you have inside your if

@Febinjohnson96
Copy link
Author

the code is reaching there.. and the information im passing through reaches the db.. This is not triggering on the flutter inappwebview. I've tried this with webview_flutter and im getting the response back through callback. But for this case its not callback is not triggering. And this is the correct way to invoke handler right? from web ?

 if (window.flutter_inappwebview) {
    console.log('Calling flutter_inappwebview');
    window.flutter_inappwebview.callHandler(
      'ResponseChannel',
      data
    );
    console.log('Data sent via flutter_inappwebview');
    return;
  }

is there any issues on this?!

@pichillilorenzo
Copy link
Owner

Do you mean that if (window.flutter_inappwebview) { is false?

@Febinjohnson96
Copy link
Author

Febinjohnson96 commented Nov 26, 2024

no this part. is this correct? Anything i missed?

window.flutter_inappwebview.callHandler(
'ResponseChannel',
data
);

@pichillilorenzo
Copy link
Owner

pichillilorenzo commented Nov 26, 2024

It is correct. Have you tried to inspect with Chrome Developer Tools for remote debugging? Do you see any JavaScript error there?

could you also post your full InAppWebView code implementation?

@Febinjohnson96
Copy link
Author

Here's the implemention of inappwebview



  InAppWebViewSettings settings = InAppWebViewSettings(
    useOnNavigationResponse: true,
    cacheMode: CacheMode.LOAD_CACHE_ELSE_NETWORK,
    javaScriptEnabled: true,
    javaScriptCanOpenWindowsAutomatically: true,
    disableDefaultErrorPage: true,
    allowFileAccessFromFileURLs: true,
    allowUniversalAccessFromFileURLs: true,
    allowFileAccess: true,
    domStorageEnabled: true,
    useOnLoadResource: true,
    mediaPlaybackRequiresUserGesture: false,
    allowContentAccess: true
  );

                InAppWebView(
                  key: webViewKey,
                  initialUrlRequest:
                      URLRequest(url: WebUri("http://{url}/")),
                  initialSettings: settings,
                  pullToRefreshController: pullToRefreshController,

                  onWebViewCreated: (controller) {
                    debugPrint("onWebViewCreated $controller");
                    webViewController = controller;
                    webViewController?.addJavaScriptHandler(
                      handlerName: 'ResponseChannel',
                      callback: (arguments) {
                        debugPrint("Data received from Angular: $arguments");
                        if (arguments.isNotEmpty) {
                          debugPrint(
                              "Data received from Angular: ${arguments[0]}");
                        } else {
                          debugPrint("No data received from Angular");
                        }
                      },
                    );
                  },
                  onLoadStart: (controller, url) {
                    setState(() {
                      this.url = url.toString();
                      urlController.text = this.url;
                    });
                  },
                  onPermissionRequest: (controller, request) async {
                    return PermissionResponse(
                        resources: request.resources,
                        action: PermissionResponseAction.GRANT);
                  },

@pichillilorenzo
Copy link
Owner

I'm not able to reproduce the issue. There is something that you are not doing correctly but I don't know, probably on JavaScript side.

Here is a simple test (using your settings or not didn't change anything to this test):

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();

  if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) {
    await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);
  }

  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final GlobalKey webViewKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("Test")),
        body: SafeArea(
            child: Column(children: <Widget>[
          Expanded(
            child: Stack(
              children: [
                InAppWebView(
                  key: webViewKey,
                  initialData: InAppWebViewInitialData(data: """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="test">TEST</button>
    <script>
        document.querySelector("#test").addEventListener("click", function() {
            const data = {
              foo: "bar",
              arr: [1, true, 3],
              obj: {a: 1, b: false, c: 3},
            };
            window.flutter_inappwebview.callHandler(
              'ResponseChannel', 
              data
            );
        });
    </script>
</body>
</html>
                    """),
                  onWebViewCreated: (controller) {
                    controller.addJavaScriptHandler(
                      handlerName: 'ResponseChannel',
                      callback: (arguments) {
                        debugPrint("Data received from Angular : $arguments");
                        if (arguments.isNotEmpty) {
                          debugPrint(
                              "Data received from Angular: ${arguments[0]}");
                        } else {
                          debugPrint("No data received from Angular");
                        }
                      },
                    );
                  },
                  onConsoleMessage: (_, consoleMessage) async {
                    if (kDebugMode) {
                      print(consoleMessage.message);
                    }
                  },
                  onLoadStop: (controller, url) async {
                    // just for test
                    controller.evaluateJavascript(source: """document.querySelector("#test").click();""");

                    await Future.delayed(const Duration(seconds: 2));
                    // you can try also this
                    controller.evaluateJavascript(source: """
                      const data = {
                        foo: "bar",
                        arr: [1, true, 3],
                        obj: {a: 1, b: false, c: 3},
                      };
                      window.flutter_inappwebview.callHandler(
                        'ResponseChannel', 
                        data
                      );
                    """);
                  },
                )
              ],
            ),
          ),
        ])));
  }
}

Logs:

[AndroidInAppWebViewWidget] (android) AndroidInAppWebViewWidget ID 0 calling "onWebViewCreated" using []
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 10}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStart" using {url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onUpdateVisitedHistory" using {isReload: false, url: about:blank}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 70}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onTitleChanged" using {title: Document}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onProgressChanged" using {progress: 100}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onLoadStop" using {url: about:blank}
I/flutter (13845): Data received from Angular : [{foo: bar, arr: [1, true, 3], obj: {a: 1, b: false, c: 3}}]
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onPageCommitVisible" using {url: about:blank}
I/flutter (13845): Data received from Angular: {foo: bar, arr: [1, true, 3], obj: {a: 1, b: false, c: 3}}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onZoomScaleChanged" using {oldScale: 2.625, newScale: 0.65625}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "ResponseChannel" using [{foo: bar, arr: [1, true, 3], obj: {a: 1, b: false, c: 3}}]
D/EGL_emulation(13845): app_time_stats: avg=26605.86ms min=26605.86ms max=26605.86ms count=1
D/EGL_emulation(13845): app_time_stats: avg=26606.18ms min=26606.18ms max=26606.18ms count=1
D/EGL_emulation(13845): app_time_stats: avg=2231.77ms min=2231.77ms max=2231.77ms count=1
[AndroidInAppWebViewController] (android) WebView ID 0 calling "onZoomScaleChanged" using {oldScale: 0.65625, newScale: 2.625}
D/EGL_emulation(13845): app_time_stats: avg=292.49ms min=11.86ms max=900.21ms count=4
I/flutter (13845): Data received from Angular : [{foo: bar, arr: [1, true, 3], obj: {a: 1, b: false, c: 3}}]
I/flutter (13845): Data received from Angular: {foo: bar, arr: [1, true, 3], obj: {a: 1, b: false, c: 3}}
[AndroidInAppWebViewController] (android) WebView ID 0 calling "ResponseChannel" using [{foo: bar, arr: [1, true, 3], obj: {a: 1, b: false, c: 3}}]

@dawid-niedzwiecki
Copy link

I am experiencing the same issue, seems like on the web side, window.isFlutterInAppWebViewReady is not being called

@pichillilorenzo
Copy link
Owner

pichillilorenzo commented Dec 3, 2024

@dawid-niedzwiecki window.isFlutterInAppWebViewReady doesn't exist. Check the official docs on how javascript communication works: https://inappwebview.dev/docs/webview/javascript/communication

You can listen for the window.addEventListener("flutterInAppWebViewPlatformReady", function(event) {, but it depends on your javascript web page business logic.
The flutterInAppWebViewPlatformReady event could be already dispatched before you listen to it in JavaScript.

On Android, if the WebView supports the feature WebViewFeature.DOCUMENT_START_SCRIPT, you probably don't need to listen to flutterInAppWebViewPlatformReady window js event.
Also, if you are using the javascript handlers after the web page has been already loaded, you don't need to listen that event either.

If you MUST use for whatever reason the flutterInAppWebViewPlatformReady window js event, then, just as an example, you can implement a logic as follow:

// execute inside the "flutterInAppWebViewPlatformReady" event listener
window.addEventListener("flutterInAppWebViewPlatformReady", function(event) {
 const args = [1, true, ['bar', 5], {foo: 'baz'}];
 window.flutter_inappwebview.callHandler('myHandlerName', ...args);
});

// or using a global flag variable
var isFlutterInAppWebViewReady = false;
window.addEventListener("flutterInAppWebViewPlatformReady", function(event) {
 isFlutterInAppWebViewReady = true;
});
// then, somewhere in your code
if (isFlutterInAppWebViewReady) {
 const args = [1, true, ['bar', 5], {foo: 'baz'}];
 window.flutter_inappwebview.callHandler('myHandlerName', ...args);
}

However, you can take my example of the previous comment and update it to your needs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants