From 66fb0b7157413d478c53c5822f2c2da02845a8e8 Mon Sep 17 00:00:00 2001 From: zhugy781 Date: Wed, 10 Dec 2025 10:02:19 +0800 Subject: [PATCH] create project --- .fvmrc | 3 + .gitignore | 34 +++++ .metadata | 10 ++ CHANGELOG.md | 3 + LICENSE | 1 + README.md | 39 ++++++ analysis_options.yaml | 4 + lib/utils/app_bridge.dart | 264 ++++++++++++++++++++++++++++++++++++++ lib/web_tools.dart | 3 + pubspec.yaml | 58 +++++++++ test/web_tools_test.dart | 5 + 11 files changed, 424 insertions(+) create mode 100644 .fvmrc create mode 100644 .gitignore create mode 100644 .metadata create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 analysis_options.yaml create mode 100644 lib/utils/app_bridge.dart create mode 100644 lib/web_tools.dart create mode 100644 pubspec.yaml create mode 100644 test/web_tools_test.dart diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..906bbb3 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.24.3" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8df109e --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +build/ + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..dfbc19f --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "ea121f8859e4b13e47a8f845e4586164519588bc" + channel: "stable" + +project_type: package diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..41cc7d8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ba75c69 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a260d8 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/lib/utils/app_bridge.dart b/lib/utils/app_bridge.dart new file mode 100644 index 0000000..3e3bc1b --- /dev/null +++ b/lib/utils/app_bridge.dart @@ -0,0 +1,264 @@ +import 'dart:convert'; +// import 'dart:html'; +import 'dart:html' as html; + +import 'package:js/js.dart'; + +// h5交互通知 原生 {type:'enum',data:'所需参数,可无'} +enum ToFlutterAppEnum { + close('close'), + gameExit('gameExit'), + createGame('createGame'), + wantToPlay('wantToPlay'), + gameOver('gameOver'), + uploadImage('upload_image'), + soundRecord('sound_recording'), + toRecharge('toRecharge'), + playing('playing'), + toRedDiamond('toRedDiamond'), + gameType('gameType'), + jumpToH5('jumpToH5'), + toHomepage('toHomepage'), + toMonthCardPay('toMonthCardPay'), + + checkGameState('checkGameState'), + closeObserving('closeObserving'), + translateRequest('translateRequest'), + share('share'), + //开播检测 + checkStartBroadcaster('checkStartBroadcaster'), + //直播间发言 + taskLiveRoomChat('taskLiveRoomChat'), + //直播间送礼 + taskLiveRoomGift('taskLiveRoomGift'), + //直播间其他任务 close + taskLiveRoomOther('taskLiveRoomOther'), + //跳转从业者申请 + toApplyAdmissionPage('toApplyAdmissionPage'), + //直播预约设置 + shouLiveBookingPicker('shouLiveBookingPicker'), + //完善个人信息 + shouldCompleteProfile('shouldCompleteProfile'), + //在直播间或聊天室停留观看n分钟 + shouldWatchDuration('shouldWatchDuration'), + //在直播间或聊天室发送n条公屏消息 + shouldSendPublicMessage('shouldSendPublicMessage'), + //在直播间或聊天室上麦互动n分钟 + shouldMicInteraction('shouldMicInteraction'), + //向任意用户,发送n条信息 + shouldSendPrivateMessage('shouldSendPrivateMessage'), + //发布n条动态 + shouldPostFeed('shouldPostFeed'), + //分享n次直播间或聊天室至任意平台 + shouldShareRoom('shouldShareRoom'), + //佩戴任意装扮 + shouldWearDecoration('shouldWearDecoration'), + //前往语音房 + shouldGoToVoiceRoom('shouldGoToVoiceRoom'), + + // 定向充值 + rechargeItem('rechargeItem'), + + ///通用交互 别往这下面加,👆🏻加 + commonInteraction('commonInteraction'), + defaultCode(''); + + const ToFlutterAppEnum(this.code); + final String code; + + static ToFlutterAppEnum? fromCode(String code) { + return ToFlutterAppEnum.values.firstWhere( + (e) => e.code == code, + orElse: () => ToFlutterAppEnum.defaultCode, + ); + } +} + +// 原生交互通知 h5 {type:'enum',data:'所需参数 '} +enum FromFlutterAppEnum { + translateResult('translateResult'), //翻译 + redDiamondRecharge('diamond_recharge'), //钻石充值 + shareFinished('share_finished'), //分享完成 + defaultCode(''); + + const FromFlutterAppEnum(this.code); + final String code; +} + +@JS() +external void sendMessageToNative(String data); + +class FlutterBridge { + static final FlutterBridge instance = FlutterBridge._internal(); + + /** + * 在需要处理 WebView 消息的地方注册监听器: + * FlutterBridge.instance.on(FromJsEnum.translateResult.code, (data) { + print("收到来自 WebView 的消息: $data"); + // 执行你需要的逻辑 + }); + 使用过需要释放 + // 取消监听 'translateResult' 类型的消息 + FlutterBridge.instance.off(FromJsEnum.translateResult.code); + * */ + final _messageListeners = )>{}; + var textMap = {}; //多语言翻译 + + FlutterBridge._internal() { + _initListener(); + } + + // 只初始化一次,监听 WebView 消息 + void _initListener() { + html.window.onMessage.listen((event) { + if (event.data is String) { + try { + final Map data = jsonDecode(event.data); + final String? type = data['type']; + if (type != null && _messageListeners.containsKey(type)) { + _messageListeners[type]?.call(data); + } + print('Invalid message format from Flutter: $type'); + } catch (e) { + print('Invalid message format from Flutter: ${event.data}'); + } + } else { + try { + final String? type = event.data['type']; + if (type != null && _messageListeners.containsKey(type)) { + _messageListeners[type]?.call(event.data); + } + print('Invalid message format from Flutter: $type'); + } catch (e) { + print('Invalid message format from Flutter: ${event.data}'); + } + } + }); + } + + // 注册监听某个 type 的消息 + void on(String type, Function(Map) callback) { + if (_messageListeners.containsKey(type)) { + print("Listener for '$type' is already registered."); + return; // 如果已经注册了这个类型的监听器,就不再重复添加 + } + _messageListeners[type] = callback; + print("Listener for '$type' has been registered."); + } + + // 取消监听某个 type 的消息 + void off(String type) { + if (!_messageListeners.containsKey(type)) { + print("No listener found for '$type'."); + return; // 如果没有找到监听器,直接返回 + } + _messageListeners.remove(type); + print("Listener for '$type' has been removed."); + } + + // 发送消息给 App(通过 WebView 调用 JS 方法) + void sendToFlutter(String type, Map data) { + final dataStr = jsonEncode({'type': type, 'data': data}); + print('$dataStr'); + sendMessageToNative(dataStr); + } + + void sendToFlutterTest() { + // final message = jsonEncode({ + // 'type': type, + // 'data': data, + // }); + // _runJs("receiveMessageFromFlutter($message);"); + final dataStr = jsonEncode({'type': close, 'data': {}}); + sendMessageToNative(dataStr); + } + // 执行 JS 代码 + // void _runJs(String js) { + // final script = ScriptElement() + // ..innerHtml = js + // ..type = 'application/javascript'; + // document.body?.append(script); + // script.remove(); + // } + + // 具体封装的常用方法,直接发送消息给 Flutter Web + void close() => sendToFlutter(ToFlutterAppEnum.close.code, {}); + void gameOver() => sendToFlutter(ToFlutterAppEnum.gameOver.code, {}); + void createGame(String gameId) => + sendToFlutter(ToFlutterAppEnum.createGame.code, {'gameId': gameId}); + void wantToPlay(String gameId) => + sendToFlutter(ToFlutterAppEnum.wantToPlay.code, {'gameId': gameId}); + void translateRequest(Map data) => + sendToFlutter(ToFlutterAppEnum.translateRequest.code, data); + void toRecharge() => sendToFlutter(ToFlutterAppEnum.toRecharge.code, {}); + void toRedDiamond() => sendToFlutter(ToFlutterAppEnum.toRedDiamond.code, {}); + void jumpToH5(String path, String title) => sendToFlutter( + ToFlutterAppEnum.jumpToH5.code, {'path': path, 'title': title}); + void toHomepage(String userId) => + sendToFlutter(ToFlutterAppEnum.toHomepage.code, {'userId': userId}); + void toMonthCardPay(String googleProductId, String iosProductId, + {otherUserId = ''}) => + sendToFlutter(ToFlutterAppEnum.toMonthCardPay.code, { + 'googleProductId': googleProductId, + 'iosProductId': iosProductId, + 'otherUserId': otherUserId, + }); + void checkGameState(String gameCode) => sendToFlutter( + ToFlutterAppEnum.checkGameState.code, {'gameCode': gameCode}); + void share({ + required String activityId, + required bool needShareReport, + Map extraParams = const {}, + }) => + sendToFlutter(ToFlutterAppEnum.share.code, { + "activityId": activityId, + "shareReportKey": needShareReport ? "ActivityShared" : "", + ...extraParams + }); + + void checkStartBroadcaster() => + sendToFlutter(ToFlutterAppEnum.checkStartBroadcaster.code, {}); + + void taskLiveRoomChat() => + sendToFlutter(ToFlutterAppEnum.taskLiveRoomChat.code, {}); + void taskLiveRoomGift() => + sendToFlutter(ToFlutterAppEnum.taskLiveRoomGift.code, {}); + void taskLiveRoomOther() => + sendToFlutter(ToFlutterAppEnum.taskLiveRoomOther.code, {}); + void toApplyAdmissionPage() => + sendToFlutter(ToFlutterAppEnum.toApplyAdmissionPage.code, {}); + void shouLiveBookingPicker() => + sendToFlutter(ToFlutterAppEnum.shouLiveBookingPicker.code, {}); + /** 完善个人信息 */ + void shouldCompleteProfile() => + sendToFlutter(ToFlutterAppEnum.shouldCompleteProfile.code, {}); + /** 在直播间或聊天室停留观看n分钟 */ + void shouldWatchDuration() => + sendToFlutter(ToFlutterAppEnum.shouldWatchDuration.code, {}); +/** 在直播间或聊天室发送n条公屏消息 */ + void shouldSendPublicMessage() => + sendToFlutter(ToFlutterAppEnum.shouldSendPublicMessage.code, {}); + /** 在直播间或聊天室上麦互动n分钟 */ + void shouldMicInteraction() => + sendToFlutter(ToFlutterAppEnum.shouldMicInteraction.code, {}); + /** 向任意用户,发送n条信息*/ + void shouldSendPrivateMessage() => + sendToFlutter(ToFlutterAppEnum.shouldSendPrivateMessage.code, {}); + /** 发布n条动态*/ + void shouldPostFeed() => + sendToFlutter(ToFlutterAppEnum.shouldPostFeed.code, {}); + /** 分享n次直播间或聊天室至任意平台 */ + void shouldShareRoom() => + sendToFlutter(ToFlutterAppEnum.shouldShareRoom.code, {}); +/** 佩戴任意装扮 */ + void shouldWearDecoration() => + sendToFlutter(ToFlutterAppEnum.shouldWearDecoration.code, {}); + /** 前往语音房 */ + void shouldGoToVoiceRoom() => + sendToFlutter(ToFlutterAppEnum.shouldGoToVoiceRoom.code, {}); + + ///通用交互 targetId gameId 或者 话题id 或者 分享活动 ShareEvenType.type 或者 其他活动的 url 地址不含 域名部分 + void commonInteraction(String type, {dynamic targetId}) => sendToFlutter( + ToFlutterAppEnum.commonInteraction.code, + {'interactionType': type, 'targetId': targetId}); +} diff --git a/lib/web_tools.dart b/lib/web_tools.dart new file mode 100644 index 0000000..227134e --- /dev/null +++ b/lib/web_tools.dart @@ -0,0 +1,3 @@ +library; + +export 'package:web_tools/utils/app_bridge.dart'; diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..9387611 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,58 @@ +name: web_tools +description: "A new Flutter package project." +version: 0.0.1 +publish_to: 'none' # 不发布到pub.dev +homepage: https://gitea.sdws.shop/xim/web_tools.git + +environment: + sdk: ^3.5.3 + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + js: ^0.6.3 + + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/to/asset-from-package + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/to/font-from-package diff --git a/test/web_tools_test.dart b/test/web_tools_test.dart new file mode 100644 index 0000000..0da434d --- /dev/null +++ b/test/web_tools_test.dart @@ -0,0 +1,5 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('adds one to input values', () {}); +}