Flutter Engine
The Flutter Engine
|
Dart web platform libraries e.g. dart:html
is partially hand-written and partially generated, with the code generation using the Chrome IDL as the source of truth for many browser interfaces. This introduces a dependency on the version of the IDL and doesn’t always match up with other browser interfaces.
Currently, we do not intend on updating our scripts to use a newer version of the IDL, so APIs and classes in these libraries may be inaccurate.
In order to work around this, we ask users to leverage JS interop. Longer term, we intend to revamp our web library offerings to be more robust and reliable.
The following are workarounds to common issues you might see with using the web platform libraries.
As mentioned above, there exists stale interfaces. While some of these may be fixed in the source code, many might not.
In order to work around this, you can use the annotation @staticInterop
from package:js
.
Let’s look at an example. FileReader
is a dart:html
interface that is missing the API readAsBinaryString
(#42834). We can work around this by doing something like the following:
Alternatively, you can directly use the js_util
library, using the methods getProperty
, setProperty
, callMethod
, and callConstructor
.
In the case where the API is missing a constructor, we can define a constructor within a @staticInterop
class. Note that constructors, external
or otherwise, are disallowed in extensions currently. For example:
or with js_util
's callConstructor
:
There are several native interfaces that are suppressed e.g. USBDevice
(#42200) due to historical reasons. These native interfaces are marked with @Native
, are private, and have no attributes associated with them. Therefore, unlike other @Native
objects, we can’t access any of the APIs or attributes associated with this interface. We can again either use the @staticInterop
annotation or use the js_util
library to circumvent this issue. For example, we can abstract a _SubtleCrypto
object:
or with js_util
:
Avoid casting these native objects to non-@staticInterop
package:js
types e.g.
With the above, you’ll see a static error:
‘Error: Non-static JS interop class 'SubtleCrypto’ conflicts with natively supported class '_SubtleCrypto' in 'dart:html'.`
This is because the types in the @Native
annotation are reserved and the above leads to namespace conflicts between the @Native
type and the user JS interop type in the compiler. @staticInterop
classes, however, don't have this issue.
One alternative that seems viable is to use a static extension on the @Native
type in dart:html
directly, e.g.
This may work fine, as long as FileReader
does not add readAsBinaryString
. In the case where this API is added to the class, Dart will prioritize that instance method over the extension method you wrote. This may lead to issues, like a type error when the signatures between the two methods are incompatible, or confusing runtime behavior.
Furthermore, you may come across API conflicts with other users who have also defined extension methods on these @Native
types.
To avoid the above, it's recommended you stick with @staticInterop
.
In the future, when views/extension types are introduced to the language, this guidance will likely change so that you can directly use views on @Native
types.