import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:yumi/shared/tools/sc_pick_utils.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:provider/provider.dart'; import 'package:tencent_cloud_chat_sdk/enum/conversation_type.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:yumi/app/constants/sc_global_config.dart'; import 'package:yumi/app/constants/sc_screen.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/shared/tools/sc_deviceId_utils.dart'; import 'package:yumi/shared/tools/sc_room_utils.dart'; import 'package:yumi/main.dart'; import 'package:yumi/services/audio/rtm_manager.dart'; import 'package:yumi/modules/index/main_route.dart'; import '../chat/chat_route.dart'; class WebViewPage extends StatefulWidget { final String title; final String url; final String showTitle; const WebViewPage({ Key? key, this.title = "", this.showTitle = "true", required this.url, }) : super(key: key); @override _WebViewPageState createState() => _WebViewPageState(); } class _WebViewPageState extends State { late WebViewController _controller; String _title = ""; double _progress = 0.0; bool _isLoading = true; String urlLink = ""; @override void initState() { super.initState(); if (widget.url.split("?").length > 1) { urlLink = "${widget.url}&"; } else { urlLink = "${widget.url}?"; } urlLink = "${urlLink}lang=${SCGlobalConfig.lang}"; // 初始化 WebViewController _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..addJavaScriptChannel( "FlutterPageControl", onMessageReceived: (sjMessage) async { String msg = sjMessage.message; if (sjMessage.message == "close_page") { SCNavigatorUtils.goBack(context); } else if (msg.startsWith("view_user_info")) { //跳转个人信息 if (msg.contains(":")) { var sli = msg.split(":"); if (sli.length > 1) { String userId = sli[1]; SCNavigatorUtils.push( context, "${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == userId}&tageId=$userId", ); } } } else if (msg.startsWith("go_to_room")) { //跳转房间 if (msg.contains(":")) { var sli = msg.split(":"); if (sli.length > 1) { String roomId = sli[1]; SCRoomUtils.goRoom( roomId, navigatorKey.currentState!.context, ); } } } else if (msg.startsWith("private_chat")) { //打开私聊 if (msg.contains(":")) { var sli = msg.split(":"); if (sli.length > 1) { String userId = sli[1]; var conversation = V2TimConversation( type: ConversationType.V2TIM_C2C, userID: userId, conversationID: '', ); var bool = await Provider.of( context, listen: false, ).startConversation(conversation); if (!bool) return; var json = jsonEncode(conversation.toJson()); SCNavigatorUtils.push( context, "${SCChatRouter.chat}?conversation=${Uri.encodeComponent(json)}", ); } } } else if (msg.startsWith("uploadImgFile")) { picImage(); } else if (msg.startsWith("editingRoom")) { SCNavigatorUtils.push(context, SCMainRoute.editRoomSearchAdmin); } else if (msg.startsWith("editingUser")) { SCNavigatorUtils.push(context, SCMainRoute.editUserSearchAdmin); } }, ) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { setState(() { _progress = progress / 100.0; }); }, onPageStarted: (String url) { setState(() { _isLoading = true; }); }, onPageFinished: (String url) { // 延迟500毫秒注入,等待Vue3初始化 Future.delayed(Duration(milliseconds: 550), () { _injectJavaScriptInterface(); }); setState(() { _isLoading = false; _getPageTitle(); }); }, onWebResourceError: (WebResourceError error) { _onWebResourceError(error); }, ), ) ..loadRequest(Uri.parse(urlLink)); } @override void dispose() { _controller.loadRequest(Uri.parse('about:blank')); super.dispose(); } void _injectJavaScriptInterface() async { String imei = await SCDeviceIdUtils.getDeviceId(); // 注入JavaScript对象和方法 _controller.runJavaScript(''' window.app = window.app || {}; // 注入获取访问信息的方法 window.app.getAccessOrigin = function() { // 获取认证信息(这里可以从Flutter传递) return JSON.stringify({ 'Authorization': 'Bearer ${AccountStorage().token}', 'Req-Lang': '${SCGlobalConfig.lang}', 'Req-App-Intel': 'build=${SCGlobalConfig.build};version=${SCGlobalConfig.version};model=${SCGlobalConfig.model};channel=${SCGlobalConfig.channel};Req-Imei=$imei', 'Req-Sys-Origin': 'origin=${SCGlobalConfig.origin};originChild=${SCGlobalConfig.originChild}' }); }; // 注入其他可能需要的方法 window.app.getAuth = function() { return window.app.getAccessOrigin(); }; // 可以通过这个方法向Flutter发送消息 window.app.sendToFlutter = function(data) { FlutterApp.postMessage(data); }; '''); } void picImage() async { SCPickUtils.pickImage(context, (b, path) { _controller.runJavaScript(''' window.app = window.app || {}; // 注入获取访问信息的方法 window.app.getImagePath = function() { // 获取认证信息(这里可以从Flutter传递) return JSON.stringify({ 'path': '$path', }); }; // 注入其他可能需要的方法 window.app.getAuth = function() { return window.app.getImagePath(); }; // 可以通过这个方法向Flutter发送消息 window.app.sendToFlutter = function(data) { FlutterApp.postMessage(data); }; '''); }, neeCrop: false); } // 获取页面标题 Future _getPageTitle() async { try { final title = await _controller.runJavaScriptReturningResult("document.title") as String?; if (title != null) { setState(() { _title = title.replaceAll("\"", ""); }); } } catch (e) { print("获取标题失败: $e"); } } @override Widget build(BuildContext context) { return Scaffold( appBar: widget.showTitle == "true" ? AppBar( elevation: 0, backgroundColor: SCGlobalConfig.businessLogicStrategy.getWebViewPageAppBarBackgroundColor(), centerTitle: true, title: Text( _title.isNotEmpty ? _title : widget.title, style: TextStyle( fontSize: sp(18), color: SCGlobalConfig.businessLogicStrategy.getWebViewPageTitleTextColor(), ), ), leading: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { SCNavigatorUtils.goBack(context); }, child: Container( padding: EdgeInsets.only(left: width(15), right: width(15)), child: Center( child: Icon(Icons.arrow_back_ios, size: 20.w, color: SCGlobalConfig.businessLogicStrategy.getWebViewPageBackArrowColor()), ), ), ), systemOverlayStyle: SystemUiOverlayStyle.dark, ) : null, body: SafeArea( top: false, child: Stack( children: [ WebViewWidget(controller: _controller), // 加载指示器 // if (_isLoading) // Center( // child: CircularProgressIndicator( // valueColor: AlwaysStoppedAnimation(Color(0xffFF6000)), // ), // ), ], ), ), ); } Widget _progressBar(double progress, BuildContext context) { return progress < 1.0 ? LinearProgressIndicator( value: progress, backgroundColor: SCGlobalConfig.businessLogicStrategy.getWebViewPageProgressBarBackgroundColor(), minHeight: 1.0, valueColor: AlwaysStoppedAnimation(SCGlobalConfig.businessLogicStrategy.getWebViewPageProgressBarActiveColor()), ) : const SizedBox.shrink(); } void _onWebResourceError(WebResourceError error) { print('_onWebResourceError:${error.description}'); // 可以在这里添加错误处理逻辑,比如显示错误页面 } }