addWebMessageListener method
Adds a PlatformWebMessageListener to the WebView and injects a JavaScript object into each frame that the PlatformWebMessageListener will listen on.
The injected JavaScript object will be named PlatformWebMessageListener.jsObjectName in the global scope. This will inject the JavaScript object in any frame whose origin matches PlatformWebMessageListener.allowedOriginRules for every navigation after this call, and the JavaScript object will be available immediately when the page begins to load.
Each PlatformWebMessageListener.allowedOriginRules entry must follow the format SCHEME "://" [ HOSTNAME_PATTERN [ ":" PORT ] ]
, each part is explained in the below table:
Rule | Description | Example |
---|---|---|
http/https with hostname | SCHEME is http or https; HOSTNAME_ is a regular hostname; PORT is optional, when not present, the rule will match port 80 for http and port
443 for https.
|
|
http/https with pattern matching | SCHEME is http or https; HOSTNAME_ is a sub-domain matching
pattern with a leading *. ; PORT is optional, when not present, the rule will
match port 80 for http and port 443 for https.
|
|
http/https with IP literal | SCHEME is https or https; HOSTNAME_ is IP literal; PORT is
optional, when not present, the rule will match port 80 for http and port 443
for https.
|
|
Custom scheme | SCHEME is a custom scheme; HOSTNAME_ and PORT must not be
present.
|
|
* |
Wildcard rule, matches any origin. |
|
Note that this is a powerful API, as the JavaScript object will be injected when the frame's origin matches any one of the allowed origins. The HTTPS scheme is strongly recommended for security; allowing HTTP origins exposes the injected object to any potential network-based attackers. If a wildcard "*" is provided, it will inject the JavaScript object to all frames. A wildcard should only be used if the app wants any third party web page to be able to use the injected object. When using a wildcard, the app must treat received messages as untrustworthy and validate any data carefully.
This method can be called multiple times to inject multiple JavaScript objects.
Let's say the injected JavaScript object is named myObject
. We will have following methods on that object once it is available to use:
// Web page (in JavaScript)
// message needs to be a JavaScript String, MessagePorts is an optional parameter.
myObject.postMessage(message[, MessagePorts]) // on Android
myObject.postMessage(message) // on iOS
// To receive messages posted from the app side, assign a function to the "onmessage"
// property. This function should accept a single "event" argument. "event" has a "data"
// property, which is the message string from the app side.
myObject.onmessage = function(event) { ... }
// To be compatible with DOM EventTarget's addEventListener, it accepts type and listener
// parameters, where type can be only "message" type and listener can only be a JavaScript
// function for myObject. An event object will be passed to listener with a "data" property,
// which is the message string from the app side.
myObject.addEventListener(type, listener)
// To be compatible with DOM EventTarget's removeEventListener, it accepts type and listener
// parameters, where type can be only "message" type and listener can only be a JavaScript
// function for myObject.
myObject.removeEventListener(type, listener)
We start the communication between JavaScript and the app from the JavaScript side. In order to send message from the app to JavaScript, it needs to post a message from JavaScript first, so the app will have a PlatformJavaScriptReplyProxy object to respond. Example:
// Web page (in JavaScript)
myObject.onmessage = function(event) {
// prints "Got it!" when we receive the app's response.
console.log(event.data);
}
myObject.postMessage("I'm ready!");
// Flutter App
child: InAppWebView(
onWebViewCreated: (controller) async {
if (defaultTargetPlatform != TargetPlatform.android || await WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
await controller.addWebMessageListener(WebMessageListener(
jsObjectName: "myObject",
onPostMessage: (message, sourceOrigin, isMainFrame, replyProxy) {
// do something about message, sourceOrigin and isMainFrame.
replyProxy.postMessage("Got it!");
},
));
}
await controller.loadUrl(urlRequest: URLRequest(url: WebUri("https://www.example.com")));
},
),
NOTE for Android: This method should only be called if WebViewFeature.isFeatureSupported returns true
for WebViewFeature.WEB_MESSAGE_LISTENER.
NOTE for iOS: it is implemented using JavaScript.
NOTE for MacOS: it is implemented using JavaScript.
Officially Supported Platforms/Implementations:
- Android native WebView (Official API - WebViewCompat.WebMessageListener)
- iOS
- MacOS
Implementation
Future<void> addWebMessageListener(WebMessageListener webMessageListener) =>
platform.addWebMessageListener(webMessageListener.platform);