Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
ethan
/
appframe
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit 2847354b
authored
2025-12-23 15:22:45 +0800
by
tanghuan
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
IM消息推送的需求,部分调整
1 parent
36914fc1
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
179 additions
and
36 deletions
lib/bloc/login_main_cubit.dart
lib/bloc/login_phone_cubit.dart
lib/bloc/login_qr_cubit.dart
lib/bloc/web_cubit.dart
lib/config/constant.dart
lib/services/im_service.dart
lib/ui/pages/web_page.dart
lib/bloc/login_main_cubit.dart
View file @
2847354
import
'package:appframe/config/constant.dart'
;
import
'package:appframe/config/locator.dart'
;
import
'package:appframe/config/routes.dart'
;
import
'package:appframe/data/repositories/wechat_auth_repository.dart'
;
import
'package:equatable/equatable.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:fluwx/fluwx.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
...
...
@@ -131,14 +133,25 @@ class LoginMainCubit extends Cubit<LoginMainState> {
var
userType
=
0
;
var
stuId
=
''
;
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
if
(
roles
.
isNotEmpty
)
{
var
role
=
roles
[
0
];
classCode
=
role
[
'classCode'
];
userType
=
role
[
'userType'
];
stuId
=
role
[
'stuId'
];
// 将角色中的班级数据处理后,进行缓存
List
<
String
>
classIdList
=
[];
for
(
var
role
in
roles
)
{
classIdList
.
add
(
role
[
'classCode'
]
as
String
);
}
debugPrint
(
'classCodeIds:--------------
$classIdList
'
);
sharedPreferences
.
setStringList
(
Constant
.
classIdSetKey
,
classIdList
);
}
else
{
sharedPreferences
.
setStringList
(
Constant
.
classIdSetKey
,
[]);
}
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
var
preUserCode
=
sharedPreferences
.
getString
(
'pre_userCode'
)
??
''
;
if
(
userCode
!=
preUserCode
)
{
// 新用户登录
...
...
lib/bloc/login_phone_cubit.dart
View file @
2847354
import
'dart:async'
;
import
'package:appframe/config/constant.dart'
;
import
'package:appframe/config/locator.dart'
;
import
'package:appframe/config/routes.dart'
;
import
'package:appframe/data/repositories/phone_auth_repository.dart'
;
...
...
@@ -163,14 +164,25 @@ class LoginPhoneCubit extends Cubit<LoginPhoneState> {
var
userType
=
0
;
var
stuId
=
''
;
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
if
(
roles
.
isNotEmpty
)
{
var
role
=
roles
[
0
];
classCode
=
role
[
'classCode'
];
userType
=
role
[
'userType'
];
stuId
=
role
[
'stuId'
];
// 将角色中的班级数据处理后,进行缓存
List
<
String
>
classIdList
=
[];
for
(
var
role
in
roles
)
{
classIdList
.
add
(
role
[
'classCode'
]
as
String
);
}
debugPrint
(
'classCodeIds:--------------
$classIdList
'
);
sharedPreferences
.
setStringList
(
Constant
.
classIdSetKey
,
classIdList
);
}
else
{
sharedPreferences
.
setStringList
(
Constant
.
classIdSetKey
,
[]);
}
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
var
preUserCode
=
sharedPreferences
.
getString
(
'pre_userCode'
)
??
''
;
if
(
userCode
!=
preUserCode
)
{
// 新用户登录
...
...
@@ -186,7 +198,7 @@ class LoginPhoneCubit extends Cubit<LoginPhoneState> {
if
(
preClassCode
!=
''
&&
roles
.
any
((
element
)
=>
element
[
'classCode'
]
==
preClassCode
&&
element
[
'classCode'
]
==
preClassCode
&&
element
[
'userType'
]
==
preUserType
&&
element
[
'stuId'
]
==
preStuId
))
{
classCode
=
preClassCode
;
...
...
lib/bloc/login_qr_cubit.dart
View file @
2847354
...
...
@@ -7,6 +7,7 @@ import 'package:appframe/config/routes.dart';
import
'package:appframe/data/repositories/wechat_auth_repository.dart'
;
import
'package:crypto/crypto.dart'
;
import
'package:equatable/equatable.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:fluwx/fluwx.dart'
;
import
'package:shared_preferences/shared_preferences.dart'
;
...
...
@@ -173,14 +174,25 @@ class LoginQrCubit extends Cubit<LoginQrState> {
var
userType
=
0
;
var
stuId
=
''
;
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
if
(
roles
.
isNotEmpty
)
{
var
role
=
roles
[
0
];
classCode
=
role
[
'classCode'
];
userType
=
role
[
'userType'
];
stuId
=
role
[
'stuId'
];
// 将角色中的班级数据处理后,进行缓存
List
<
String
>
classIdList
=
[];
for
(
var
role
in
roles
)
{
classIdList
.
add
(
role
[
'classCode'
]
as
String
);
}
debugPrint
(
'classCodeIds:--------------
$classIdList
'
);
sharedPreferences
.
setStringList
(
Constant
.
classIdSetKey
,
classIdList
);
}
else
{
sharedPreferences
.
setStringList
(
Constant
.
classIdSetKey
,
[]);
}
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
var
preUserCode
=
sharedPreferences
.
getString
(
'pre_userCode'
)
??
''
;
if
(
userCode
!=
preUserCode
)
{
// 新用户登录
...
...
lib/bloc/web_cubit.dart
View file @
2847354
...
...
@@ -39,6 +39,10 @@ class WebState extends Equatable {
final
String
opIcon
;
final
bool
showBottomNavBar
;
// 是否通过登录操作进入
// 用来控制是否需要判断处理加群、退群等逻辑
final
bool
loginOpFlag
;
final
String
?
sessionCode
;
final
String
?
userCode
;
final
String
?
classCode
;
...
...
@@ -61,6 +65,10 @@ class WebState extends Equatable {
final
bool
chooseVideoCmdFlag
;
final
String
chooseVideoCmdMessage
;
/// 提示信息
final
bool
showSnackBar
;
final
String
snackBarMsg
;
final
String
h5Version
;
/// 用于测试监测问题
...
...
@@ -76,6 +84,7 @@ class WebState extends Equatable {
this
.
bgColor
=
0xFF7691FA
,
this
.
opIcon
=
'none'
,
this
.
showBottomNavBar
=
false
,
this
.
loginOpFlag
=
false
,
this
.
sessionCode
,
this
.
userCode
,
this
.
classCode
,
...
...
@@ -89,6 +98,8 @@ class WebState extends Equatable {
this
.
chooseImageCmdMessage
=
''
,
this
.
chooseVideoCmdFlag
=
false
,
this
.
chooseVideoCmdMessage
=
''
,
this
.
showSnackBar
=
false
,
this
.
snackBarMsg
=
''
,
this
.
h5Version
=
''
,
this
.
testMsg
=
''
,
});
...
...
@@ -104,6 +115,7 @@ class WebState extends Equatable {
String
?
opIcon
,
bool
?
showNavBar
,
bool
?
showBottomNavBar
,
bool
?
loginOpFlag
,
String
?
sessionCode
,
String
?
userCode
,
String
?
classCode
,
...
...
@@ -117,6 +129,8 @@ class WebState extends Equatable {
String
?
chooseImageCmdMessage
,
bool
?
chooseVideoCmdFlag
,
String
?
chooseVideoCmdMessage
,
bool
?
showSnackBar
,
String
?
snackBarMsg
,
String
?
h5Version
,
String
?
testMsg
,
})
{
...
...
@@ -130,6 +144,7 @@ class WebState extends Equatable {
bgColor:
bgColor
??
this
.
bgColor
,
opIcon:
opIcon
??
this
.
opIcon
,
showBottomNavBar:
showBottomNavBar
??
this
.
showBottomNavBar
,
loginOpFlag:
loginOpFlag
??
this
.
loginOpFlag
,
sessionCode:
sessionCode
??
this
.
sessionCode
,
userCode:
userCode
??
this
.
userCode
,
classCode:
classCode
??
this
.
classCode
,
...
...
@@ -143,6 +158,8 @@ class WebState extends Equatable {
chooseImageCmdMessage:
chooseImageCmdMessage
??
this
.
chooseImageCmdMessage
,
chooseVideoCmdFlag:
chooseVideoCmdFlag
??
this
.
chooseVideoCmdFlag
,
chooseVideoCmdMessage:
chooseVideoCmdMessage
??
this
.
chooseVideoCmdMessage
,
showSnackBar:
showSnackBar
??
this
.
showSnackBar
,
snackBarMsg:
snackBarMsg
??
this
.
snackBarMsg
,
h5Version:
h5Version
??
this
.
h5Version
,
testMsg:
testMsg
??
this
.
testMsg
,
);
...
...
@@ -172,6 +189,8 @@ class WebState extends Equatable {
chooseImageCmdMessage
,
chooseVideoCmdFlag
,
chooseVideoCmdMessage
,
showSnackBar
,
snackBarMsg
,
h5Version
,
testMsg
,
];
...
...
@@ -382,12 +401,62 @@ class WebCubit extends Cubit<WebState> with WidgetsBindingObserver {
var
imService
=
getIt
.
get
<
ImService
>();
var
loginResult
=
await
imService
.
login
(
state
.
userCode
!);
if
(
loginResult
)
{
print
(
"缓存自动登录处,IM 登录成功"
);
await
imService
.
registerPush
();
debugPrint
(
"缓存自动登录处,IM 登录成功"
);
// 注册推送服务
imService
.
registerPush
();
//
if
(
state
.
loginOpFlag
)
{
_getPendingGroup
();
}
}
else
{
print
(
"缓存自动登录处,IM 登录失败"
);
debugPrint
(
"缓存自动登录处,IM 登录失败"
);
}
}
}
///
/// 获取待加群和待退群
///
Future
<
Map
<
String
,
List
<
String
>>>
_getPendingGroup
()
async
{
var
classIds
=
getIt
.
get
<
SharedPreferences
>().
getStringList
(
Constant
.
classIdSetKey
);
List
<
String
>
classIdList
=
[];
if
(
classIds
!=
null
)
{
// 转换和去重
classIdList
=
Set
<
String
>.
from
(
classIds
).
toList
();
}
var
unjoinedGroupIdList
=
<
String
>[];
var
leaveGroupIdList
=
<
String
>[];
Map
<
String
,
List
<
String
>>
result
=
{
'unjoinedGroupIdList'
:
unjoinedGroupIdList
,
'leaveGroupIdList'
:
leaveGroupIdList
,
};
var
imService
=
getIt
.
get
<
ImService
>();
var
joinedGroupIdList
=
await
imService
.
getJoinedGroupList
();
// 获取群组列表失败,joinedGroupIdList=null
if
(
joinedGroupIdList
==
null
)
{
return
result
;
}
// 需要加群
for
(
var
classId
in
classIdList
)
{
if
(!
joinedGroupIdList
.
contains
(
classId
))
{
unjoinedGroupIdList
.
add
(
classId
);
}
}
// 需要退群
for
(
var
joinedGroupId
in
joinedGroupIdList
)
{
if
(!
classIdList
.
contains
(
joinedGroupId
))
{
leaveGroupIdList
.
add
(
joinedGroupId
);
}
}
debugPrint
(
'待加群:
$unjoinedGroupIdList
'
);
debugPrint
(
'待退群:
$leaveGroupIdList
'
);
return
result
;
}
void
_onMessageReceived
(
JavaScriptMessage
message
)
async
{
...
...
lib/config/constant.dart
View file @
2847354
...
...
@@ -93,6 +93,11 @@ class Constant {
?
'kM4yqbehB3io9UiLvH6eHvM7xAhfYxoyyaO1tLoHgKltcaI7MZXkUbpFaWdeQIqe'
:
'GkMkhAnrCThYrZxApCBdFidcAC8USwVnhoqMGzqmSvmcegRCvETtDR2Te9btarnG'
;
/// Key
/// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
static
const
String
classIdSetKey
=
'auth_class_ids'
;
/// 测试阶段使用
static
const
bool
needIM
=
false
;
static
const
bool
needUpgrade
=
true
;
...
...
lib/services/im_service.dart
View file @
2847354
...
...
@@ -11,6 +11,7 @@ import 'package:tencent_cloud_chat_sdk/enum/log_level_enum.dart';
import
'package:tencent_cloud_chat_sdk/enum/login_status.dart'
;
import
'package:tencent_cloud_chat_sdk/enum/message_elem_type.dart'
;
import
'package:tencent_cloud_chat_sdk/models/v2_tim_callback.dart'
;
import
'package:tencent_cloud_chat_sdk/models/v2_tim_group_info.dart'
;
import
'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart'
;
import
'package:tencent_cloud_chat_sdk/models/v2_tim_message_receipt.dart'
;
import
'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart'
;
...
...
@@ -20,7 +21,7 @@ import 'package:tencent_cloud_chat_sdk/tencent_im_sdk_plugin.dart';
class
ImService
{
// sdkListener 事件监听器
V2TimSDKListener
sdkListener
=
V2TimSDKListener
(
final
V2TimSDKListener
_
sdkListener
=
V2TimSDKListener
(
onConnectFailed:
(
int
code
,
String
error
)
{
// 连接失败的回调函数
// code 错误码
...
...
@@ -41,6 +42,7 @@ class ImService {
},
onUserSigExpired:
()
{
// 在线时票据过期:此时您需要生成新的 userSig 并再次调用 V2TIMManager 的 login() 函数重新登录。
// 如果收到 onUserSigExpired 回调,说明您登录用的 UserSig 票据已经过期,请使用新签发的 UserSig 进行重新登录。如果继续使用过期的 UserSig,会导致 IM SDK 登录进入死循环。
},
onUserStatusChanged:
(
List
<
V2TimUserStatus
>
userStatusList
)
{
//用户状态变更通知
...
...
@@ -78,10 +80,9 @@ class ImService {
// message.textElem?.text;
// 时间戳转换
// DateTime timestamp = DateTime.fromMillisecondsSinceEpoch(message.timestamp! * 1000);
// String formattedTime = DateFormat('yyyy-MM-dd HH:mm:ss').format(timestamp);
//
// print("收到IM消息—— 发送时间:$formattedTime 发送者:${message.sender} 内容:${message.textElem?.text}");
DateTime
dt
=
DateTime
.
fromMillisecondsSinceEpoch
(
message
.
timestamp
!
*
1000
);
print
(
"收到IM消息—— 时间:
${dt.year}
-
${dt.month}
-
${dt.day}
${dt.hour}
:
${dt.minute}
:
${dt.second}
发送者:
${message.sender}
内容:
${message.textElem?.text}
"
);
// 目前只会有文本消息,所以其他消息类型暂不处理,直接return
return
;
...
...
@@ -184,22 +185,22 @@ class ImService {
V2TimAdvancedMsgListener
get
msgListener
=>
_msgListener
;
///
/// 初始化 IM SDK
///
Future
<
bool
>
initSdk
()
async
{
// 初始化SDK
var
initSDKRes
=
await
TencentImSDKPlugin
.
v2TIMManager
.
initSDK
(
sdkAppID:
Constant
.
imSdkAppId
,
loglevel:
LogLevelEnum
.
V2TIM_LOG_ALL
,
listener:
sdkListener
,
listener:
_
sdkListener
,
);
if
(
initSDKRes
.
code
==
0
)
{
print
(
"IM
初始化成功--------
"
);
print
(
"IM
SDK 初始化成功--------
${initSDKRes.data}
"
);
return
true
;
}
else
{
print
(
"IM初始化失败--------"
);
/// 失败后的处理,
print
(
"IM SDK 初始化失败--------
${initSDKRes.data}
"
);
return
false
;
}
}
...
...
@@ -224,10 +225,13 @@ class ImService {
Future
<
bool
>
login
(
String
userID
)
async
{
// 登录前先判断登录状态
var
loginStatus
=
await
TencentImSDKPlugin
.
v2TIMManager
.
getLoginStatus
();
print
(
'IM 登录状态:
${loginStatus.code}
'
);
if
(
loginStatus
.
code
==
LoginStatus
.
V2TIM_STATUS_LOGINED
)
{
// 已经登录,不需要再次登录
return
true
;
if
(
loginStatus
.
code
==
0
)
{
debugPrint
(
'登录前检测 IM 登录状态:
${loginStatus.data}
'
);
if
(
loginStatus
.
data
==
LoginStatus
.
V2TIM_STATUS_LOGINED
)
{
// 已经登录,不需要再次登录
debugPrint
(
'IM 已经登录,不需要再次登录'
);
return
true
;
}
}
final
apiService
=
getIt
.
get
<
ApiService
>(
instanceName:
"appApiService"
);
...
...
@@ -240,13 +244,17 @@ class ImService {
V2TimCallback
res
=
await
TencentImSDKPlugin
.
v2TIMManager
.
login
(
userID:
userID
,
userSig:
userSig
);
loginStatus
=
await
TencentImSDKPlugin
.
v2TIMManager
.
getLoginStatus
();
print
(
'IM 登录状态
2:
${loginStatus.code
}
'
);
print
(
'IM 登录状态
:
${loginStatus.data
}
'
);
if
(
res
.
code
==
0
)
{
print
(
"IM 登录成功--------"
);
// 添加消息的事件监听器
// await TencentImSDKPlugin.v2TIMManager.getMessageManager().addAdvancedMsgListener(listener: msgListener);
await
addMsgListener
(
_msgListener
);
var
loginUserResp
=
await
TencentImSDKPlugin
.
v2TIMManager
.
getLoginUser
();
print
(
"当前登录用户:
${loginUserResp.data}
"
);
return
true
;
}
else
{
// 登录失败逻辑
...
...
@@ -255,7 +263,9 @@ class ImService {
}
}
///
/// 登出
/// 一般不需要使用,IM与App生命周期一致即可
///
Future
<
bool
>
logout
()
async
{
var
logoutRes
=
await
TencentImSDKPlugin
.
v2TIMManager
.
logout
();
...
...
@@ -268,6 +278,18 @@ class ImService {
}
}
Future
<
List
<
String
>?>
getJoinedGroupList
()
async
{
var
groupListRes
=
await
TencentImSDKPlugin
.
v2TIMManager
.
getGroupManager
().
getJoinedGroupList
();
if
(
groupListRes
.
code
==
0
)
{
debugPrint
(
"获取群列表成功--------"
);
List
<
V2TimGroupInfo
>?
groupList
=
groupListRes
.
data
;
return
groupList
?.
map
((
ele
)
=>
ele
.
groupID
).
toList
();
}
else
{
debugPrint
(
'获取群列表失败 Res.code =
${groupListRes.code}
'
);
return
null
;
}
}
void
_onNotificationClicked
({
required
String
ext
,
String
?
userID
,
String
?
groupID
})
{
print
(
"收到推送消息--------"
);
print
(
"_onNotificationClicked:
$ext
, userID:
$userID
, groupID:
$groupID
"
);
...
...
@@ -309,19 +331,19 @@ class ImService {
///
TencentCloudChatPush
().
addPushListener
(
listener:
timPushListener
);
//
var getIdRes = await TencentCloudChatPush().getRegistrationID();
//
if (getIdRes.code == 0) {
//
print('getRegistrationID: ${getIdRes.data}');
//
} else {
//
print('getRegistrationID: ${getIdRes.errorMessage}');
//
}
//
//
var tokenRes = await TencentCloudChatPush().getAndroidPushToken();
//
if (tokenRes.code == 0) {
//
print('android Token: ${tokenRes.data}');
//
} else {
//
print('android Token: ${tokenRes.errorMessage}');
//
}
var
getIdRes
=
await
TencentCloudChatPush
().
getRegistrationID
();
if
(
getIdRes
.
code
==
0
)
{
print
(
'getRegistrationID:
${getIdRes.data}
'
);
}
else
{
print
(
'getRegistrationID:
${getIdRes.errorMessage}
'
);
}
var
tokenRes
=
await
TencentCloudChatPush
().
getAndroidPushToken
();
if
(
tokenRes
.
code
==
0
)
{
print
(
'android Token:
${tokenRes.data}
'
);
}
else
{
print
(
'android Token:
${tokenRes.errorMessage}
'
);
}
}
else
{
print
(
'注册推送失败--------'
);
print
(
'
${res.errorMessage}
'
);
...
...
lib/ui/pages/web_page.dart
View file @
2847354
...
...
@@ -3,6 +3,9 @@ import 'package:appframe/config/constant.dart';
import
'package:appframe/config/env_config.dart'
;
import
'package:appframe/config/locator.dart'
;
import
'package:appframe/config/routes.dart'
;
import
'package:appframe/ui/widgets/tip_overlay_widget.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:go_router/go_router.dart'
;
...
...
@@ -16,6 +19,8 @@ class WebPage extends StatelessWidget {
Widget
build
(
BuildContext
buildContext
)
{
final
Map
<
String
,
dynamic
>?
extraData
=
GoRouterState
.
of
(
buildContext
).
extra
as
Map
<
String
,
dynamic
>?;
var
loginOpFlag
=
true
;
var
sessionCode
=
extraData
?[
'sessionCode'
];
var
userCode
=
extraData
?[
'userCode'
];
var
classCode
=
extraData
?[
'classCode'
];
...
...
@@ -23,6 +28,8 @@ class WebPage extends StatelessWidget {
var
stuId
=
extraData
?[
'stuId'
];
if
(
sessionCode
==
null
||
sessionCode
==
''
)
{
loginOpFlag
=
false
;
var
sharedPreferences
=
getIt
.
get
<
SharedPreferences
>();
sessionCode
=
sharedPreferences
.
getString
(
'auth_sessionCode'
);
userCode
=
sharedPreferences
.
getString
(
'auth_userCode'
);
...
...
@@ -34,6 +41,7 @@ class WebPage extends StatelessWidget {
return
BlocProvider
(
create:
(
context
)
=>
WebCubit
(
WebState
(
loginOpFlag:
loginOpFlag
,
sessionCode:
sessionCode
,
userCode:
userCode
,
classCode:
classCode
,
...
...
@@ -130,6 +138,8 @@ class WebPage extends StatelessWidget {
context
.
read
<
WebCubit
>().
chooseImage
(
context
);
}
else
if
(
state
.
chooseVideoCmdFlag
)
{
context
.
read
<
WebCubit
>().
chooseVideo
(
context
);
}
else
if
(
state
.
showSnackBar
)
{
TipOverlayUtil
.
showTip
(
context
,
state
.
snackBarMsg
);
}
},
),
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment