import 'dart:convert'; 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_core/utilities/at_pick_utils.dart'; import 'package:aslan/chatvibe_data/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:aslan/chatvibe_core/constants/at_global_config.dart'; import 'package:aslan/chatvibe_core/constants/at_screen.dart'; import 'package:aslan/chatvibe_core/routes/at_fluro_navigator.dart'; import 'package:aslan/chatvibe_core/utilities/at_deviceId_utils.dart'; import 'package:aslan/chatvibe_core/utilities/at_room_utils.dart'; import 'package:aslan/main.dart'; import 'package:aslan/chatvibe_managers/rtm_manager.dart'; import 'package:aslan/chatvibe_ui/widgets/share/share_page.dart'; import 'package:aslan/chatvibe_features/chat/at_chat_route.dart'; import 'package:aslan/chatvibe_features/index/main_route.dart'; import 'package:aslan/chatvibe_features/webview/at_webview_navigation_handler.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=${ATGlobalConfig.lang}"; // 初始化 WebViewController _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..addJavaScriptChannel( "FlutterPageControl", onMessageReceived: (sjMessage) async { String msg = sjMessage.message; if (sjMessage.message == "close_page") { ATNavigatorUtils.goBack(context); } else if (msg.startsWith("view_user_info")) { //跳转个人信息 if (msg.contains(":")) { var sli = msg.split(":"); if (sli.length > 1) { String userId = sli[1]; ATNavigatorUtils.push( context, "${MainRoute.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]; ATRoomUtils.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()); ATNavigatorUtils.push( context, "${ATChatRouter.chat}?conversation=${Uri.encodeComponent(json)}", ); } } } else if (msg.startsWith("uploadImgFile")) { picImage(); } else if (msg.startsWith("editingRoom")) { ATNavigatorUtils.push(context, MainRoute.editRoomSearchAdmin); } else if (msg.startsWith("editingUser")) { ATNavigatorUtils.push(context, MainRoute.editUserSearchAdmin); } else if (msg.startsWith("myCoupleList")) { ATNavigatorUtils.push(context, MainRoute.cpList); } else if (msg.startsWith("shareDrawer")) { if (msg.contains(":")) { var sli = msg.split(":"); if (sli.length > 1) { String shareMsg = sli[1]; _showShareDialog(shareMsg); } } } }, ) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { setState(() { _progress = progress / 100.0; }); }, onNavigationRequest: ATWebViewNavigationHandler.handleNavigationRequest, 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 ATDeviceIdUtils.collectDeviceId(); // 注入JavaScript对象和方法 _controller.runJavaScript(''' window.app = window.app || {}; // 注入获取访问信息的方法 window.app.getAccessOrigin = function() { // 获取认证信息(这里可以从Flutter传递) return JSON.stringify({ 'Authorization': 'Bearer ${AccountStorage().token}', 'Req-Lang': '${ATGlobalConfig.lang}', 'Req-App-Intel': 'build=${ATGlobalConfig.build};version=${ATGlobalConfig.version};model=${ATGlobalConfig.model};channel=${ATGlobalConfig.channel};Req-Imei=$imei', 'Req-Sys-Origin': 'origin=${ATGlobalConfig.origin};originChild=${ATGlobalConfig.originChild}' }); }; // 注入其他可能需要的方法 window.app.getAuth = function() { return window.app.getAccessOrigin(); }; // 可以通过这个方法向Flutter发送消息 window.app.sendToFlutter = function(data) { FlutterApp.postMessage(data); }; '''); } void picImage() async { ATPickUtils.pickImageProcess(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: ATGlobalConfig.businessLogicStrategy .getWebViewPageAppBarBackgroundColor(), centerTitle: true, title: Text( _title.isNotEmpty ? _title : widget.title, style: TextStyle( fontSize: sp(18), color: ATGlobalConfig.businessLogicStrategy .getWebViewPageTitleTextColor(), ), ), leading: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { ATNavigatorUtils.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: ATGlobalConfig.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: ATGlobalConfig.businessLogicStrategy .getWebViewPageProgressBarBackgroundColor(), minHeight: 1.0, valueColor: AlwaysStoppedAnimation( ATGlobalConfig.businessLogicStrategy .getWebViewPageProgressBarActiveColor(), ), ) : const SizedBox.shrink(); } void _onWebResourceError(WebResourceError error) { print('_onWebResourceError:${error.description}, url:${error.url}'); ATWebViewNavigationHandler.handleWebResourceError(error); } void _showShareDialog(String shareMsg) { SmartDialog.show( tag: "showShareDialog", alignment: Alignment.bottomCenter, debounce: true, animationType: SmartAnimationType.fade, builder: (_) { return SharePage(shareMsg); }, ); } }