为什么要调用js
JavaScript拥有庞大且成熟的工具生态系统
1. flutter-web
1. 引入js web/index.html
<!-- Add the required JS libraries --> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js" integrity="sha512-a+SUDuwNzXDvz4XrIcXHuCf089/iJAoN4lmrXJg18XnduKK6YlDHNRalv4yd1N40OKI80tFidF+rqTFKGPoWFQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/md5.min.js" integrity="sha512-ENWhXy+lET8kWcArT6ijA6HpVEALRmvzYBayGL6oFWl96exmq8Fjgxe2K6TAblHLP75Sa/a1YjHpIZRt+9hGOQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <!-- Register the js file where the logic is written --> <script src="CryptoEnc.js" type="application/javascript"></script>
2. 创建工具js web/CryptoEnc.js
function CryptoEnc() {} CryptoEnc.prototype.encrypt = function(toEncObj){ var toEnc = toEncObj.value; var encrypted = CryptoJS.MD5(toEnc); return encrypted; } CryptoEnc.prototype.testFunc = function(toEncObj2){ var toEnc = toEncObj2.value; return "========bbbbtestFunc"+toEnc; }
3. 创建对应的lib/js/js_interop.dart
// #1 @JS() library js_interop; // The above two lines are required import 'package:js/js.dart'; // #2 @JS() class CryptoEnc { external CryptoEnc(); external String encrypt(ToEncrypt toEncrypt); external String testFunc(ToEncrypt2 toEncrypt2); } // #3 @JS() @anonymous class ToEncrypt { external String get value; external factory ToEncrypt({String value}); } @JS() @anonymous class ToEncrypt2 { external String get value; external factory ToEncrypt2({String value}); }
4. 由于引入的js是针对web平台的,所以引入需要做引入处理
///encrypt.dart class ToEncrypt { final String value; ToEncrypt({ required this.value, }); } class ToEncrypt2 { final String value; ToEncrypt2({ required this.value, }); } class CryptoEnc { CryptoEnc(); String encrypt(ToEncrypt toEncrypt) { // We are not implementing any encryption for mobile for now. // This is just for demonstration. throw UnimplementedError(); } String testFunc(ToEncrypt2 toEncrypt) { // We are not implementing any encryption for mobile for now. // This is just for demonstration. throw UnimplementedError(); } } ///export_encrypt.dart export 'encrypt.dart' if (dart.library.js) 'js_interop.dart';
5. 使用
var encVal = CryptoEnc().encrypt( ToEncrypt( value: "aaaaaa", ), ); var encVal2 = CryptoEnc().testFunc(ToEncrypt2( value: "cccc", )); print(encVal); print("testFunc=$encVal2");
2. Android
1. 引入依赖
webview_flutter: ^4.4.2
2. index.html
<!DOCTYPE html> <html> <head> <title>Test js dart</title> </head> <body> <script> function inputClick (url) { console.log('inputClick=>'+url); } function playUrl(url) { console.log('playUrl=>'+url); } function startPlay() { console.log('startPlay'); } function postMsg() { console.log('postMsg'); //向dart发送消息 Print.postMessage('postMsg'); } </script> </body> </html>
3. dart
import 'package:flutter/material.dart'; import 'package:tvboxstudy/log_extensions.dart'; import 'package:webview_flutter/webview_flutter.dart'; class LocalHtmlWebView extends StatefulWidget { const LocalHtmlWebView({super.key}); @override LocalHtmlWebViewState createState() => LocalHtmlWebViewState(); } class LocalHtmlWebViewState extends State<LocalHtmlWebView> { late String localHtmlContents; late WebViewController controller; ValueNotifier<bool> isShowLoading = ValueNotifier(true); @override void initState() { super.initState(); initController(); loadLocalHtml(); _registerJavascriptChannel(); } void runJS(int type) { if (type == 1) { controller.runJavaScript( 'inputClick();', ); } else if (type == 2) { controller.runJavaScript( 'startPlay();', ); }else if (type == 3) { controller.runJavaScript( 'postMsg();', ); } else if (type == 4) { controller.runJavaScript( "playUrl('https://media.w3.org/2010/05/sintel/trailer.mp4');", ); } } void _registerJavascriptChannel() { controller.addJavaScriptChannel( 'Print', onMessageReceived: (JavaScriptMessage message) { //收到消息做相应的处理 print("onMessageReceived=>${message.message}"); }, ); } void initController() { controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(Colors.transparent) ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { "progress=$progress".log(); if (progress == 100) { isShowLoading.value = false; } }, onPageStarted: (String url) {}, onPageFinished: (String url) { controller .runJavaScriptReturningResult('document.body.scrollHeight') .then((value) { "scrollHeight=>$value".log(); }); }, onWebResourceError: (WebResourceError error) {}, onNavigationRequest: (NavigationRequest request) { if (request.url.startsWith('https://www.youtube.com/')) { return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ); } void loadLocalHtml() async { controller.loadFlutterAsset('assets/www/player/index2.html'); } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ Row( children: [ TextButton(onPressed: (){ runJS(1); }, child: Text("inputClick")), TextButton(onPressed: (){ runJS(2); }, child: Text("startPlay")), TextButton(onPressed: (){ runJS(3); }, child: Text("postMsg")), TextButton(onPressed: (){ runJS(4); }, child: Text("playUrl")), ], ), Expanded( child: Stack( children: [ WebViewWidget( controller: controller, ), ValueListenableBuilder( valueListenable: isShowLoading, builder: (BuildContext context, bool value, Widget? child) { return isShowLoading.value ? const Center( child: CircularProgressIndicator( color: Colors.white, )) : const SizedBox.shrink(); }, ) ], ), ), ], ), ); } }