Flutter中JavaScript與Dart實現(xiàn)雙向通信的方案
基于官方 webview_flutter 插件的通信方式
基于官方 webview_flutter 插件的通信方式
在 pubspec.yaml 中添加
添加 webview 包 方便后面使用,記得 pub get 更新
dependencies:
flutter:
sdk: flutter
# 移動端 WebView 通信核心依賴
webview_flutter: ^4.4.4
# Web 平臺 JS 通信依賴
js: ^0.6.7
配置自己使用的 js 路徑地址信息, 該地址位于項目根目錄中添加對應(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 提供的跨端通信接口,專門用于 JavaScript → Flutter 的數(shù)據(jù)傳遞(單向主動推送)。你可以把它理解成:
- Flutter 在 WebView 里 “預(yù)埋” 了一個名為 FlutterJsChannel(你自定義的名稱)的 “消息信箱”;
- JS 端只要往這個 “信箱” 里丟消息(調(diào)用 postMessage),F(xiàn)lutter 端的 onMessageReceived 回調(diào)就會立刻收到并處理。
WebView 加載的 HTML/JS 中,通過 window.通道名稱.postMessage(數(shù)據(jù)) 發(fā)送消息
dart 文件 創(chuàng)建 web 交互 方法定義
通過 runJavaScript(jsCode); 調(diào)用項目 內(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",
// 實時接收 JS 傳遞的數(shù)據(jù)(持續(xù)回調(diào),無需主動觸發(fā))
onMessageReceived: (JavaScriptMessage message) {
print("object");
// 第一步:先打印日志,這是最直接的驗證,無關(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 中聲明的一致(大小寫敏感)
String assetsJsContent = await rootBundle.loadString("assets/js/md5.js");
// ② 執(zhí)行該 JS 字符串,將函數(shù)注入 WebView 環(huán)境
// 此時只是「導(dǎo)入」函數(shù),并未調(diào)用具體方法,無返回值
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 {
// ① 編寫 JS 代碼,調(diào)用已注入的函數(shù)(來自 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)建一個 WebView 的控制器實例,用來管理 WebView 的所有行為(加載頁面、JS 交互、樣式設(shè)置等)。
- …setJavaScriptMode(JavaScriptMode.unrestricted)
- 開啟 WebView 的 JavaScript 支持:
- JavaScriptMode.unrestricted:完全允許 JS 執(zhí)行(默認(rèn)是禁用的),這是 Flutter 和 JS 交互的前提。
- 如果設(shè)為JavaScriptMode.disabled,則 WebView 中的 JS 代碼無法運(yùn)行,通信通道也會失效。
- …setBackgroundColor(Colors.white)
- 設(shè)置 WebView 的背景顏色為白色(默認(rèn)可能是透明或灰色),優(yōu)化視覺效果。
..loadHtmlString("""<html><body></body></html>""")- 加載一段空的 HTML 字符串到 WebView 中(也可以用loadUrl加載遠(yuǎn)程網(wǎng)頁)。這里加載空頁面,說明核心目的是通過 JS 通道接收數(shù)據(jù),而非展示網(wǎng)頁內(nèi)容。
- …addJavaScriptChannel(…)
- 這是核心邏輯:創(chuàng)建 Flutter 和 JS 之間的通信通道,實現(xiàn)JS 主動向 Flutter 發(fā)送數(shù)據(jù):
- “FlutterJsChannel”:通道的唯一標(biāo)識,JS 端必須通過這個名稱調(diào)用(比如window.FlutterJsChannel.postMessage(‘要傳遞的數(shù)據(jù)’))。
- onMessageReceived:回調(diào)函數(shù),只要 JS 調(diào)用了postMessage,這個回調(diào)就會實時觸發(fā)(也就是你注釋里說的 “持續(xù)回調(diào),無需主動觸發(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)試驗證。
- _updateAnimeList(message.message):調(diào)用自定義方法處理數(shù)據(jù)(比如解析數(shù)據(jù)、更新動漫列表)。
- 注釋的setState:如果需要更新 Flutter 的 UI(比如把數(shù)據(jù)展示在頁面上),必須用setState觸發(fā)頁面刷新。
項目啟動類
void main()
{
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
WidgetsFlutterBinding.ensureInitialized() 是 Flutter 應(yīng)用的 “基礎(chǔ)引擎初始化”,為所有 Widget 和異步操作提供運(yùn)行環(huán)境。
Web 平臺 - Dart 與 JS 通信
@JS
@JS() 是 package:js 庫提供的元注解(裝飾器),作用是建立 Dart 代碼和 JS 代碼的映射關(guān)系。你可以把它理解成:給 Dart 代碼貼一個 “標(biāo)簽”,告訴 Dart 編譯器 “這段代碼要對應(yīng)到 JS 中的某個東西”。
傳遞 Dart 函數(shù)給 JS(回調(diào))
用 @allowInterop 注解(@JS() 配套),可以把 Dart 函數(shù)作為回調(diào)傳給 JS。
- @JS() 是 Dart 與 Web 端 JS 交互的核心注解,用于建立 Dart 代碼和 JS 變量 / 函數(shù) / 對象的映射關(guān)系。
- 使用時必須導(dǎo)入 package:js,且被注解的成員需加 external 關(guān)鍵字。
- 配套 @allowInterop 可實現(xiàn) Dart 函數(shù)作為回調(diào)傳給 JS,僅支持 Web 平臺。
總結(jié)
到此這篇關(guān)于Flutter中JavaScript與Dart實現(xiàn)雙向通信方案的文章就介紹到這了,更多相關(guān)Flutter中JS與Dart雙向通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開發(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 ExpandableRecyclerView使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android ExpandableRecyclerView的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
android實現(xiàn)icon動態(tài)旋轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)icon動態(tài)旋轉(zhuǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07
Kotlin Channel處理多個數(shù)據(jù)組合的流
最近項目中對 kotlin 的使用比較多。不得不說 kotlin 確實可以極大的提高 android 的開發(fā)效率,channel用于協(xié)程之間的通訊,使用send和receive往通道里寫入或者讀取數(shù)據(jù),2個方法為非阻塞掛起函數(shù),channel是熱流,不管有沒有訂閱者都會發(fā)送2022-11-11
Android實現(xiàn)循環(huán)輪播跑馬燈的效果
這篇文章主要介紹了為大家詳細(xì)介紹了如何通過Android實現(xiàn)循環(huán)輪播跑馬燈的效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-05-05
Kotlin HttpURLConnection與服務(wù)器交互實現(xiàn)方法詳解
簡單來說,HttpURLConnection 是發(fā)起HTTP請求的基礎(chǔ)類庫,提供了HTTP請求的基本功能,不過封裝的比較少,在使用時很多內(nèi)容都需要自己設(shè)置,也需要自己處理請求流和響應(yīng)流2022-09-09

