7

For a Webview relate feature I had used Method channels to open Webview through Native Android & iOS code and I am opening a website in it, I was getting callback from JS to native code in mobile platforms. For Android I was providing a class whose method is getting called from JS, It looks something like this:

webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(WebAppInterface(this), "nativeCommunicator")

webView.loadUrl("SOME_URL")

…

class WebAppInterface(private val mContext: Activity) {
  @JavascriptInterface
  fun postMessage(text: String) {
    println("WebAppInterface.message($text)")
    //send back to flutter
  }
}

Which seems quite straightforward way to get callback from js to my code.

Now I am trying to do this in Flutter Web I opened the website by calling

import 'package:js/js.dart';
...
js.context.callMethod('open', 'SOME_URL', '_self');

Which works fine, Now I am trying to get callback by creating this class

@JS()
library native_communicator;

import 'package:js/js.dart';
@JS('nativeCommunicator')
class NativeCommunicator{

 @JS('postMessage')
 external static set _postMessage(void Function(String text) f);


 @JS()
 external static void postMessage();

}

void setJSCallbackFunction(void Function(String text) postMessageFunction) {
 NativeCommunicator._postMessage = allowInterop(postMessageFunction);
}

I am calling setJSCallbackFunction and passing my function as param, but it keeps giving me runtime error that It can not find ‘postMessage’, I tried some other way which leads to can not find ‘nativeCommunicator’ error, Can anyone point out how to do this right? I need to call a dart method from js.

2 Answers 2

10
+200

Making a Dart function callable from JavaScript

If you pass a Dart function to a JavaScript API as an argument, wrap the Dart function using allowInterop() or allowInteropCaptureThis().

To make a Dart function callable from JavaScript by name, use a setter annotated with @JS().

Sample:

@JS()
library callable_function;

import 'package:js/js.dart';

/// Allows assigning a function to be callable from `window.functionName()`
@JS('functionName')
external set _functionName(void Function() f);

void _someDartFunction() {
  print('Hello from Dart!');
}

void main() {
  _functionName = allowInterop(_someDartFunction);
  // JavaScript code may now call `functionName()` or `window.functionName()`.
}

From package:js docs

Changes -

@JS()
library native_communicator;

import 'package:js/js.dart';
@JS('nativeCommunicator')
class NativeCommunicator{

 @JS('postMessage')
 external static set _postMessage(void Function(String text) f);

// No need to do this as 'allowInterop()' will do the necessary.
//
// @JS()
// external static void postMessage();
//
// }

void setJSCallbackFunction(void Function(String text) postMessageFunction) {
 NativeCommunicator._postMessage = allowInterop(postMessageFunction);
}
import 'path/to/setJSCallbackFunction-file';

void main() {
    setJSCallbackFunction(param);
}

Steps to debug

  1. Look for generated js file - build/web/main.dart.js
  2. Try using search to locate the function. (Here, postMessage)
  3. If you can't find it, then you might have missed some annotations or might not have called allowInterop() in main()
  4. If you are able to find it but it isn't working, check your dart function and make sure you are passing the right parameters. Also, make sure that dart.main.js is in scope.
<script src"path/to/dart.main.js">
window.functionName(); // or functionName()
</script>

Prefer to define the js function as a top-level function which can be called with window.functionName() or functionName()

Sign up to request clarification or add additional context in comments.

Comments

5

I think you're looking for allowInterop function from dart:js library: https://api.flutter.dev/flutter/dart-js/dart-js-library.html

Sample code:

import 'dart:html';
import 'dart:js';
import 'package:js/js_util.dart';

String dartFunc(String str) {
  return 'Inside dartFunc: ' + str;
}

void main() {
  setProperty(window, 'dartFunc', allowInterop(dartFunc));
  runApp(MyApp());
}

5 Comments

It's right there in my code. please check, Did you try it and had working sample?
Sorry, didn't notice it. I've updated the answer with some sample code.
How do you call it from js?
It's defined on the global window object, so you can reference it by dartFunc or window.dartFunc
Are there any security implications to consider when using this solution? Is it safe as long as I give precise control to a specific method?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.