Flutter中JavaScript與Dart實(shí)現(xiàn)雙向通信的方案
基于官方 webview_flutter 插件的通信方式
基于官方 webview_flutter 插件的通信方式
在 pubspec.yaml 中添加
添加 webview 包 方便后面使用,記得 pub get 更新
dependencies:
flutter:
sdk: flutter
# 移動(dòng)端 WebView 通信核心依賴
webview_flutter: ^4.4.4
# Web 平臺(tái) JS 通信依賴
js: ^0.6.7
配置自己使用的 js 路徑地址信息, 該地址位于項(xiàng)目根目錄中添加對(duì)應(yīng) js 文件
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/js/xxx.js
靜態(tài) js 文件,建立通道
function test(){
if (window.FlutterJsChannel) {
window.FlutterJsChannel.postMessage(realTimeData);
console.log(realTimeData);
// 新增:打印推送成功日志
console.log("【JS 推送成功】:數(shù)據(jù)已發(fā)送給 Flutter");
} else {
// 新增:打印推送失敗日志
console.log("【JS 推送失敗】:FlutterJsChannel 不存在");
}
}
postMessage 通道的核心概念
- postMessage 本質(zhì)是 Flutter 為 WebView 提供的跨端通信接口,專門(mén)用于 JavaScript → Flutter 的數(shù)據(jù)傳遞(單向主動(dòng)推送)。你可以把它理解成:
- Flutter 在 WebView 里 “預(yù)埋” 了一個(gè)名為 FlutterJsChannel(你自定義的名稱)的 “消息信箱”;
- JS 端只要往這個(gè) “信箱” 里丟消息(調(diào)用 postMessage),F(xiàn)lutter 端的 onMessageReceived 回調(diào)就會(huì)立刻收到并處理。
WebView 加載的 HTML/JS 中,通過(guò) window.通道名稱.postMessage(數(shù)據(jù)) 發(fā)送消息
dart 文件 創(chuàng)建 web 交互 方法定義
通過(guò) runJavaScript(jsCode); 調(diào)用項(xiàng)目 內(nèi)部方法
import 'package:webview_flutter/webview_flutter.dart';
late WebViewController _webViewController;
_webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(Colors.white)
..loadHtmlString("""<html><body></body></html>""")
..addJavaScriptChannel(
"FlutterJsChannel",
// 實(shí)時(shí)接收 JS 傳遞的數(shù)據(jù)(持續(xù)回調(diào),無(wú)需主動(dòng)觸發(fā))
onMessageReceived: (JavaScriptMessage message) {
print("object");
// 第一步:先打印日志,這是最直接的驗(yàn)證,無(wú)關(guān) UI 更新
print("【通道回調(diào)觸發(fā)】:收到數(shù)據(jù) -> ${message.message}");
// print("【數(shù)據(jù)類型】:${message.message.runtimeType}");
_updateAnimeList(message.message);
}
);
// 步驟 1:讀取并加載 Assets 中的 JS 文件(核心:注入 JS 函數(shù))
Future<void> _loadAssetsJsFile() async {
try {
// ① 讀取 Assets 中的 JS 文件(轉(zhuǎn)為純文本字符串)
// 路徑必須和 pubspec.yaml 中聲明的一致(大小寫(xiě)敏感)
String assetsJsContent = await rootBundle.loadString("assets/js/md5.js");
// ② 執(zhí)行該 JS 字符串,將函數(shù)注入 WebView 環(huán)境
// 此時(shí)只是「導(dǎo)入」函數(shù),并未調(diào)用具體方法,無(wú)返回值
await _webViewController.runJavaScript(assetsJsContent);
setState(() {
_callResult = "Assets JS 文件加載完成(函數(shù)已注入),可調(diào)用具體方法";
_callAssetsJsFunction();
print(_callResult);
});
} catch (e) {
setState(() {
_callResult = "加載 Assets JS 文件失?。?e";
});
}
}
// 步驟 2:調(diào)用 Assets JS 文件中定義的具體方法
_callAssetsJsFunction() async {
try {
// ① 編寫(xiě) JS 代碼,調(diào)用已注入的函數(shù)(來(lái)自 assets/js/demo.js)
String jsCode = """
test();
""";
// ③ 執(zhí)行 JS 代碼,觸發(fā)函數(shù)調(diào)用
_webViewController.runJavaScript(jsCode);
// 新增:打印日志,確認(rèn) JS 指令發(fā)送成功
print("【Flutter】JS 執(zhí)行指令已發(fā)送給 WebView");
} catch (e) {
setState(() {
_callResult = "調(diào)用 Assets JS 函數(shù)失?。?e";
});
}
}
- WebViewController()
- 創(chuàng)建一個(gè) WebView 的控制器實(shí)例,用來(lái)管理 WebView 的所有行為(加載頁(yè)面、JS 交互、樣式設(shè)置等)。
- …setJavaScriptMode(JavaScriptMode.unrestricted)
- 開(kāi)啟 WebView 的 JavaScript 支持:
- JavaScriptMode.unrestricted:完全允許 JS 執(zhí)行(默認(rèn)是禁用的),這是 Flutter 和 JS 交互的前提。
- 如果設(shè)為JavaScriptMode.disabled,則 WebView 中的 JS 代碼無(wú)法運(yùn)行,通信通道也會(huì)失效。
- …setBackgroundColor(Colors.white)
- 設(shè)置 WebView 的背景顏色為白色(默認(rèn)可能是透明或灰色),優(yōu)化視覺(jué)效果。
..loadHtmlString("""<html><body></body></html>""")- 加載一段空的 HTML 字符串到 WebView 中(也可以用loadUrl加載遠(yuǎn)程網(wǎng)頁(yè))。這里加載空頁(yè)面,說(shuō)明核心目的是通過(guò) JS 通道接收數(shù)據(jù),而非展示網(wǎng)頁(yè)內(nèi)容。
- …addJavaScriptChannel(…)
- 這是核心邏輯:創(chuàng)建 Flutter 和 JS 之間的通信通道,實(shí)現(xiàn)JS 主動(dòng)向 Flutter 發(fā)送數(shù)據(jù):
- “FlutterJsChannel”:通道的唯一標(biāo)識(shí),JS 端必須通過(guò)這個(gè)名稱調(diào)用(比如window.FlutterJsChannel.postMessage(‘要傳遞的數(shù)據(jù)’))。
- onMessageReceived:回調(diào)函數(shù),只要 JS 調(diào)用了postMessage,這個(gè)回調(diào)就會(huì)實(shí)時(shí)觸發(fā)(也就是你注釋里說(shuō)的 “持續(xù)回調(diào),無(wú)需主動(dòng)觸發(fā)”)。
- JavaScriptMessage message:回調(diào)的參數(shù),message.message是 JS 傳遞的原始數(shù)據(jù)(字符串類型)。
- 回調(diào)內(nèi)的邏輯
- print(“【通道回調(diào)觸發(fā)】:收到數(shù)據(jù) -> ${message.message}”):打印 JS 傳遞的數(shù)據(jù),用于調(diào)試驗(yàn)證。
- _updateAnimeList(message.message):調(diào)用自定義方法處理數(shù)據(jù)(比如解析數(shù)據(jù)、更新動(dòng)漫列表)。
- 注釋的setState:如果需要更新 Flutter 的 UI(比如把數(shù)據(jù)展示在頁(yè)面上),必須用setState觸發(fā)頁(yè)面刷新。
項(xiàng)目啟動(dòng)類
void main()
{
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
WidgetsFlutterBinding.ensureInitialized() 是 Flutter 應(yīng)用的 “基礎(chǔ)引擎初始化”,為所有 Widget 和異步操作提供運(yùn)行環(huán)境。
Web 平臺(tái) - Dart 與 JS 通信
@JS
@JS() 是 package:js 庫(kù)提供的元注解(裝飾器),作用是建立 Dart 代碼和 JS 代碼的映射關(guān)系。你可以把它理解成:給 Dart 代碼貼一個(gè) “標(biāo)簽”,告訴 Dart 編譯器 “這段代碼要對(duì)應(yīng)到 JS 中的某個(gè)東西”。
傳遞 Dart 函數(shù)給 JS(回調(diào))
用 @allowInterop 注解(@JS() 配套),可以把 Dart 函數(shù)作為回調(diào)傳給 JS。
- @JS() 是 Dart 與 Web 端 JS 交互的核心注解,用于建立 Dart 代碼和 JS 變量 / 函數(shù) / 對(duì)象的映射關(guān)系。
- 使用時(shí)必須導(dǎo)入 package:js,且被注解的成員需加 external 關(guān)鍵字。
- 配套 @allowInterop 可實(shí)現(xiàn) Dart 函數(shù)作為回調(diào)傳給 JS,僅支持 Web 平臺(tái)。
總結(jié)
到此這篇關(guān)于Flutter中JavaScript與Dart實(shí)現(xiàn)雙向通信方案的文章就介紹到這了,更多相關(guān)Flutter中JS與Dart雙向通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開(kāi)發(fā)(Kotlin) 擴(kuò)展函數(shù)和運(yùn)算符重載的使用
這篇文章介紹了Kotlin中的擴(kuò)展函數(shù)和運(yùn)算符重載,擴(kuò)展函數(shù)允許你在不修改現(xiàn)有類的情況下為其添加新函數(shù),而運(yùn)算符重載則允許你自定義運(yùn)算符的行為,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-11-11
Android實(shí)現(xiàn)字幕滾動(dòng)的方法
這篇文章主要介紹了Android實(shí)現(xiàn)字幕滾動(dòng)的方法,很實(shí)用的功能,需要的朋友可以參考下2014-07-07
Android ExpandableRecyclerView使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android ExpandableRecyclerView的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android中Activity過(guò)渡動(dòng)畫(huà)的實(shí)例講解
在android5.0 以上版本中,google為我們提供了幾種activity切換的過(guò)渡動(dòng)畫(huà),目的是為了讓 activity 切換轉(zhuǎn)場(chǎng)更加美觀,下面這篇文章主要給大家介紹了關(guān)于Android中Activity過(guò)渡動(dòng)畫(huà)的相關(guān)資料,需要的朋友可以參考下2021-11-11
android實(shí)現(xiàn)icon動(dòng)態(tài)旋轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)icon動(dòng)態(tài)旋轉(zhuǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
Android自定義PopupWindow簡(jiǎn)單小例子
這篇文章主要為大家詳細(xì)介紹了Android自定義PopupWindow簡(jiǎn)單小例子,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Kotlin Channel處理多個(gè)數(shù)據(jù)組合的流
最近項(xiàng)目中對(duì) kotlin 的使用比較多。不得不說(shuō) kotlin 確實(shí)可以極大的提高 android 的開(kāi)發(fā)效率,channel用于協(xié)程之間的通訊,使用send和receive往通道里寫(xiě)入或者讀取數(shù)據(jù),2個(gè)方法為非阻塞掛起函數(shù),channel是熱流,不管有沒(méi)有訂閱者都會(huì)發(fā)送2022-11-11
Android實(shí)現(xiàn)循環(huán)輪播跑馬燈的效果
這篇文章主要介紹了為大家詳細(xì)介紹了如何通過(guò)Android實(shí)現(xiàn)循環(huán)輪播跑馬燈的效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-05-05
Kotlin HttpURLConnection與服務(wù)器交互實(shí)現(xiàn)方法詳解
簡(jiǎn)單來(lái)說(shuō),HttpURLConnection 是發(fā)起HTTP請(qǐng)求的基礎(chǔ)類庫(kù),提供了HTTP請(qǐng)求的基本功能,不過(guò)封裝的比較少,在使用時(shí)很多內(nèi)容都需要自己設(shè)置,也需要自己處理請(qǐng)求流和響應(yīng)流2022-09-09

