From 963db9bd3d98dca73547f45441c1eb65206674f3 Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Tue, 18 Nov 2025 22:46:08 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(rtc):=20=E9=9B=86=E6=88=90=E5=A3=B0?= =?UTF-8?q?=E7=BD=91RTC=E5=92=8CRTM=E5=8A=9F=E8=83=BD=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=AE=9E=E6=97=B6=E9=9F=B3=E8=A7=86=E9=A2=91=E9=80=9A?= =?UTF-8?q?=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增获取声网RTC和RTM Token的接口与实现 - 更新RTC管理器以支持频道创建及加入流程 - 实现RTM管理器初始化、登录及频道订阅功能 - 添加agora_token_generator依赖用于生成RTM令牌 - 修改RTC初始化逻辑以适配直播场景并启用视频预览- 在用户加入频道成功后自动订阅RTM频道并发送加入房间消息 -优化网络请求代码结构,新增RTC相关API和服务端交互逻辑 --- lib/widget/live/live_room_anchor_showcase.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/widget/live/live_room_anchor_showcase.dart b/lib/widget/live/live_room_anchor_showcase.dart index 8522a2c..1b1247b 100644 --- a/lib/widget/live/live_room_anchor_showcase.dart +++ b/lib/widget/live/live_room_anchor_showcase.dart @@ -90,6 +90,7 @@ class LiveRoomAnchorShowcase extends StatelessWidget { isLeft: true, micIcon: Assets.imagesMicClose, ), + SizedBox(width: 15.w), _buildSideAnchorCard( isLeft: false, micIcon: Assets.imagesMicOpen, From 11832809e0633f7228855666dcab4d274b980eee Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Wed, 19 Nov 2025 00:56:28 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat(live):=20=E5=AE=9E=E7=8E=B0=E7=9B=B4?= =?UTF-8?q?=E6=92=AD=E9=97=B4RTC=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96UI=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 集成声网RTC SDK,实现直播频道创建与加入功能 - 添加摄像头和麦克风权限申请机制 - 实现RTC频道状态监听与UI同步更新 -优化直播间主播展示区域,支持视频流渲染 - 完善房间控制器逻辑,添加资源释放机制 - 更新依赖库,引入app_settings和package_info_plus插件- 修复discover页面布局样式问题,提升代码可读性 --- lib/controller/discover/room_controller.dart | 45 +++- lib/pages/discover/discover_page.dart | 212 +++++++++-------- lib/pages/discover/live_room_page.dart | 15 +- lib/rtc/rtc_manager.dart | 24 +- .../live/live_room_anchor_showcase.dart | 218 +++++++++++------- pubspec.lock | 10 +- 6 files changed, 321 insertions(+), 203 deletions(-) diff --git a/lib/controller/discover/room_controller.dart b/lib/controller/discover/room_controller.dart index f1eb85f..9231af0 100644 --- a/lib/controller/discover/room_controller.dart +++ b/lib/controller/discover/room_controller.dart @@ -5,8 +5,7 @@ import 'package:dating_touchme_app/rtc/rtc_manager.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; - -import '../../pages/discover/live_room_page.dart'; +import 'package:permission_handler/permission_handler.dart'; /// 直播房间相关控制器 class RoomController extends GetxController { @@ -23,7 +22,9 @@ class RoomController extends GetxController { /// 调用接口创建 RTC 频道 Future createRtcChannel() async { - if (isLoading.value) return ; + if (isLoading.value) return; + final granted = await _ensureRtcPermissions(); + if (!granted) return; try { isLoading.value = true; @@ -31,6 +32,14 @@ class RoomController extends GetxController { final base = response.data; if (base.isSuccess && base.data != null) { rtcChannel.value = base.data; + GetStorage storage = GetStorage(); + String userId = storage.read('userId') ?? ''; + String tokens = RtmTokenBuilder.buildToken( + appId: '4c2ea9dcb4c5440593a418df0fdd512d', + appCertificate: '16f34b45181a4fae8acdb1a28762fcfa', + userId: userId, + tokenExpireSeconds: 3600, + ); await _joinRtcChannel(base.data!.token, base.data!.channelId, base.data!.uid); } else { final message = base.message.isNotEmpty ? base.message : '创建频道失败'; @@ -42,16 +51,42 @@ class RoomController extends GetxController { isLoading.value = false; } } - Future _joinRtcChannel(String token, String channelName, int uid) async { + Future _joinRtcChannel( + String token, + String channelName, + int uid, + ) async { try { await RTCManager.instance.joinChannel( token: token, channelId: channelName, - uid: uid + uid: uid, ); } catch (e) { SmartDialog.showToast('加入频道失败:$e'); } } + + Future _ensureRtcPermissions() async { + final statuses = await [Permission.camera, Permission.microphone].request(); + final allGranted = statuses.values.every((status) => status.isGranted); + if (allGranted) { + return true; + } + + final permanentlyDenied = + statuses.values.any((status) => status.isPermanentlyDenied); + if (permanentlyDenied) { + SmartDialog.showToast('请在系统设置中开启摄像头和麦克风权限'); + await openAppSettings(); + } else { + SmartDialog.showToast('请允许摄像头和麦克风权限以进入房间'); + } + return false; + } + + Future disposeRtcResources() async { + await RTCManager.instance.dispose(); + } } diff --git a/lib/pages/discover/discover_page.dart b/lib/pages/discover/discover_page.dart index ecafdad..6413dbc 100644 --- a/lib/pages/discover/discover_page.dart +++ b/lib/pages/discover/discover_page.dart @@ -13,7 +13,8 @@ class DiscoverPage extends StatefulWidget { State createState() => _DiscoverPageState(); } -class _DiscoverPageState extends State with AutomaticKeepAliveClientMixin{ +class _DiscoverPageState extends State + with AutomaticKeepAliveClientMixin { late final RoomController roomController; List topNav = ["相亲", "聚会脱单"]; @@ -31,13 +32,10 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie {"isNew": false}, ]; - List tabList = [ - "全部", "同城", "相亲视频", "相亲语音" - ]; + List tabList = ["全部", "同城", "相亲视频", "相亲语音"]; int active = 0; - void changeNav(int active) { print("当前项: $active"); } @@ -69,29 +67,33 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie child: Column( children: [ - HomeAppbar(topNav: topNav, changeNav: changeNav, right: InkWell( - onTap: () async { - await roomController.createRtcChannel(); - }, - child: Container( - width: 52.w, - height: 20.w, - decoration: BoxDecoration( + HomeAppbar( + topNav: topNav, + changeNav: changeNav, + right: InkWell( + onTap: () async { + await roomController.createRtcChannel(); + }, + child: Container( + width: 52.w, + height: 20.w, + decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(20.w)), - color: const Color.fromRGBO(108, 105, 244, 1) - ), - child: Center( - child: Text( - "申请红娘", - style: TextStyle( + color: const Color.fromRGBO(108, 105, 244, 1), + ), + child: Center( + child: Text( + "申请红娘", + style: TextStyle( fontSize: 10.w, color: Colors.white, - fontWeight: FontWeight.w500 + fontWeight: FontWeight.w500, + ), ), ), ), ), - ),), + ), Container( width: 351.w, height: 45.w, @@ -100,30 +102,41 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - ...tabList.asMap().entries.map((entry){ + ...tabList.asMap().entries.map((entry) { return Container( margin: EdgeInsets.only(right: 27.w), child: InkWell( - onTap: (){ + onTap: () { active = entry.key; - setState(() { - - }); + setState(() {}); }, child: Container( height: 21.w, - padding: EdgeInsets.symmetric(horizontal: active == entry.key ? 30.w : 0), + padding: EdgeInsets.symmetric( + horizontal: active == entry.key ? 30.w : 0, + ), decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(21.w)), - color: Color.fromRGBO(108, 105, 244, active == entry.key ? 1 : 0) + borderRadius: BorderRadius.all( + Radius.circular(21.w), + ), + color: Color.fromRGBO( + 108, + 105, + 244, + active == entry.key ? 1 : 0, + ), ), child: Center( child: Text( entry.value, style: TextStyle( - fontSize: 12.w, - color: active == entry.key ? Colors.white :const Color.fromRGBO(51, 51, 51, .7), - fontWeight: active == entry.key ? FontWeight.w700 : FontWeight.w500 + fontSize: 12.w, + color: active == entry.key + ? Colors.white + : const Color.fromRGBO(51, 51, 51, .7), + fontWeight: active == entry.key + ? FontWeight.w700 + : FontWeight.w500, ), ), ), @@ -141,17 +154,16 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie spacing: 7.w, runSpacing: 7.w, children: [ - ...liveList.map((e){ - return LiveItem(item: e,); + ...liveList.map((e) { + return LiveItem(item: e); }), - ], ), ), - ) + ), ], ), - ) + ), ], ); } @@ -160,8 +172,6 @@ class _DiscoverPageState extends State with AutomaticKeepAliveClie bool get wantKeepAlive => true; } - - class LiveItem extends StatefulWidget { final Map item; const LiveItem({super.key, required this.item}); @@ -174,7 +184,7 @@ class _LiveItemState extends State { @override Widget build(BuildContext context) { return InkWell( - onTap: (){ + onTap: () { Get.to(() => LiveRoomPage(id: 0)); }, child: ClipRRect( @@ -185,7 +195,7 @@ class _LiveItemState extends State { width: 171.w, height: 171.w, decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10.w)) + borderRadius: BorderRadius.all(Radius.circular(10.w)), ), child: Image.network( "https://picsum.photos/400", @@ -208,62 +218,63 @@ class _LiveItemState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - SizedBox(width: 5.w,), + SizedBox(width: 5.w), Image.asset( Assets.imagesLocationIcon, width: 6.w, height: 7.w, ), - SizedBox(width: 3.w,), + SizedBox(width: 3.w), Text( "49.9km", style: TextStyle( - fontSize: 8.w, - color: Colors.white, - fontWeight: FontWeight.w500 + fontSize: 8.w, + color: Colors.white, + fontWeight: FontWeight.w500, ), - ) + ), ], ), - ) + ), ], ), ), - if(widget.item["isNew"]) Positioned( - top: 9.w, - right: 8.w, - child: Container( - width: 39.w, - height: 13.w, - decoration: BoxDecoration( + if (widget.item["isNew"]) + Positioned( + top: 9.w, + right: 8.w, + child: Container( + width: 39.w, + height: 13.w, + decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(13.w)), - color: const Color.fromRGBO(0, 0, 0, .3) - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 5.w, - height: 5.w, - margin: EdgeInsets.only(right: 3.w), - decoration: BoxDecoration( + color: const Color.fromRGBO(0, 0, 0, .3), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 5.w, + height: 5.w, + margin: EdgeInsets.only(right: 3.w), + decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(5.w)), - color: const Color.fromRGBO(255, 209, 43, 1) + color: const Color.fromRGBO(255, 209, 43, 1), + ), ), - ), - Text( - "等待", - style: TextStyle( + Text( + "等待", + style: TextStyle( fontSize: 8.w, color: Colors.white, - fontWeight: FontWeight.w500 + fontWeight: FontWeight.w500, + ), ), - ) - ], + ], + ), ), ), - ), Positioned( left: 9.w, bottom: 6.w, @@ -277,51 +288,54 @@ class _LiveItemState extends State { maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( - fontSize: 8.w, - color: Colors.white, - fontWeight: FontWeight.w500 + fontSize: 8.w, + color: Colors.white, + fontWeight: FontWeight.w500, ), ), ), - SizedBox(height: 2.w,), + SizedBox(height: 2.w), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "福州 | 28岁", style: TextStyle( - fontSize: 11.w, - color: Colors.white, - fontWeight: FontWeight.w500 + fontSize: 11.w, + color: Colors.white, + fontWeight: FontWeight.w500, ), ), - SizedBox(width: 5.w,), - if(widget.item["isNew"]) Container( - width: 32.w, - height: 10.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10.w)), - color: const Color.fromRGBO(255, 206, 28, .8) - ), - child: Center( - child: Text( - "新人", - style: TextStyle( + SizedBox(width: 5.w), + if (widget.item["isNew"]) + Container( + width: 32.w, + height: 10.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(10.w), + ), + color: const Color.fromRGBO(255, 206, 28, .8), + ), + child: Center( + child: Text( + "新人", + style: TextStyle( fontSize: 8.w, color: Colors.white, - fontWeight: FontWeight.w500 + fontWeight: FontWeight.w500, + ), ), ), ), - ) ], - ) + ), ], ), - ) + ), ], ), ), ); } -} \ No newline at end of file +} diff --git a/lib/pages/discover/live_room_page.dart b/lib/pages/discover/live_room_page.dart index c297871..ab5e03b 100644 --- a/lib/pages/discover/live_room_page.dart +++ b/lib/pages/discover/live_room_page.dart @@ -1,8 +1,10 @@ +import 'package:dating_touchme_app/controller/discover/room_controller.dart'; import 'package:dating_touchme_app/generated/assets.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; import 'package:dating_touchme_app/widget/live/live_room_user_header.dart'; import 'package:dating_touchme_app/widget/live/live_room_anchor_showcase.dart'; import 'package:dating_touchme_app/widget/live/live_room_seat_list.dart'; @@ -21,6 +23,7 @@ class LiveRoomPage extends StatefulWidget { } class _LiveRoomPageState extends State { + late final RoomController _roomController; String message = ''; final TextEditingController _messageController = TextEditingController(); @@ -64,6 +67,16 @@ class _LiveRoomPageState extends State { @override void initState() { super.initState(); + _roomController = Get.isRegistered() + ? Get.find() + : Get.put(RoomController()); + } + + @override + void dispose() { + _roomController.disposeRtcResources(); + _messageController.dispose(); + super.dispose(); } void _showGiftPopup() { @@ -135,7 +148,7 @@ class _LiveRoomPageState extends State { popularityText: '1263', ), SizedBox(height: 7.w), - const LiveRoomAnchorShowcase(), + LiveRoomAnchorShowcase(), SizedBox(height: 5.w), const LiveRoomSeatList(), SizedBox(height: 5.w), diff --git a/lib/rtc/rtc_manager.dart b/lib/rtc/rtc_manager.dart index 6f70add..6150f64 100644 --- a/lib/rtc/rtc_manager.dart +++ b/lib/rtc/rtc_manager.dart @@ -2,12 +2,19 @@ import 'dart:convert'; import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:dating_touchme_app/rtc/rtm_manager.dart'; +import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import '../pages/discover/live_room_page.dart'; /// RTC 管理器,负责管理声网音视频通话功能 class RTCManager { + /// 频道加入状态通知,用于UI监听 + final ValueNotifier channelJoinedNotifier = ValueNotifier(false); + RtcEngine? get engine => _engine; + bool get isInChannel => _isInChannel; + int? get currentUid => _currentUid; + // 单例模式 static final RTCManager _instance = RTCManager._internal(); factory RTCManager() => _instance; @@ -19,6 +26,7 @@ class RTCManager { bool _isInChannel = false; String? _currentChannelId; int? _currentUid; + int? _streamId; // 事件回调 Function(RtcConnection connection, int elapsed)? onJoinChannelSuccess; @@ -101,6 +109,7 @@ class RTCManager { RtcEngineEventHandler( onJoinChannelSuccess: (RtcConnection connection, int elapsed) async{ _isInChannel = true; + channelJoinedNotifier.value = true; _currentChannelId = connection.channelId; print('加入频道成功,频道名:${connection.channelId},耗时:${elapsed}ms'); if(connection.localUid == _currentUid){ @@ -121,6 +130,9 @@ class RTCManager { onUserJoined!(connection, remoteUid, elapsed); } }, + onStreamMessage: (RtcConnection connection, int remoteUid, int streamId, Uint8List data, int length, int sentTs){ + print('收到消息,UID:$remoteUid,流ID:$streamId,数据:${utf8.decode(data)}'); + }, onUserOffline: ( RtcConnection connection, @@ -134,6 +146,7 @@ class RTCManager { }, onLeaveChannel: (RtcConnection connection, RtcStats stats) { _isInChannel = false; + channelJoinedNotifier.value = false; _currentChannelId = null; print('离开频道,统计信息:${stats.duration}秒'); if (onLeaveChannel != null) { @@ -347,6 +360,7 @@ class RTCManager { uid: uid, options: options ?? const ChannelMediaOptions(), ); + _streamId = await _engine?.createDataStream(DataStreamConfig(syncWithAudio: false, ordered: false)); print('正在加入频道:$channelId,UID:$uid'); } @@ -407,18 +421,9 @@ class RTCManager { print('客户端角色已设置为:$role'); } - /// 获取当前是否在频道中 - bool get isInChannel => _isInChannel; - /// 获取当前频道ID String? get currentChannelId => _currentChannelId; - /// 获取当前用户ID - int? get currentUid => _currentUid; - - /// 获取 RTC Engine 实例(用于高级操作) - RtcEngine? get engine => _engine; - /// 释放资源 Future dispose() async { try { @@ -433,6 +438,7 @@ class RTCManager { _isInChannel = false; _currentChannelId = null; _currentUid = null; + channelJoinedNotifier.value = false; print('RTC Engine disposed'); } catch (e) { print('Failed to dispose RTC Engine: $e'); diff --git a/lib/widget/live/live_room_anchor_showcase.dart b/lib/widget/live/live_room_anchor_showcase.dart index 1b1247b..953182a 100644 --- a/lib/widget/live/live_room_anchor_showcase.dart +++ b/lib/widget/live/live_room_anchor_showcase.dart @@ -1,110 +1,157 @@ +import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/rtc/rtc_manager.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -class LiveRoomAnchorShowcase extends StatelessWidget { +class LiveRoomAnchorShowcase extends StatefulWidget { const LiveRoomAnchorShowcase({super.key}); + @override + State createState() => _LiveRoomAnchorShowcaseState(); +} + +class _LiveRoomAnchorShowcaseState extends State { + final RTCManager _rtcManager = RTCManager.instance; + @override Widget build(BuildContext context) { - return Column( - children: [ - Stack( + return ValueListenableBuilder( + valueListenable: _rtcManager.channelJoinedNotifier, + builder: (context, joined, _) { + return Column( children: [ - Container( - width: 177.w, - height: 175.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(9.w)), - color: const Color.fromRGBO(47, 10, 94, 1), - ), - ), - Positioned( - top: 5.w, - left: 5.w, - child: Container( - width: 42.w, - height: 13.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(13.w)), - color: const Color.fromRGBO(142, 20, 186, 1), - ), - child: Center( - child: Text( - "主持人", - style: TextStyle( - fontSize: 9.w, - color: Colors.white, + Stack( + children: [ + _buildAnchorVideo(joined), + Positioned( + top: 5.w, + left: 5.w, + child: Container( + width: 42.w, + height: 13.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(13.w)), + color: const Color.fromRGBO(142, 20, 186, 1), + ), + child: Center( + child: Text( + "主持人", + style: TextStyle(fontSize: 9.w, color: Colors.white), + ), ), ), ), - ), - ), - Positioned( - top: 5.w, - right: 5.w, - child: Container( - width: 20.w, - height: 20.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(20.w)), - color: const Color.fromRGBO(0, 0, 0, .3), + Positioned( + top: 5.w, + right: 5.w, + child: Container( + width: 20.w, + height: 20.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.w)), + color: const Color.fromRGBO(0, 0, 0, .3), + ), + child: Center( + child: Image.asset( + Assets.imagesGiftIcon, + width: 19.w, + height: 19.w, + ), + ), + ), ), - child: Center( - child: Image.asset( - Assets.imagesGiftIcon, - width: 19.w, - height: 19.w, + Positioned( + bottom: 5.w, + right: 5.w, + child: Container( + width: 47.w, + height: 20.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.w)), + color: Colors.white, + ), + child: Center( + child: Text( + "加好友", + style: TextStyle( + fontSize: 11.w, + color: const Color.fromRGBO(117, 98, 249, 1), + ), + ), + ), ), ), - ), + ], ), - Positioned( - bottom: 5.w, - right: 5.w, - child: Container( - width: 47.w, - height: 20.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(20.w)), - color: Colors.white, + SizedBox(height: 5.w), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _buildSideAnchorCard( + isLeft: true, + micIcon: Assets.imagesMicClose, ), - child: Center( - child: Text( - "加好友", - style: TextStyle( - fontSize: 11.w, - color: const Color.fromRGBO(117, 98, 249, 1), - ), - ), + _buildSideAnchorCard( + isLeft: false, + micIcon: Assets.imagesMicOpen, ), - ), + ], ), ], - ), - SizedBox(height: 5.w), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _buildSideAnchorCard( - isLeft: true, - micIcon: Assets.imagesMicClose, - ), - SizedBox(width: 15.w), - _buildSideAnchorCard( - isLeft: false, - micIcon: Assets.imagesMicOpen, + ); + }, + ); + } + + Widget _buildAnchorVideo(bool joined) { + final engine = _rtcManager.engine; + if (!joined || engine == null) { + return _buildWaitingPlaceholder(); + } + + final localUid = _rtcManager.currentUid ?? 0; + return ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(9.w)), + child: SizedBox( + width: 177.w, + height: 175.w, + child: AgoraVideoView( + controller: VideoViewController( + rtcEngine: engine, + canvas: VideoCanvas( + uid: 0, ), - ], + ), + onAgoraVideoViewCreated: (viewId){ + engine.startPreview(); + }, ), - ], + ), + ); + } + + Widget _buildWaitingPlaceholder() { + return Container( + width: 177.w, + height: 175.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(9.w)), + color: const Color.fromRGBO(47, 10, 94, 1), + ), + child: Center( + child: Text( + '等待主播', + style: TextStyle( + color: Colors.white.withOpacity(0.8), + fontSize: 12.w, + ), + ), + ), ); } - Widget _buildSideAnchorCard({ - required bool isLeft, - required String micIcon, - }) { + Widget _buildSideAnchorCard({required bool isLeft, required String micIcon}) { return Stack( children: [ Container( @@ -170,11 +217,7 @@ class LiveRoomAnchorShowcase extends StatelessWidget { color: const Color.fromRGBO(0, 0, 0, .65), ), child: Center( - child: Image.asset( - micIcon, - width: 10.w, - height: 11.w, - ), + child: Image.asset(micIcon, width: 10.w, height: 11.w), ), ), SizedBox(width: 5.w), @@ -193,4 +236,3 @@ class LiveRoomAnchorShowcase extends StatelessWidget { ); } } - diff --git a/pubspec.lock b/pubspec.lock index 1886d6d..83bf62a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,6 +49,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" + app_settings: + dependency: "direct main" + description: + name: app_settings + sha256: "3e46c561441e5820d3a25339bf8b51b9e45a5f686873851a20c257a530917795" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.1" archive: dependency: transitive description: @@ -949,7 +957,7 @@ packages: source: hosted version: "2.2.0" package_info_plus: - dependency: transitive + dependency: "direct main" description: name: package_info_plus sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d From fc4efc6edf7e838760eab5e4c430983b65888528 Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Wed, 19 Nov 2025 01:17:22 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(rtc):=20=E6=B7=BB=E5=8A=A0-=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=B6=88=E6=81=AF=E5=8A=9F=E8=83=BD=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20sendMessage=20=E6=96=B9=E6=B3=95=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=AD=97=E7=AC=A6=E4=B8=B2=E6=B6=88=E6=81=AF?= =?UTF-8?q?=20-=20=E4=BD=BF=E7=94=A8=20UTF-8=20=E7=BC=96=E7=A0=81=E5=B0=86?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BD=AC=E6=8D=A2=E4=B8=BA=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E6=B5=81=20-=20=E8=B0=83=E7=94=A8=E5=BC=95=E6=93=8E=E7=9A=84?= =?UTF-8?q?=20sendStreamMessage=20=E6=8E=A5=E5=8F=A3=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=20-=20=E6=89=93=E5=8D=B0=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E7=9A=84=E6=97=A5=E5=BF=97=E4=BF=A1=E6=81=AF?= =?UTF-8?q?-=20=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87=20streamId=20=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=B6=88=E6=81=AF=E5=88=B0=E6=8C=87=E5=AE=9A=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/rtc/rtc_manager.dart | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/rtc/rtc_manager.dart b/lib/rtc/rtc_manager.dart index 6150f64..f49fcd1 100644 --- a/lib/rtc/rtc_manager.dart +++ b/lib/rtc/rtc_manager.dart @@ -421,6 +421,17 @@ class RTCManager { print('客户端角色已设置为:$role'); } + /// 发送消息 + Future sendMessage(String message) async { + Uint8List data = utf8.encode(message); + await _engine!.sendStreamMessage( + streamId: _streamId ?? 0, + data: data, + length: data.length, + ); + print('已发送消息:$message'); + } + /// 获取当前频道ID String? get currentChannelId => _currentChannelId; From be767ef08ccb01c5ed393355d30f2c67dfae1d8d Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Wed, 19 Nov 2025 01:19:01 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(rtc):=20=E6=B7=BB=E5=8A=A0-=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=B6=88=E6=81=AF=E5=8A=9F=E8=83=BD=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=20sendMessage=20=E6=96=B9=E6=B3=95=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E5=8F=91=E9=80=81=E5=AD=97=E7=AC=A6=E4=B8=B2=E6=B6=88=E6=81=AF?= =?UTF-8?q?=20-=20=E4=BD=BF=E7=94=A8=20UTF-8=20=E7=BC=96=E7=A0=81=E5=B0=86?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E8=BD=AC=E6=8D=A2=E4=B8=BA=E5=AD=97=E8=8A=82?= =?UTF-8?q?=E6=B5=81=20-=20=E8=B0=83=E7=94=A8=E5=BC=95=E6=93=8E=E7=9A=84?= =?UTF-8?q?=20sendStreamMessage=20=E6=8E=A5=E5=8F=A3=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=20-=20=E6=89=93=E5=8D=B0=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E7=9A=84=E6=97=A5=E5=BF=97=E4=BF=A1=E6=81=AF?= =?UTF-8?q?-=20=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87=20streamId=20=E5=8F=91?= =?UTF-8?q?=E9=80=81=E6=B6=88=E6=81=AF=E5=88=B0=E6=8C=87=E5=AE=9A=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/controller/discover/room_controller.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/controller/discover/room_controller.dart b/lib/controller/discover/room_controller.dart index 9231af0..3c2f771 100644 --- a/lib/controller/discover/room_controller.dart +++ b/lib/controller/discover/room_controller.dart @@ -67,6 +67,10 @@ class RoomController extends GetxController { } } + Future sendMessage(String message) async { + await RTCManager.instance.sendMessage(message); + } + Future _ensureRtcPermissions() async { final statuses = await [Permission.camera, Permission.microphone].request(); final allGranted = statuses.values.every((status) => status.isGranted); From 4ea8a67471b18863e2800d0df76b7ca4eb8fd92a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AD=90=E8=B4=A4?= Date: Wed, 19 Nov 2025 08:56:38 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.kotlin/errors/errors-1763460366013.log | 198 ++++++++++++++++++ pubspec.lock | 10 +- 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 android/.kotlin/errors/errors-1763460366013.log diff --git a/android/.kotlin/errors/errors-1763460366013.log b/android/.kotlin/errors/errors-1763460366013.log new file mode 100644 index 0000000..6854532 --- /dev/null +++ b/android/.kotlin/errors/errors-1763460366013.log @@ -0,0 +1,198 @@ +kotlin version: 2.1.0 +error message: Daemon compilation failed: null +java.lang.Exception + at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:69) + at org.jetbrains.kotlin.daemon.common.CompileService$CallResult$Error.get(CompileService.kt:65) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:240) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159) + at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111) + at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:76) + at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62) + at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53) + at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59) + at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174) + at java.base/java.util.concurrent.FutureTask.run(Unknown Source) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169) + at org.gradle.internal.Factories$1.create(Factories.java:31) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) + at java.base/java.util.concurrent.FutureTask.run(Unknown Source) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:48) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) + at java.base/java.lang.Thread.run(Unknown Source) +Caused by: java.lang.AssertionError: java.lang.Exception: Could not close incremental caches in D:\www\dating_touchme_app\build\app_settings\kotlin\compileDebugKotlin\cacheable\caches-jvm\jvm\kotlin: class-fq-name-to-source.tab, source-to-classes.tab, internal-name-to-source.tab + at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:236) + at org.jetbrains.kotlin.incremental.IncrementalCachesManager.close(IncrementalCachesManager.kt:55) + at kotlin.io.CloseableKt.closeFinally(Closeable.kt:56) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:293) + at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:674) + at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:91) + at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1659) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) + ... 3 more +Caused by: java.lang.Exception: Could not close incremental caches in D:\www\dating_touchme_app\build\app_settings\kotlin\compileDebugKotlin\cacheable\caches-jvm\jvm\kotlin: class-fq-name-to-source.tab, source-to-classes.tab, internal-name-to-source.tab + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.com.google.common.io.Closer.close(Closer.java:223) + ... 22 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\app_settings-6.1.1\android\src\main\kotlin\com\spencerccf\app_settings\AppSettingsPlugin.kt and D:\www\dating_touchme_app\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:33) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:443) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\app_settings-6.1.1\android\src\main\kotlin\com\spencerccf\app_settings\AppSettingsPlugin.kt and D:\www\dating_touchme_app\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:999) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:451) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\app_settings-6.1.1\android\src\main\kotlin\com\spencerccf\app_settings\AppSettingsPlugin.kt and D:\www\dating_touchme_app\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:33) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.save(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.incremental.storage.AppendableCollectionExternalizer.save(LazyStorage.kt:151) + at org.jetbrains.kotlin.incremental.storage.AppendableCollectionExternalizer.save(LazyStorage.kt:142) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:443) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + Suppressed: java.lang.Exception: Could not close incremental caches in D:\www\dating_touchme_app\build\app_settings\kotlin\compileDebugKotlin\cacheable\caches-jvm\lookups: id-to-file.tab, file-to-id.tab + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:95) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.close(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.LookupStorage.close(LookupStorage.kt:155) + ... 23 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\app_settings-6.1.1\android\src\main\kotlin\com\spencerccf\app_settings\AppSettingsPlugin.kt and D:\www\dating_touchme_app\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.LegacyFileExternalizer.save(IdToFileMap.kt:51) + at org.jetbrains.kotlin.incremental.storage.LegacyFileExternalizer.save(IdToFileMap.kt:48) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:443) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 25 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\app_settings-6.1.1\android\src\main\kotlin\com\spencerccf\app_settings\AppSettingsPlugin.kt and D:\www\dating_touchme_app\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:999) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:451) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.close(PersistentStorage.kt:124) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 25 more + Suppressed: java.lang.Exception: Could not close incremental caches in D:\www\dating_touchme_app\build\app_settings\kotlin\compileDebugKotlin\cacheable\caches-jvm\inputs: source-to-output.tab + ... 25 more + Suppressed: java.lang.IllegalArgumentException: this and base files have different roots: C:\Users\Administrator\AppData\Local\Pub\Cache\hosted\pub.flutter-io.cn\app_settings-6.1.1\android\src\main\kotlin\com\spencerccf\app_settings\AppSettingsPlugin.kt and D:\www\dating_touchme_app\android. + at kotlin.io.FilesKt__UtilsKt.toRelativeString(Utils.kt:117) + at kotlin.io.FilesKt__UtilsKt.relativeTo(Utils.kt:128) + at org.jetbrains.kotlin.incremental.storage.RelocatableFileToPathConverter.toPath(RelocatableFileToPathConverter.kt:24) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:50) + at org.jetbrains.kotlin.incremental.storage.FileDescriptor.getHashCode(FileToPathConverter.kt:30) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.hashKey(LinkedCustomHashMap.java:109) + at org.jetbrains.kotlin.com.intellij.util.containers.LinkedCustomHashMap.remove(LinkedCustomHashMap.java:153) + at org.jetbrains.kotlin.com.intellij.util.containers.SLRUMap.remove(SLRUMap.java:89) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.flushAppendCache(PersistentMapImpl.java:999) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.doPut(PersistentMapImpl.java:451) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.put(PersistentMapImpl.java:422) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.put(PersistentHashMap.java:105) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:80) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.applyChanges(InMemoryStorage.kt:108) + at org.jetbrains.kotlin.incremental.storage.AppendableInMemoryStorage.applyChanges(InMemoryStorage.kt:179) + at org.jetbrains.kotlin.incremental.storage.InMemoryStorage.close(InMemoryStorage.kt:136) + at org.jetbrains.kotlin.incremental.storage.AppendableSetBasicMap.close(BasicMap.kt:157) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner$close$1.invoke(BasicMapsOwner.kt:53) + at org.jetbrains.kotlin.incremental.storage.BasicMapsOwner.forEachMapSafe(BasicMapsOwner.kt:87) + ... 24 more + + diff --git a/pubspec.lock b/pubspec.lock index 65f7f97..0b91096 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" + app_settings: + dependency: "direct main" + description: + name: app_settings + sha256: "3e46c561441e5820d3a25339bf8b51b9e45a5f686873851a20c257a530917795" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.1" archive: dependency: transitive description: @@ -941,7 +949,7 @@ packages: source: hosted version: "2.2.0" package_info_plus: - dependency: transitive + dependency: "direct main" description: name: package_info_plus sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d