webの開発の為に多種多様なjavascriptのライブラリが存在しますが、flutter web開発時に使いたくてもdart・flutterでそれらを扱うパッケージが存在しないこともあると思います
そんな場合にはdart側からJavascirptの処理を直接呼び出すサポートをしてくれるのがjs
パッケージです
その基本的な使い方を見ていきます
前提
今回は「 Flutter web
にて外部のjsライブラリもしくは自身で作成したjsの処理を実行する 」事を想定しており、純粋にDartからjs処理を呼び出す事についてはあまり言及しません
概要
全体の流れとしては、以下の通りとなります
-
web
フォルダ配下にjavascriptの処理を定義したファイルを作成 -
web/index.html
内でそのファイルをインポート - Dart(Flutter)側でインポートしたjsファイルの処理を呼び出すメソッドを定義
ファイル構成
.
├── lib
│ ├── my_javascript.dart # このファイルにjs処理を書いていく
│ └── main.dart
│
└── web
├── my_javascript.js # このファイルにjs処理を書いていく
├── index.html
└── manifest.json
基本の流れ
-
js
パッケージをインポートしておく
$ flutter pub add js
- jsのfunctionを定義したファイルをwebディレクトリに作成
function basicFunction() {
console.log("function executed!")
}
-
web/index.html
にて定義したjsファイルをインポート
<script src="my_javascript.js"></script>
- js処理を呼び出すDart側のメソッドを定義
@JS()
library my_javascript;
import 'package:js/js.dart';
@JS('basicFunction')
external void basicFunction();
- 前提としてjsファイルの呼び出し部分の前には
@JS()
アノテーションを付ける -
library
としてjsの処理を定義したファイルを指定 - 定義したjsの処理を割り当てるdartメソッドの前に
@JS(<割り当てるfunction名>)
を付ける - dartメソッドの頭に
external
句を付けて引数、返り値をjsの処理と同様にする
- Dart側のメソッドを実行する
あとはDart側で定義したメソッドを実行するだけです
onPressed: ()=> basicFunction(),
外部jsライブラリの使い方
上記では自分で定義したjavascriptの処理を呼び出しましたが、今度は公開されている外部のjsライブラリを使ってみましょう
扱い方は2通り
外部ライブラリを使う場合は、「自分で定義したjavascriptの処理で使うやり方」と「dart側で直接外部ライブラリの処理を呼び出すやり方」と2通りが存在します
自分で定義したjsの処理で使う
- 外部ライブラリを
web/index.html
でインポートしておく
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
- 自分で定義したjavascriptの処理内で呼び出す
web/index.html
でインポートしておけば、自身のjsファイル内で改めてimportする事なく外部ライブラリの処理を呼ぶ事ができます
// function using library
function functionUsingLibrary(list){
// using max method from lodash
console.log(`biggest number is ${_.max(list)}`)
}
Dart側から直接呼び出す
- 外部ライブラリを
web/index.html
でインポートしておく
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
- Dart側で外部ライブラリの処理を直接呼ぶ
Dart側で直接呼び出す際はlibrary
としてインポートします
@JS('_')
library lodash;
import 'package:js/js.dart';
@JS('uniq')
external List<int> uniq(List<int> list);
どちらが良いのか?
呼び出したいjsの処理がそのライブラリの処理だけであれば、Dart側から直接呼んでも良いですが、複数あったり、今後増える可能性もあるのであれば 自分で定義したjsファイルを用意し、そこに処理を集約させる 方が個人的には分かりやすく、責務もスッキリすると考えています。あくまでも個人的な意見ですが。
jsの処理に引数を渡す
引数を受け取るjs処理があると思います。String
やbool
などプリミティブな型はそのまま渡せますが、オブジェクトを引数として渡す場合は、そのオブジェクトのクラスをjsパッケージを使って定義する必要があります
@JS('functionWithObjectArg')
external void functionWithObjectArg(Person person);
@JS('')
@anonymous
class Person {
external String get name;
external int get age;
external String get message;
external factory Person({String name, int age, String message});
-
js
に用意されている@anonymous
アノテーションを付ける -
@anonymous
アノテーションが付いたクラスではfactory
コンストラクタを定義する必要がある - 通常、名前付き引数は使えないので、上記の通りクラスとして定義し、そのコンストラクタを名前付きにする事で実現させる
onPressed: () => functionWithObjectArg(
Person(
name: 'John',
age: 52,
message: "Hi, I'm John!!",
),
),
jsの処理に関数を引数として渡す
関数を引数で渡したい場合は、渡す関数をallowInterop
メソッドでラップする。onSuccessやonFailureのコールバックメソッドを使う際に有効です。
// example with passing function
function functionWithFunctionArg(func) {
const result = func()
console.log(`function result was ${result}`)
}
@JS('functionWithFunctionArg')
external void functionWithFunctionArg(Function func);
onPressed: () {
functionWithFunctionArg(allowInterop(() {
return 125 + 25;
}));
},
jsのPromiseをdart側で実行する
Promiseのjs処理を呼びたい場合、Dart側でそのままFuture
型に変換する事はできません。
以下二つの対応が必要です
-
js_utilライブラリ
(jsパッケージに内包されている)のpromiseToFuture
関数でFutureに変換する -
promiseToFuture
メソッドは引数としてObject
を受け取る為、dart側のインターフェースでは Objectを返すメソッドとして定義する必要がある
// example with Promise function
async function functionWithPromise() {
console.log("execution started")
await new Promise(resolve => {
setTimeout(resolve, 3000) // wait 3 seconds
});
console.log("call waited 3 seconds")
}
@JS('functionWithPromise')
external Object functionWithPromise();
// 呼び出し
onPressed: () async {
await promiseToFuture(functionWithPromise());
print('execution finished');
},
おわり
コード:
以上の知識があれば、大体のjsライブラリは活用する事が出来るかと思います。Web開発では豊富なjsライブラリを使いたいシーンも、そのライブラリに対応したFlutterパッケージが存在しない事も多々有ります。packages:js
はそんな制約を一気に取っ払ってくれる強力な助っ人です。
参考
https://flutter-square.com/js-call-dart/ (ja)
https://liewjuntung.medium.com/ use-javascript-in-flutter-web-a6eed3efb9a0 (en)
https://qiita.com/tfandkusu/items/b8b498d60ddff3db4d50 (ja)
https://codeburst.io/ how-to-use-javascript-libraries-in-your-dart-applications-e44668b8595d (en)
https://www.youtube.com/watch?v=zoN1_5tYzOM&t=44s (en)