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

[webview_flutter_web] Add support for JavaScript channels #1

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Frank3K
Copy link
Collaborator

@Frank3K Frank3K commented Apr 3, 2023

This pull request implements JavaScript channels for webview_flutter_web, allowing postMessage communication from a web application to Flutter.

The regular webview_flutter package already supports JavaScript channels for iOS and Android, making is possible to send messages from a web application to Flutter.

Related issues

Flutter issue asking for support: flutter/flutter#101758.

How it works

On iOS and Android it is possible to send messages on a JavaScript channel using the postMessage API. This API is very simple: it only allows a single string argument (docs). On Web, there's the postMessage API on window, on which arbitrary data can be sent. Since the postMessage API for Android and iOS is a subset (string vs object), the web postMessage API can be used to implement the JavaScript channel.

Demo-videos

The following demo show a small application which sends a postMessage to the Flutter application.

Screen.Recording.2023-04-06.at.12.42.57.mov
Screen.Recording.2023-04-06.at.20.33.57.mov

PoC code

Flutter side

    ...
    webViewController = WebViewController();
    webViewController.addJavaScriptChannel(
      'flutterApp',
      onMessageReceived: (message) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(message.message),
          ),
        );
      },
    );
   ...

Web side

HTML
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>HTML5 Example Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="description" content="HTML5 Example Page" />
    <style type="text/css">
      body {
        font-family: sans-serif;
      }
    </style>
    <script type="text/javascript" src="demo.js"></script>
  </head>
  <body>
    <header>
      <h1>HTML5 Example Page</h1>
    </header>
    <button onclick="helloWorld()">Hello world</button>
    <button onclick="userAgent()">Show userAgent</button>
  </body>
</html>
JavaScript
function sendMessage(message) {
  const channel = window["flutterApp"] || window.parent;
  if (!channel) {
    return;
  }

  channel.postMessage(message, '*');
}

function helloWorld() {
  sendMessage("Hello world");
}

function userAgent() {
  sendMessage(window.navigator.userAgent);
}

Web implementation notes and limitations

Security

In the above PoC the postMessage is sent with * as target origin. This is considered bad practice. The web application should use the origin of the flutter web application as the target origin.

Named JavaScript channels

On iOS and Android it is possible to name a JavaScript channel. On web, this is not possible since that would require injecting JavaScript code into the iframe (which is not possible cross-origin). Therefore the web application uses window.parent (using window["flutterApp"] || window.parent) to get to the flutter application. Therefore the web implementation only allows a single channel.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the relevant style guides and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use dart format.)
  • I signed the CLA.
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I listed at least one issue that this PR fixes in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.
  • I updated CHANGELOG.md to add a description of the change, following repository CHANGELOG style.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Comment on lines 127 to 128
// TODO: what to return?
return Future.wait([]);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@omartinma I'm not sure what to return here (and below).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Frank3K, When using Future<void> there is no need to explicitly return anything.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I thought too, but when I remove the return Future.wait([]); I get the following error:

The body might complete normally, causing 'null' to be returned, but the return type, Future<void>, is a potentially non-nullable type.
Try adding either a return or a throw statement at the end. dart(body_might_complete_normally)

image

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Frank3K It could be because you are missing the async modifier in the function.

It should look like this:

