import 'dart:convert'; import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:aslan/chatvibe_ui/components/at_debounce_widget.dart'; import 'package:aslan/chatvibe_core/constants/at_global_config.dart'; import 'package:aslan/chatvibe_core/routes/at_fluro_navigator.dart'; import 'package:aslan/chatvibe_data/sources/local/user_manager.dart'; import 'package:provider/provider.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:aslan/app_localizations.dart'; import 'package:aslan/chatvibe_ui/components/dialog/dialog_base.dart'; import 'package:aslan/chatvibe_data/sources/repositories/room_repository_imp.dart'; import 'package:aslan/chatvibe_domain/models/res/at_get_game_config_data.dart'; import 'package:aslan/chatvibe_managers/rtc_manager.dart'; import 'package:aslan/chatvibe_features/wallet/wallet_route.dart'; import '../../chatvibe_data/models/enum/at_game_mode_type.dart'; class GameBsWebviewPage extends StatefulWidget { final String url; ///安全高度 final double height; final double width; final String gameMode; final String gameId; const GameBsWebviewPage({ Key? key, required this.url, required this.height, required this.width, this.gameMode = "", this.gameId = "", }) : super(key: key); @override _GameBsWebviewPageState createState() => _GameBsWebviewPageState(); } class _GameBsWebviewPageState extends State { late WebViewController _controller; double _progress = 0.0; bool _isLoading = true; final EventChannel _eventChannelPlugin = EventChannel('baishunChannel'); @override void initState() { super.initState(); Provider.of(context, listen: false).closeFullGame = false; // 初始化 WebViewController _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..addJavaScriptChannel( "baishunChannel", onMessageReceived: (sjMessage) {}, ) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { setState(() { _progress = progress / 100.0; }); }, onPageStarted: (String url) { setState(() { _isLoading = true; }); }, onPageFinished: (String url) { _injectJavaScriptInterface(); }, onWebResourceError: (WebResourceError error) { _onWebResourceError(error); }, ), ) ..loadRequest(Uri.parse(widget.url)); bindChannel(); _uploadGameRecord(); } @override void dispose() { _controller.loadRequest(Uri.parse('about:blank')); super.dispose(); } void _injectJavaScriptInterface() async {} @override Widget build(BuildContext context) { return widget.height < 0 ? SizedBox( width: ScreenUtil().screenWidth, height: ScreenUtil().screenHeight, child: buidMainContent(), ) : Column( children: [ widget.gameMode == ATGameModeType.CHAT_ROOM.name ? Container() : Row( children: [ Spacer(), ATDebounceWidget( child: Icon( Icons.close, color: ATGlobalConfig.businessLogicStrategy .getGameWebViewCloseIconColor(), size: 25.w, ), onTap: () { Navigator.of(context).pop(); }, ), SizedBox(width: 3.w), ], ), SizedBox(height: 6.w), AspectRatio( aspectRatio: (750 / widget.height), child: buidMainContent(), ), ], ); } Widget buidMainContent() { return Scaffold( backgroundColor: ATGlobalConfig.businessLogicStrategy .getGameWebViewScaffoldBackgroundColor(), resizeToAvoidBottomInset: false, body: SafeArea( top: false, child: Stack( children: [ Selector( selector: (c, p) => p.closeFullGame, shouldRebuild: (prev, next) => prev != next, builder: (_, closeFullGame, __) { if (closeFullGame) { Navigator.of(context).removeRoute(ModalRoute.of(context)!); } return Container(); }, ), WebViewWidget(controller: _controller), // 加载指示器 if (_isLoading) Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( ATGlobalConfig.businessLogicStrategy .getWebViewPageProgressBarActiveColor(), ), ), ), ], ), ), ); } Widget _progressBar(double progress, BuildContext context) { return progress < 1.0 ? LinearProgressIndicator( value: progress, backgroundColor: ATGlobalConfig.businessLogicStrategy .getGameWebViewProgressBarBackgroundColor(), minHeight: 1.0, valueColor: AlwaysStoppedAnimation( ATGlobalConfig.businessLogicStrategy .getWebViewPageProgressBarActiveColor(), ), ) : const SizedBox.shrink(); } void _onWebResourceError(WebResourceError error) { print('_onWebResourceError:${error.description}'); setState(() { _isLoading = false; }); // 可以在这里添加错误处理逻辑,比如显示错误页面 } void bindChannel() { if (Platform.isAndroid) { _eventChannelPlugin.receiveBroadcastStream().listen((event) { final obj = json.decode(event); String jsFunName = obj['jsCallback']; if (jsFunName.contains('getConfig')) { print("BSGAME游戏调⽤getConfig main.dart"); ATGetGameConfigData _configData = ATGetGameConfigData( appChannel: ATGlobalConfig.gameAppChannel, appId: ATGlobalConfig.gameAppid, userId: AccountStorage().getCurrentUser()?.userProfile?.id ?? "", gameMode: widget.height < 0 ? "3" : (widget.gameMode == ATGameModeType.CHAT_ROOM.name ? "3" : "2"), language: ATGlobalConfig.lang == "ar" ? "7" : "2", gsp: 101, roomId: Provider.of( context, listen: false, ).currenRoom?.roomProfile?.roomProfile?.id ?? "", gameRoomId: "", code: AccountStorage().getToken(), role: Provider.of(context, listen: false).isFz() ? "2" : "0", gameConfig: GameConfig( sceneMode: 0, currencyIcon: "https://tkm-atu.oss-ap-southeast-1.aliyuncs.com/avatar/b1bc4425-0037-433b-bf00-6977620ff57e.png", ), ); String jsUrl = jsFunName + "(${jsonEncode(_configData.toJson())})"; _controller!.runJavaScript(jsUrl); } else if (jsFunName.contains('destroy')) { print("BSGAME游戏调⽤destroy main.dart"); //关闭游戏TODO客⼾端 _controller.loadRequest(Uri.parse('about:blank')); if (widget.gameMode == ATGameModeType.CHAT_ROOM) { Provider.of( context, listen: false, ).roomMannyGameClose(); } else { Navigator.of(context).pop(); } super.dispose(); } else if (jsFunName.contains('gameRecharge')) { print("BSGAME游戏调⽤gameRecharge main.dart"); //拉起⽀付商城TODO客⼾端 _showGameRecharge(); } else if (jsFunName.contains('gameLoaded')) { print("BSGAME游戏调⽤gameLoaded main.dart"); setState(() { _isLoading = false; }); //游戏加载完毕TODO客⼾端 } else if (jsFunName.contains('sendGameAction')) { print("BSGAME游戏调⽤sendGameAction main.dart--${obj}"); String str = sendGameActionUtil(obj); if (str.isNotEmpty) { _controller.runJavaScript(str); } } }); } else { _controller.addJavaScriptChannel( "getConfig", onMessageReceived: (JavaScriptMessage jsonMessage) { print("BSGAME 游戏调⽤getConfig main.dart ios"); final obj = json.decode(jsonMessage.message); String jsFunName = obj['jsCallback']; ATGetGameConfigData _configData = ATGetGameConfigData( appChannel: ATGlobalConfig.gameAppChannel, appId: ATGlobalConfig.gameAppid, userId: AccountStorage().getCurrentUser()?.userProfile?.id ?? "", gameMode: widget.height < 0 ? "3" : "2", language: ATGlobalConfig.lang == "ar" ? "7" : "2", gsp: 101, roomId: Provider.of( context, listen: false, ).currenRoom?.roomProfile?.roomProfile?.id ?? "", code: AccountStorage().getToken(), gameConfig: GameConfig( sceneMode: 0, currencyIcon: "https://tkm-atu.oss-ap-southeast-1.aliyuncs.com/avatar/b1bc4425-0037-433b-bf00-6977620ff57e.png", ), ); String jsUrl = jsFunName + "(${jsonEncode(_configData.toJson())})"; _controller!.runJavaScript(jsUrl); }, ); _controller.addJavaScriptChannel( "destroy", onMessageReceived: (JavaScriptMessage message) { print("BSGAME 游戏调⽤destroy main.dart ios"); _controller.loadRequest(Uri.parse('about:blank')); if (widget.gameMode == ATGameModeType.CHAT_ROOM) { Provider.of( context, listen: false, ).roomMannyGameClose(); } else { Navigator.of(context).pop(); } super.dispose(); }, ); _controller.addJavaScriptChannel( "gameRecharge", onMessageReceived: (JavaScriptMessage message) { print("BSGAME 游戏调⽤gameRecharge main.dart ios"); _showGameRecharge(); }, ); _controller.addJavaScriptChannel( "gameLoaded", onMessageReceived: (JavaScriptMessage message) { setState(() { _isLoading = false; }); print("BSGAME 游戏调⽤gameLoaded main.dart ios"); }, ); _controller.addJavaScriptChannel( "sendGameAction", onMessageReceived: (JavaScriptMessage message) { String str = sendGameActionUtil(message.message); if (str.isNotEmpty) { _controller.runJavaScript(str); } }, ); } } void _showGameRecharge() { SmartDialog.dismiss(tag: "showConfirmDialog"); SmartDialog.show( tag: "showConfirmDialog", alignment: Alignment.center, animationType: SmartAnimationType.fade, builder: (_) { return MsgDialog( title: ATAppLocalizations.of(context)!.tips, msg: ATAppLocalizations.of(context)!.balanceNotEnough, btnText: ATAppLocalizations.of(context)!.confirm, onEnsure: () { SmartDialog.dismiss(tag: "showConfirmDialog"); ATNavigatorUtils.push( context, WalletRoute.recharge, replace: false, ); }, ); }, ); } String sendGameActionUtil(message) { String result = ''; int type = message['type']; Map params = message['params']; switch (type) { case 13: //游戏开始 break; case 14: //游戏结束 break; case 15: //上下座 int optType = params['optType']; //0 上座,1 下座 String userId = params['userId']; //用户 id int seat = params['seat']; ////座位位置 //如果不鉴权就直接把下面的消息返回 final Map map = {}; map["optType"] = optType; map["userId"] = userId; map["seat"] = seat; final Map parentMap = {}; parentMap["type"] = 4; // 使用下标操作符添加数据 parentMap["params"] = map; result = "gameActionUpdate(${json.encode(parentMap)})"; break; case 17: //踢人 String userId = params['userId']; int seat = params['seat']; //如果不鉴权就直接把下面的消息返回 final Map map = {}; map["optResult"] = 0; map["optUserId"] = AccountStorage().getCurrentUser()?.userProfile?.id; map["userId"] = userId; map["reason"] = seat; final Map parentMap = {}; parentMap["type"] = 6; // 使用下标操作符添加数据 parentMap["params"] = map; result = "gameActionUpdate(${json.encode(parentMap)})"; break; } return result; } void _uploadGameRecord() { ChatRoomRepository().ludoHistoryRecord( widget.gameId, widget.height > 0 ? "IN_ROOM" : "OUT_ROOM", ); } }