Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
clx_flutter_message
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
openSourceLibrary
clx_flutter_message
Commits
bd1bb7a4
提交
bd1bb7a4
authored
11月 04, 2025
作者:
史晓晨
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat:socket日志保存文件
上级
d665d252
显示空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
179 行增加
和
39 行删除
+179
-39
build.gradle
example/android/app/build.gradle
+1
-1
main.dart
example/lib/main.dart
+33
-37
message_config_impl.dart
example/lib/message/message_config_impl.dart
+14
-0
pubspec.yaml
example/pubspec.yaml
+1
-0
clx_flutter_message.dart
lib/clx_flutter_message.dart
+4
-0
socket_io.dart
lib/core/socket/socket_io.dart
+12
-1
log_utils.dart
lib/util/log_utils.dart
+111
-0
pubspec.yaml
pubspec.yaml
+3
-0
没有找到文件。
example/android/app/build.gradle
浏览文件 @
bd1bb7a4
...
...
@@ -45,7 +45,7 @@ android {
applicationId
"com.clx.clx_flutter_message_example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion
flutter
.
minSdkVersion
minSdkVersion
21
targetSdkVersion
flutter
.
targetSdkVersion
versionCode
flutterVersionCode
.
toInteger
()
versionName
flutterVersionName
...
...
example/lib/main.dart
浏览文件 @
bd1bb7a4
import
'package:clx_flutter_message/clx_flutter_message.dart'
;
import
'package:dio/dio.dart'
;
import
'package:flutter/material.dart'
;
import
'
dart:async
'
;
import
'
package:get/get.dart
'
;
import
'package:flutter/services.dart'
;
import
'package:clx_flutter_message/clx_flutter_message.dart'
;
import
'message/message_config_impl.dart'
;
void
main
(
)
{
runApp
(
const
MyApp
());
...
...
@@ -16,46 +17,41 @@ class MyApp extends StatefulWidget {
}
class
_MyAppState
extends
State
<
MyApp
>
{
String
_platformVersion
=
'Unknown'
;
final
_clxFlutterMessagePlugin
=
ClxFlutterMessage
();
@override
void
initState
()
{
super
.
initState
();
initPlatformState
();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future
<
void
>
initPlatformState
()
async
{
String
platformVersion
;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try
{
platformVersion
=
await
_clxFlutterMessagePlugin
.
getPlatformVersion
()
??
'Unknown platform version'
;
}
on
PlatformException
{
platformVersion
=
'Failed to get platform version.'
;
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if
(!
mounted
)
return
;
setState
(()
{
_platformVersion
=
platformVersion
;
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
MaterialApp
(
return
Get
MaterialApp
(
home:
Scaffold
(
appBar:
AppBar
(
title:
const
Text
(
'Plugin example app'
),
),
body:
Center
(
child:
Text
(
'Running on:
$_platformVersion
\n
'
),
body:
SingleChildScrollView
(
child:
Column
(
children:
[
TextButton
(
onPressed:
()
{
// 初始化消息插件配置
messageConfig
..
accessToken
=
"e2914fd5543142db87185db50f072c2d"
..
productCode
=
"carrier-driver-app"
..
userKey
=
"1021191558918987845"
..
webSocketUrl
=
"ws://gateway.testclx.cn/common-socket-endpoint/common"
..
inAppAccessKey
=
"CARRIER_INTERNAL_MESSAGE_APP"
..
functionKey
=
"default"
..
dio
=
Dio
()
..
messageManagement
=
MessageConfigImpl
();
messageConfig
.
messageManagement
?.
refreshMessage
(
context
);
},
child:
Text
(
"链接"
),
),
TextButton
(
onPressed:
()
{
messageConfig
.
messageManagement
?.
close
();
},
child:
Text
(
"断开连接"
),
),
],
),
),
),
);
...
...
example/lib/message/message_config_impl.dart
0 → 100644
浏览文件 @
bd1bb7a4
import
'package:clx_flutter_message/clx_flutter_message.dart'
;
class
MessageConfigImpl
extends
BaseMessageConfig
{
@override
void
handleMessage
(
data
)
{
print
(
"MessageConfigImpl handleMessage:
$data
"
);
}
@override
Future
?
onJumpToMessagePage
(
String
page
,
arguments
)
{
print
(
"MessageConfigImpl onJumpToMessagePage:
$page
$arguments
"
);
return
null
;
}
}
example/pubspec.yaml
浏览文件 @
bd1bb7a4
...
...
@@ -28,6 +28,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons
:
^1.0.2
dio
:
^5.7.0
dev_dependencies
:
integration_test
:
...
...
lib/clx_flutter_message.dart
浏览文件 @
bd1bb7a4
import
'package:clx_flutter_message/util/string_util.dart'
;
import
'package:clx_flutter_message/util/toast_util.dart'
;
import
'package:flutter/material.dart'
;
import
'clx_flutter_message_platform_interface.dart'
;
import
'common/constant.dart'
;
import
'core/api/message_net.dart'
;
...
...
@@ -11,6 +12,8 @@ import 'core/notice/notice_manager.dart';
import
'core/notification/notification_layout/notification_layout_widget.dart'
;
import
'core/notification/notification_manager.dart'
;
import
'core/socket/socket_io.dart'
;
import
'util/log_utils.dart'
;
export
'core/model/message_config.dart'
;
export
'core/model/message_data.dart'
;
export
'core/notice/notice_dialog_widget.dart'
;
...
...
@@ -124,6 +127,7 @@ abstract class BaseMessageConfig
BaseMessageConfig
()
{
notificationLayoutController
=
NotificationLayoutController
();
noticeDialogWidgetController
=
NoticeDialogWidgetController
();
LogUtil
.
instance
.
init
();
}
// 刷新消息、获取未处理消息,重新连接websocket
...
...
lib/core/socket/socket_io.dart
浏览文件 @
bd1bb7a4
...
...
@@ -2,7 +2,9 @@ import 'dart:async';
import
'dart:developer'
;
import
'dart:io'
;
import
'package:clx_flutter_message/util/log_utils.dart'
;
import
'package:web_socket_channel/io.dart'
;
import
'socket_message.dart'
;
typedef
MessageCallBack
=
void
Function
(
dynamic
message
);
...
...
@@ -10,10 +12,13 @@ typedef MessageCallBack = void Function(dynamic message);
class
Socket
{
// io通道
IOWebSocketChannel
?
channel
;
// 接受的消息体
SocketMessageBody
?
_lastMessage
;
// 心跳包定时器
Timer
?
heartbeatTimer
;
// 心跳包发送间隔
Duration
heartbeatInterval
=
const
Duration
(
seconds:
15
);
// 心跳包发送间隔
// 私有构造函数
...
...
@@ -62,6 +67,8 @@ class Socket {
channel
?.
stream
.
listen
(
(
message
)
{
log
(
"connectId:
${params['connectId']}
Received message:
$message
"
);
LogUtil
.
instance
.
log
(
"connectId:
${params['connectId']}
Received message:
$message
"
);
if
(
message
is
String
)
{
if
(
message
==
''
)
{
_lastMessage
=
null
;
...
...
@@ -76,21 +83,25 @@ class Socket {
},
onError:
(
error
)
{
log
(
"WebSocket Error:
$error
"
);
LogUtil
.
instance
.
log
(
"WebSocket Error:
$error
"
);
},
onDone:
()
{
log
(
"WebSocket connection closed"
);
LogUtil
.
instance
.
log
(
"WebSocket connection closed
$_lastMessage
"
);
if
(
_lastMessage
?.
type
==
2
)
{
/// 服务器主动断开连接、如果可以重连
if
(
_lastMessage
?.
content
?[
'canReconnect'
]
==
1
)
{
reconnectWebSocket
();
LogUtil
.
instance
.
log
(
"WebSocket connection reconnectWebSocket"
);
}
else
{
_clean
();
LogUtil
.
instance
.
log
(
"WebSocket connection _clean"
);
}
return
;
}
else
{
if
(
heartbeatTimer
!=
null
)
{
reconnectWebSocket
();
LogUtil
.
instance
.
log
(
"WebSocket connection reconnectWebSocket"
);
}
}
},
...
...
lib/util/log_utils.dart
0 → 100644
浏览文件 @
bd1bb7a4
import
'dart:async'
;
import
'dart:io'
;
import
'package:intl/intl.dart'
;
import
'package:path_provider/path_provider.dart'
;
/// 日志级别
enum
LogLevel
{
debug
,
info
,
warning
,
error
}
class
LogUtil
{
static
LogUtil
?
_instance
;
late
String
_logDir
;
// 日志文件存储目录
final
int
_maxRetentionDays
=
7
;
// 日志保留天数(超过自动删除)
LogUtil
.
_
();
static
LogUtil
get
instance
{
_instance
??=
LogUtil
.
_
();
return
_instance
!;
}
/// 初始化日志工具(必须在APP启动时调用)
Future
<
void
>
init
()
async
{
// 获取应用文档目录(iOS/Android 私有目录,无需额外权限)
Directory
appDocDir
=
await
getApplicationDocumentsDirectory
();
_logDir
=
"
${appDocDir.path}
/logs"
;
// 创建日志目录(若不存在)
await
Directory
(
_logDir
).
create
(
recursive:
true
);
// 清理过期日志
_cleanExpiredLogs
();
}
/// 写入日志(公共方法,支持不同级别)
Future
<
void
>
log
(
String
message
,
{
LogLevel
level
=
LogLevel
.
debug
,
String
?
tag
,
// 日志标签(如页面/功能名)
})
async
{
if
(
_logDir
.
isEmpty
)
{
throw
Exception
(
"LogUtil 未初始化,请先调用 init()"
);
}
// 1. 格式化日志内容(时间 + 级别 + 标签 + 消息)
String
time
=
DateFormat
(
"yyyy-MM-dd HH:mm:ss.SSS"
).
format
(
DateTime
.
now
());
String
levelStr
=
_levelToString
(
level
);
String
logContent
=
"[
$time
] [
$levelStr
]
${tag != null ? "[$tag] " : ""}$message
\n
"
;
// 2. 获取当前日志文件(按天划分,如 2023-10-01.log)
String
fileName
=
"
${DateFormat("yyyy-MM-dd").format(DateTime.now())}
.log"
;
File
logFile
=
File
(
"
$_logDir
/
$fileName
"
);
// 3. 追加写入日志(异步操作,避免阻塞UI)
await
logFile
.
writeAsString
(
logContent
,
mode:
FileMode
.
append
,
flush:
true
);
}
/// 辅助方法:日志级别转字符串
String
_levelToString
(
LogLevel
level
)
{
switch
(
level
)
{
case
LogLevel
.
debug
:
return
"DEBUG"
;
case
LogLevel
.
info
:
return
"INFO"
;
case
LogLevel
.
warning
:
return
"WARNING"
;
case
LogLevel
.
error
:
return
"ERROR"
;
}
}
/// 清理过期日志(保留最近 N 天)
Future
<
void
>
_cleanExpiredLogs
()
async
{
final
now
=
DateTime
.
now
();
final
dir
=
Directory
(
_logDir
);
if
(!
await
dir
.
exists
())
return
;
// 遍历目录下所有日志文件
await
for
(
var
entity
in
dir
.
list
())
{
if
(
entity
is
File
&&
entity
.
path
.
endsWith
(
".log"
))
{
// 解析文件名中的日期(如 2023-10-01.log → 2023-10-01)
String
fileName
=
entity
.
path
.
split
(
"/"
).
last
.
replaceAll
(
".log"
,
""
);
try
{
DateTime
logDate
=
DateFormat
(
"yyyy-MM-dd"
).
parse
(
fileName
);
// 计算与当前日期的差值
int
daysDiff
=
now
.
difference
(
logDate
).
inDays
;
if
(
daysDiff
>
_maxRetentionDays
)
{
await
entity
.
delete
();
// 删除过期文件
}
}
catch
(
e
)
{
// 文件名格式错误,跳过
}
}
}
}
/// 获取所有日志文件路径(用于上传等场景)
/// Android 路径示例:/data/data/包名/app_flutter/logs/2023-10-01.log
/// iOS 路径示例:/Users/用户名/Library/Developer/CoreSimulator/Devices/.../data/Containers/Data/Application/.../Documents/logs/2023-10-01.log
Future
<
List
<
String
>>
getLogFilePaths
()
async
{
final
dir
=
Directory
(
_logDir
);
if
(!
await
dir
.
exists
())
return
[];
List
<
String
>
paths
=
[];
await
for
(
var
entity
in
dir
.
list
())
{
if
(
entity
is
File
&&
entity
.
path
.
endsWith
(
".log"
))
{
paths
.
add
(
entity
.
path
);
}
}
return
paths
;
}
}
\ No newline at end of file
pubspec.yaml
浏览文件 @
bd1bb7a4
...
...
@@ -18,6 +18,9 @@ dependencies:
cached_network_image
:
^3.3.0
fluttertoast
:
8.2.4
get
:
^4.6.6
path_provider
:
^2.0.15
# 获取文件路径
intl
:
^0.18.1
# 时间格式化
dev_dependencies
:
flutter_test
:
sdk
:
flutter
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论