@override
  Future<void> addJavaScriptChannel(
    JavaScriptChannelParams javaScriptChannelParams,
  ) async {
 ...
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I tried something similar earlier, but could not get it to compile properly back then.

@Frank3K
Copy link
Collaborator Author

Frank3K commented Apr 3, 2023

Please note that the current implementation contains a prefer_function_declarations_over_variables warning. Let's first see if we think this solution is a good solution in the first place.

Comment on lines 119 to 124
final Null Function(html.Event) handler = (html.Event event) {
if (event is html.MessageEvent) {
javaScriptChannelParams.onMessageReceived(
JavaScriptMessage(message: event.data.toString()));
}
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@omartinma This triggers a prefer_function_declarations_over_variables warning. Should we fix that warning before submitting the PR? I tried refactoring it myself, but could not get the typings correct.

@Frank3K Frank3K changed the title feat: add support for JavaScript channels [webview_flutter_web] Add support for JavaScript channels Apr 6, 2023
@Frank3K Frank3K force-pushed the feat/javascript-channels branch from a7799e5 to 5b5b6e3 Compare April 6, 2023 18:59
Frank3K pushed a commit that referenced this pull request Apr 5, 2024
flutter/flutter@f52fe4f...83134ac

2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2b3f9886fbf0 to 60e861dfe6b1 (1 revision) (flutter/flutter#136264)
2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from e354a13cfeab to 2b3f9886fbf0 (4 revisions) (flutter/flutter#136259)
2023-10-10 engine-flutter-autoroll@skia.org Roll Packages from 7de08ec to 4b483f2 (8 revisions) (flutter/flutter#136258)
2023-10-10 sokolovskyi.konstantin@gmail.com RenderAnnotatedRegion should dispose created layers. (flutter/flutter#136086)
2023-10-10 polinach@google.com TestClipPaintingContext should dispose ContainerLayer (flutter/flutter#135949)
2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9aa7cb057d22 to e354a13cfeab (1 revision) (flutter/flutter#136248)
2023-10-10 104349824+huycozy@users.noreply.github.com Migrate the "Non-speed related performance issues" issue template to Github forms (flutter/flutter#135130)
2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from 171b4b26e68b to 9aa7cb057d22 (4 revisions) (flutter/flutter#136240)
2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from d094401acb99 to 171b4b26e68b (1 revision) (flutter/flutter#136235)
2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from 92880e9847b3 to d094401acb99 (1 revision) (flutter/flutter#136233)
2023-10-10 engine-flutter-autoroll@skia.org Roll Flutter Engine from 51193f8f53eb to 92880e9847b3 (1 revision) (flutter/flutter#136232)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 8f2fa3ceb8a0 to 51193f8f53eb (4 revisions) (flutter/flutter#136228)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 73da593bac54 to 8f2fa3ceb8a0 (2 revisions) (flutter/flutter#136220)
2023-10-09 chillers@google.com [conductor] Remove PublishChannel and use MPA command (flutter/flutter#135884)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0966f62d7101 to 73da593bac54 (1 revision) (flutter/flutter#136216)
2023-10-09 41873024+droidbg@users.noreply.github.com [leak-tracking] Add leak tracking in test/painting #1 (flutter/flutter#136167)
2023-10-09 41873024+droidbg@users.noreply.github.com [leak-tracking] Cover testwidgets with leak tracking in test/gestures (flutter/flutter#136166)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 81e5bf29dee4 to 0966f62d7101 (1 revision) (flutter/flutter#136215)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 22ce5c6a45e2 to 81e5bf29dee4 (3 revisions) (flutter/flutter#136211)
2023-10-09 110993981+htoor3@users.noreply.github.com [web] Fix `page up` `page down` `home` `end` shortcut behavior on web (flutter/flutter#135454)
2023-10-09 gspencergoog@users.noreply.github.com Update `MediaQuery` documentation to highlight asynchronous nature of size (flutter/flutter#135719)
2023-10-09 47866232+chunhtai@users.noreply.github.com Reland "Adds a parent scope TraversalEdgeBehavior and fixes modal rou� (flutter/flutter#134554)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 429a242b0db6 to 22ce5c6a45e2 (1 revision) (flutter/flutter#136205)
2023-10-09 engine-flutter-autoroll@skia.org Roll Packages from e578a16 to 7de08ec (4 revisions) (flutter/flutter#136202)
2023-10-09 engine-flutter-autoroll@skia.org Roll Flutter Engine from 664f5e833871 to 429a242b0db6 (2 revisions) (flutter/flutter#136201)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants