简体   繁体   中英

Call Dart method from JS in Flutter Web

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.

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());
}

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM