When building cross-platform applications that can run on web, mobile and desktop, we often don’t need to access the underlying platform — we are either showing static data or we are communicating with a backend server to post and display newdata.
However, there are cases in which we need to retrieve some information about the platform — device’s specifications, location or hardware such as camera and sensors — or even access a specific native library or API, which requires us to communicate with the platform’s native code.
With Android and iOS we use Platform Channels to send and receive messages from the native platform, and we can use PlatformViews to display native UI views on Flutter. But how we can do it in Flutter Web?
Before Flutter was revealed to the public, Dart was used to build web apps (as you can see in this article from 2013 — Develop modern web apps with Dart by Seth Ladd), which was possible due to two of its features:
This means that we have a direct way to communicate with
To use the
js package, we must declare in a separate file the functions in
As an example, let’s look at the documentation and see how it is possible to use
JSON.stringify in Dart:
librarystatement has the
@JS()annotation, followed by the
@JSis used to specify which function we are calling, in this case,
JSON.stringify. Note that the declared function has no body and is
external, which you can read more about in this StackOverflow answer.
Showing an Alert Window on Flutter
To use it, we must need to use the following code in
In out Flutter app, we may want to give it another name, such as
showConfirm, and for that we can use the
@JS annotation as in the documentation’s example:
Then, we can simply call this method on our Flutter app:
And sure enough a new confirm window is going to be displayed to the user:
The Problem of Multiplatform
As stated previously, when using Flutter we can deploy our apps to multiple platforms. However, in the previous example we are using a
If we try to run our app in an iOS device, we will get the following compilation error:
dart:html. One way to go around this is to use conditional importing, which you can read more in Antonello Galipò’s Article: Conditional imports across Flutter and Web.
We start by creating a
stub class in which we declare all the methods we will be using, in this case the
Then, we can have one file per platform where we specify the implementation of the
showConfirm method. For our purpose, we are going to leave this as it is, since it enables us to compile our app to all platforms, if needed we will specify each implementation in the future.
Finally, we change our simple imports to conditional imports at the top of the file where we use the
In summary, this is importing the
stub_bundler.dart by default, however, if it verifies that the platform can access to
While developing our apps, there might be the need to add a specific feature that has been already in the platform that we are developing for such as Google Maps.
Google Maps libraries are widely available for Android, iOS and Web, and instead of recreating it in Flutter, Google’s approach was to use these native libraries and display them in Flutter (you can see the implementation in the official
google_maps_ flutter GitHub repository).
In the case of web, we don’t have a
Pod file or
gradle to add our dependencies, so we must add them to our
web folder, either declaring them on the
index.html file directly or by adding a new
.js file in the structure.
To demonstrate this, we are going to add a simpler library — Voca , which allows us to manipulate our Strings like converting text to camel case.
We start by downloading the normal, not minified version, of file so that we can take a peek into the class names and comments. Next, we add it to our project, in a
js folder inside
index.html file, we can add the script right below the
Before integrating any other code, we run the app to verify if there are any errors present, and though the app runs, the Chrome Dev Tools (F12), shows a long error message that starts with:
Uncaught Error: Mismatched anonymous define()
A quick google search will show the Require.js website with the following page: Mismatched anonymous define() modules …. Upon further inspection we see that
voca.js uses, meaning that we will need to add it to our app too.
So, let us dive into the Start page to integrate it in our Flutter app.
The first thing that we need to do is to rearrange the structure of the code to follow
require.js, we just need to download the latest binary from the Download section of the website and add it to the
js folder. For the case of
voca.js, we just moved the file from the root folder to the
As with before, we must add this new dependency to our
index.html file and remove the
voca.js dependency. Since we are using
require.js we need to not only add it but to add the dependency to
main.js , which is explained in this StackOverflow answer.
Reading the documentation for
voca.js, we see that we will need to access
v in order to call each function. As such, we will create a
@JS() class in Dart and specify each
static method that we want to use:
To call this method, we will just need to call:
Finally, since we are want to make our project compilable for all platforms, we create a new method called
toCamelCase in which we call
V.camelCase directly. This means that both our
stub file and the remaining mobile and desktop implementations will just need to create a method called
toCamelCase instead of a specific class and a static method:
In our Flutter app, we will be able to call this function directly:
As with Flutter for mobile devices, it’s always possible to communicate with the underlying platform to access a native API or a specific library. For Flutter Web, it’s going to be easier since we don’t need to use a
PlatformChannel and can instead call the code (almost) directly with the
Thankfully, the Dart team already has provided us with a lot of out-of-the-box methods for the most common operations via the
window variable 🥳
However, each time that we want to add an external library, we will need to rely on the
js library and create the bindings.
You can find the repository for this article here:
A new Flutter project. This project is a starting point for a Flutter application. A few resources to get you started…