Flutter JavaScript交互插件js_wrapping的使用
Flutter JavaScript交互插件 js_wrapping
的使用
js_wrapping
是一个允许开发者为 JavaScript 对象定义良好类型的接口的 Dart 包。通过这个包,你可以创建与 JavaScript 对象交互的 Dart 类,并且这些类具有明确的 Dart API,包括类型注释、构造函数,甚至可选和命名参数。
编写 JS Wrapper
假设有一个 JavaScript 类如下:
LatLng = function(lat, lng) {
this.lat = lat;
this.lng = lng;
}
LatLng.prototype.equals = function(other) {
return this.lat === other.lat && this.lng === other.lng;
}
你可以创建一个包装类如下:
@JsName()
abstract class LatLng {
factory LatLng(num lat, num lng, [bool noWrap]) => $js;
bool equals(LatLng other);
num get lat => _lat();
@JsName('lat')
num _lat();
num get lng => _lng();
@JsName('lng')
num _lng();
String toString();
String toUrlValue([num precision]);
}
一旦生成器执行完毕,你就可以使用 LatLng
来包装一个 JavaScript 的 LatLng
对象。
配置和初始化
添加依赖
在你的 pubspec.yaml
文件中添加以下内容:
dependencies:
js_wrapping: ^0.6.0
dev_dependencies:
js_wrapping_generator: ^0.6.0
运行生成器
参考 source_gen package 的运行生成器部分。
使用方法
定义 Typed JavaScript Interfaces
要创建一个 Typed JavaScript Interface,你需要从创建一个标记有 @JsName()
的类开始。它将作为创建 JavaScript 接口的模板。
@JS('google.maps')
library google_maps.sample.simple;
import 'package:js_wrapping/js_wrapping.dart';
@JsName()
abstract class LatLng {
factory LatLng(num lat, num lng, [bool noWrap]) => $js;
bool equals(LatLng other);
num get lat => _lat();
@JsName('lat')
num _lat();
num get lng => _lng();
@JsName('lng')
num _lng();
String toString();
String toUrlValue([num precision]);
}
生成器会生成一个新的库 mylib.g.dart
,包含以下内容:
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// JsWrappingGenerator
// **************************************************************************
// Copyright (c) 2015, Alexandre Ardhuin. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
@JS('google.maps')
library google_maps.sample.simple;
import 'package:js_wrapping/js_wrapping.dart';
@JS()
class LatLng {
external LatLng(num lat, num lng, [bool noWrap]);
external bool equals(LatLng other);
external String toString();
external String toUrlValue([num precision]);
}
extension LatLng$Ext on LatLng {
num get lat => _lat();
num get lng => _lng();
num _lat() => callMethod(this, 'lat', []);
num _lng() => callMethod(this, 'lng', []);
}
构造函数用于创建 JS 对象
如果 LatLng
是一个 JavaScript 对象/函数,你可以在 JavaScript 中用 LatLng()
创建一个新实例。为了使 Dart 侧能够创建这样的 JavaScript 实例,你需要定义一个 factory
构造函数:
@JsName()
abstract class LatLng {
factory LatLng(num lat, num lng, [bool noWrap]) => $js;
}
这将生成:
@JS()
class LatLng {
external LatLng(num lat, num lng, [bool noWrap]);
}
现在可以通过 LatLng()
在 Dart 中实例化 JavaScript 对象。
属性和访问器
可以向类中添加属性或抽象的 getter/setter,并生成访问底层 JavaScript 对象属性的 getter 和 setter。
@JsName()
abstract class Person {
factory Person() => $js;
String firstname, lastname;
int get age;
void set email(String email);
}
这将生成:
@JS()
class Person {
external Person();
external String get firstname;
external set firstname(String value);
external String get lastname;
external set lastname(String value);
external int get age;
external void set email(String email);
}
方法
抽象方法将以相同的方式实现:
@JsName()
abstract class Person {
factory Person() => $js;
String sayHelloTo(String other);
void fall();
}
这将生成:
@JS()
class Person {
external Person();
external String sayHelloTo(String other);
external void fall();
}
名称使用
构造函数
你可以通过在类上提供 JsName('MyClassName')
来覆盖名称:
@JsName('People')
abstract class Person {
factory Person() => $js;
String sayHelloTo(Person other);
Person get father;
}
成员
你可以通过在成员上提供 JsName('myMemberName')
来覆盖名称:
@JsName()
abstract class Person {
@JsName('daddy') Person get father;
}
小技巧和窍门
匿名对象
实例化匿名 JavaScript 对象是很常见的。如果你的私有类映射到一个匿名对象,可以在其上添加 @anonymous
注解:
@JsName()
@anonymous
abstract class Foo {
factory Foo() => $js;
}
这将生成:
@JS()
@anonymous
class Foo {
external factory Foo();
}
从方法创建 getter
如果一个 JavaScript 对象有一个 getXxx()
函数,你想在 Dart 端将其映射为 get xxx
,你可以这样做:
@JsName()
abstract class Person {
String get firstname => _getFirstname();
@JsName('getFirstname')
String _getFirstname();
}
这个方法可以应用于任何你想进行的重定向。
示例 Demo
下面是一个完整的示例 demo,展示了如何使用 js_wrapping
插件来与 JavaScript 进行交互:
JavaScript 代码
function LatLng(lat, lng) {
this.lat = lat;
this.lng = lng;
}
LatLng.prototype.equals = function(other) {
return this.lat === other.lat && this.lng === other.lng;
};
LatLng.prototype.toString = function() {
return `Lat: ${this.lat}, Lng: ${this.lng}`;
};
Dart 代码
首先,在 pubspec.yaml
中添加依赖:
dependencies:
js_wrapping: ^0.6.0
dev_dependencies:
js_wrapping_generator: ^0.6.0
然后,创建一个 Dart 文件(例如 lat_lng.dart
):
import 'package:js_wrapping/js_wrapping.dart';
@JsName()
abstract class LatLng {
factory LatLng(num lat, num lng) => $js;
bool equals(LatLng other);
num get lat => _lat();
@JsName('lat')
num _lat();
num get lng => _lng();
@JsName('lng')
num _lng();
String toString();
}
接下来,运行生成器以生成相应的 Dart 代码:
flutter pub run build_runner build
最后,在你的 Flutter 应用中使用这个类:
import 'package:flutter/material.dart';
import 'lat_lng.g.dart'; // 生成的文件
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
final latLng = LatLng(39.9042, 116.4074); // 创建一个 LatLng 实例
print(latLng.toString()); // 输出: Lat: 39.9042, Lng: 116.4074
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('js_wrapping Demo')),
body: Center(child: Text('Check console for output')),
),
);
}
}
更多关于Flutter JavaScript交互插件js_wrapping的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter JavaScript交互插件js_wrapping的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter中使用js_wrapping
插件与JavaScript进行交互的代码示例。js_wrapping
允许Flutter应用通过平台通道与嵌入的WebView中的JavaScript代码进行通信。不过需要注意的是,js_wrapping
可能不是一个实际存在的插件名称,这里我们假设有一个类似功能的插件,或者你可能需要参考一些类似功能的插件如flutter_webview_plugin
或webview_flutter
并结合平台通道来实现类似功能。
由于js_wrapping
可能不是标准插件,以下示例将使用webview_flutter
和平台通道来模拟这种交互。
1. 添加依赖
首先,在pubspec.yaml
文件中添加webview_flutter
依赖:
dependencies:
flutter:
sdk: flutter
webview_flutter: ^3.0.4 # 请检查最新版本号
2. 创建Flutter WebView页面
创建一个新的Flutter页面,包含一个WebView组件,并设置JavaScript通道的监听器。
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'dart:ui' as ui;
class WebViewPage extends StatefulWidget {
@override
_WebViewPageState createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
late WebViewController _controller;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView with JavaScript Interaction'),
),
body: WebView(
initialUrl: 'about:blank',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
_loadHtmlFromAssets();
},
onPageFinished: (String url) {
_controller.evaluateJavascript('''
window.Flutter.postMessage = function(message) {
nativeChannel.postMessage(JSON.stringify(message));
};
''');
// 监听来自JavaScript的消息
_controller.addJavascriptChannel(
JavascriptChannel(
name: 'nativeChannel',
onMessageReceived: (JavascriptMessage message) {
print('Received message from JavaScript: ${message.message}');
// 在这里处理从JavaScript接收到的消息
},
).onDispose: () {
// 清理逻辑
},
);
},
),
);
}
_loadHtmlFromAssets() async {
String htmlContent = await rootBundle.loadString('assets/sample.html');
_controller.loadUrl(Uri.dataFromString(
htmlContent,
mimeType: 'text/html',
encoding: Encoding.getByName('utf-8')
).toString());
}
}
3. 创建HTML文件
在assets
文件夹中创建一个名为sample.html
的文件,并添加以下内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample HTML</title>
<script>
function sendMessageToFlutter() {
const message = {
type: 'greeting',
text: 'Hello from JavaScript!'
};
window.Flutter.postMessage(message);
}
</script>
</head>
<body>
<h1>Hello from WebView</h1>
<button onclick="sendMessageToFlutter()">Send Message to Flutter</button>
</body>
</html>
4. 更新pubspec.yaml以包含assets
确保在pubspec.yaml
中声明了assets
文件夹:
flutter:
assets:
- assets/sample.html
5. 运行应用
现在,你可以运行你的Flutter应用,点击WebView中的按钮,应该会看到控制台输出从JavaScript发送的消息。
这个示例展示了如何使用webview_flutter
插件在Flutter应用中嵌入一个WebView,并通过平台通道与JavaScript代码进行双向通信。如果你有一个特定的js_wrapping
插件,请参考其官方文档进行相应调整。