chatapp3-flutter/lib/modules/webview/webview_page.dart
2026-04-09 21:32:23 +08:00

292 lines
10 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<WebViewPage> {
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<RtmProvider>(
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<void> _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>(Color(0xffFF6000)),
// ),
// ),
],
),
),
);
}
Widget _progressBar(double progress, BuildContext context) {
return progress < 1.0
? LinearProgressIndicator(
value: progress,
backgroundColor: SCGlobalConfig.businessLogicStrategy.getWebViewPageProgressBarBackgroundColor(),
minHeight: 1.0,
valueColor: AlwaysStoppedAnimation<Color>(SCGlobalConfig.businessLogicStrategy.getWebViewPageProgressBarActiveColor()),
)
: const SizedBox.shrink();
}
void _onWebResourceError(WebResourceError error) {
print('_onWebResourceError:${error.description}');
// 可以在这里添加错误处理逻辑,比如显示错误页面
}
}