linkv_rtc_im 0.3.17 linkv_rtc_im: ^0.3.17 copied to clipboard
linkv_rtc_im Audio/Video/IM Flutter SDK is a flutter plugin wrapper based on LinkV LVIMSDK native Android/iOS SDK
import 'dart:math';
import 'package:common_utils/common_utils.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:linkv_rtc_im/linkv_api_defines.dart';
import 'dart:async';
import 'package:linkv_rtc_im/rtm_flutter_plugin.dart';
import 'package:rtm_flutter_plugin_example/live_page.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'im_media_msg_page.dart';
import 'linkv_ui.dart';
import 'package:linkv_rtc_im/linkv_error_code.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:linkv_rtc_im/linkv_rtm_callback.dart';
import 'help.dart';
import 'package:linkv_rtc_im/bean/lv_im_msg.dart';
void main() => runApp(MyApp());
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
print("wing myBackgroundMessageHandler:");
if (message.containsKey('data')) {
// Handle data message
final dynamic data = message['data'];
print("wing data: $data");
}
if (message.containsKey('notification')) {
// Handle notification message
final dynamic notification = message['notification'];
print("wing notification: $notification");
}
// Or do other work.
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
debugShowCheckedModeBanner: false,
home: MainView(),
);
}
}
class MainView extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MainView> implements LVIMEventCallback {
final _roomIdFieldController = TextEditingController();
final _msgInputTextEdit = TextEditingController();
final _msgTargetIdTextEdit = TextEditingController();
final _msgListTextEdit = TextEditingController();
bool _isSDKInit = false;
String _version;
String userId;
var TAG = "main [Wing] ";
bool isTokenRequesting = false;
bool isIMAuthed = false;
@override
void initState() {
super.initState();
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
_msgTargetIdTextEdit.text = '1496';
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("wing onMessage: $message");
},
onBackgroundMessage: myBackgroundMessageHandler,
onLaunch: (Map<String, dynamic> message) async {
print("wing onLaunch: $message");
},
onResume: (Map<String, dynamic> message) async {
print("wing onResume: $message");
},
);
initSDK();
RtmFlutterPlugin.getSdkVersion().then((value) => {
this.setState(() {
_version = value;
})
});
RtmFlutterPlugin.setIMEventCallback(this);
_roomIdFieldController.text = "1352";
getUid().then((value) {
userId = value;
print("D/Wing own userId = " + userId);
RtmFlutterPlugin.loginUser(userId, LVIMEnumDefine.LVIM_LOGIN_TYPE_AUTO)
.then((value) {
print(value);
String loginResult = "";
if (value == 0) {
loginResult = "登录成功";
_firebaseMessaging.getToken().then((token) {
if(!ObjectUtil.isEmptyString(token)){
print("wing token = " + token);
RtmFlutterPlugin.uploadPushToken(token).then((value) {
print("wing uploadPushToken " + value.eCode.toString());
});
}
});
} else {
loginResult = "登录失败 code : " + value.toString();
}
Fluttertoast.showToast(
msg: loginResult,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER);
});
});
}
@override
void dispose() {
RtmFlutterPlugin.unInitImSDK();
super.dispose();
}
Future<String> getUid() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String uid = prefs.getString("uid");
if (uid == null || uid.length == 0) {
uid = Random().nextInt(10000).toString();
prefs.setString("uid", uid);
}
return uid;
}
void initSDK() {
RtmFlutterPlugin.initImSDK(APP_ID_LIVE, APP_SECRET_LIVE, false)
.then((result) {
print('initSDK result:$result');
if (result == LVErrorCode.SUCCESS) {
_isSDKInit = true;
}
});
RtmFlutterPlugin.setLogOpen(true);
}
void onClickHistoryMsg() async {
String tid = _msgTargetIdTextEdit.text;
List<LVIMMsg> list =
await RtmFlutterPlugin.queryLocalPrivateHistoryMessage(tid, 0, 20);
if (list == null || list.length == 0) {
print("$TAG onClickHistoryMsg null");
return;
}
print(
"$TAG onClickHistoryMsg count = ${list.length} last dbid = ${list.first.dbid} send_State = ${list.first.sendState}");
}
void sendEventMsg() {
int timestamp = (DateTime.now().millisecondsSinceEpoch / 1000).round();
RtmFlutterPlugin.sendMessageHasRead(_msgTargetIdTextEdit.text, timestamp)
.then((lvimMsg) {
print(
'[Wing] sendEventMsg end result = ${lvimMsg.eCode}, dbid = ${lvimMsg.msg.cmdType}, sendState = ${lvimMsg.msg.sendState} stime = ${lvimMsg.msg.stime}');
if (lvimMsg.eCode == 0) {
Fluttertoast.showToast(msg: "Send Msg Success");
} else {
Fluttertoast.showToast(msg: "Send Msg Failed code:${lvimMsg.eCode}");
}
});
// RtmFlutterPlugin.sendEventMessage(_msgTargetIdTextEdit.text, "flag_event_notify", _msgInputTextEdit.text).then((lvimMsg) {
// print('[Wing] sendEventMsg end result = ${lvimMsg.eCode}, dbid = ${lvimMsg.msg.cmdType}, sendState = ${lvimMsg.msg.sendState} stime = ${lvimMsg.msg.stime}');
// if (lvimMsg.eCode == 0) {
// Fluttertoast.showToast(msg: "Send Msg Success");
// } else {
// Fluttertoast.showToast(msg: "Send Msg Failed code:${lvimMsg.eCode}");
// }
// });
}
void queryUnreadCount() async {
print("queryUnreadCount start");
var unReadMessageNum = await RtmFlutterPlugin.queryUnReadMessageNum();
print(TAG + "unReadMessageNum = " + unReadMessageNum.toString());
Fluttertoast.showToast(msg: "unreadCount:${unReadMessageNum}");
}
void onClickSessionList() async {
List<LVIMSession> list = await RtmFlutterPlugin.querySessionList(
LVIMEnumDefine.LVIMDB_TYPE_ROOM);
if (list == null || list.length == 0) {
print("$TAG onClickSessionList null");
return;
}
list.forEach((element) {
print(
"$TAG onClickSessionList from=${element.lastMsg.fromID} to=${element.lastMsg.toID} dbid = ${element.lastMsg.dbid}, send_State = ${element.lastMsg.sendState}, unread_count = ${element.unreadCount}, content = ${element.lastMsg.msgContent}");
});
}
void onClear1234Unread() async {
String tid = _msgTargetIdTextEdit.text;
int result = await RtmFlutterPlugin.clearPrivateSessionUnreadMsg(
tid, LVIMEnumDefine.LVIMDB_TYPE_ROOM);
print(TAG + " onClear1234Unread result = $result");
}
void onClearAllUnread() async {
int result = await RtmFlutterPlugin.clearPrivateAllUnreadMsg(
LVIMEnumDefine.LVIMDB_TYPE_ROOM);
print(TAG + " onClearAllUnread result = $result");
}
void sendMessageHasRead() async {
String tid = _msgTargetIdTextEdit.text;
int stime = new DateTime.now().millisecondsSinceEpoch;
var result = await RtmFlutterPlugin.sendMessageHasRead(tid, stime);
print(TAG +
" sendMessageHasRead result = ${result.eCode}, tid = $tid, stime = $stime");
print(
'sendMessageHasRead 回调成功');
Fluttertoast.showToast(msg: "sendMessageHasRead result = ${result.eCode}, tid = $tid, stime = $stime");
}
void onDeleteChat() async {
String tid = _msgTargetIdTextEdit.text;
int rs = await RtmFlutterPlugin.deleteLocalPrivateSession(tid);
print(TAG + " onDeleteChat result = $rs, tid = $tid");
}
void onClickSend() {
print(
"[Wing] sendPrivateMessage start to = ${_msgTargetIdTextEdit.text}, content = ${_msgInputTextEdit.text}");
var lvPushContent = new LVPushContent();
lvPushContent.title = "push title";
lvPushContent.body = "push content";
lvPushContent.extra = "push extra";
lvPushContent.click_action = "FLUTTER_NOTIFICATION_CLICK";
RtmFlutterPlugin.sendPrivateMessage(
LVIMEnumDefine.IM_SUBTYPE_TEXT,
_msgTargetIdTextEdit.text,
"msgType",
_msgInputTextEdit.text,
lvPushContent)
.then((lvimMsg) {
print(
'[Wing] sendPrivateMessage end result = ${lvimMsg.eCode}, dbid = ${lvimMsg.msg.dbid}, sendState = ${lvimMsg.msg.sendState} stime = ${lvimMsg.msg.stime}');
print(
'sendPrivateMessage 回调成功');
if (lvimMsg.eCode == 0) {
Fluttertoast.showToast(msg: "Send Msg Success");
} else {
Fluttertoast.showToast(msg: "Send Msg Failed code:${lvimMsg.eCode}");
}
// resend(lvimMsg.msg);
});
// RtmFlutterPlugin.setPrivateDBStorageMax(5);
}
// 消息重发
void resend(LVIMMsg msg) {
RtmFlutterPlugin.sendMessage(msg).then((lvimMsg) {
print(
'[Wing] sendMessage end result = ${lvimMsg.eCode}, dbid = ${lvimMsg.msg.dbid}, sendState = ${lvimMsg.msg.sendState} stime = ${lvimMsg.msg.stime}');
if (lvimMsg.eCode == 0) {
Fluttertoast.showToast(msg: "Send Msg Success");
} else {
Fluttertoast.showToast(msg: "Send Msg Failed code:${lvimMsg.eCode}");
}
});
}
void onClickWatchLive() async {
print("onClickWatchLive");
bool isCan = await canLive();
if (!isCan) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
LivePage(false, _roomIdFieldController.text, userId)));
}
void onClickStartLive() async {
print("onClickStartLive");
bool isCan = await canLive();
if (!isCan) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
LivePage(true, _roomIdFieldController.text, userId)));
}
Future<bool> canLive() async {
// 1. 相机权限
bool canLive = await checkPermission();
print("canlive = $canLive");
if (!canLive) return canLive;
// 2. 是否输入了房间id
if (_roomIdFieldController.text.length == 0) {
LinkvUi.showAlert(context, "Please enter your room number!");
return false;
}
// 3. SDK是否已经初始化成功了
if (!_isSDKInit) {
initSDK();
return false;
}
// 4. IM是否鉴权通过
if (!isIMAuthed) {
Fluttertoast.showToast(
msg: "请等待鉴权成功后进入房间",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER);
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text("uid :$userId"),
),
body: SafeArea(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => FocusScope.of(context).requestFocus(new FocusNode()),
child: Container(
padding: const EdgeInsets.only(left: 20, top: 20, right: 20),
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Text("Version: "),
Expanded(
child: Text("$_version"),
)
],
),
TextButton(
onPressed: () {
if (_msgTargetIdTextEdit.text.length == 0) {
Fluttertoast.showToast(msg: "please target user id");
return;
}
Navigator.push(
context,
MaterialPageRoute(
builder: (ctx) => IMMediaMsgPage(
userid: userId,
targetUid: _msgTargetIdTextEdit.text,
)));
},
child: Text("测试IM私信"),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
TextField(
controller: _msgInputTextEdit,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(
left: 10, top: 12, bottom: 12),
hintText: "Please enter message Content",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.cyan))),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
TextField(
controller: _msgTargetIdTextEdit,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(
left: 10, top: 12, bottom: 12),
hintText: "Please enter target user id",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.cyan))),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
TextField(
controller: _msgListTextEdit,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(
left: 10, top: 12, bottom: 12),
hintText: "received message",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.cyan)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.cyan))),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width - 20,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"Send Private Message",
style: TextStyle(color: Colors.white),
),
onPressed: onClickSend,
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Row(
children: <Widget>[
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"History Msg",
style: TextStyle(color: Colors.white),
),
onPressed: onClickHistoryMsg),
),
Container(
width: 20,
),
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"Session List",
style: TextStyle(color: Colors.white),
),
onPressed: onClickSessionList)),
],
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Row(
children: <Widget>[
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"Clear 1234 Unread",
style: TextStyle(color: Colors.white),
),
onPressed: onClear1234Unread)),
Container(
width: 20,
),
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"Clear All Unread",
style: TextStyle(color: Colors.white),
),
onPressed: onClearAllUnread)),
],
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Row(
children: <Widget>[
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"delete chat",
style: TextStyle(color: Colors.white),
),
onPressed: onDeleteChat)),
Container(
width: 20,
),
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"send read receipt",
style: TextStyle(color: Colors.white),
),
onPressed: sendMessageHasRead)),
],
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Row(
children: <Widget>[
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"send event msg",
style: TextStyle(color: Colors.white),
),
onPressed: sendEventMsg)),
Container(
width: 20,
),
Container(
height: 50,
width: (MediaQuery.of(context).size.width - 60) * 0.5,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"get unread count",
style: TextStyle(color: Colors.white),
),
onPressed: queryUnreadCount)),
],
),
Padding(
padding: const EdgeInsets.only(top: 50),
),
TextField(
controller: _roomIdFieldController,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(
left: 10, top: 12, bottom: 12),
hintText: "Please enter room_id",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.cyan))),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width - 20,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"Start Live",
style: TextStyle(color: Colors.white),
),
onPressed: onClickStartLive,
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
),
Container(
height: 50,
width: MediaQuery.of(context).size.width - 20,
color: Colors.cyan,
child: CupertinoButton(
child: Text(
"Watch Live",
style: TextStyle(color: Colors.white),
),
onPressed: onClickWatchLive,
),
),
],
),
),
),
),
),
);
}
// MARK: - Permission
Future<bool> checkPermission() async {
Permission _camera = Permission.camera;
Permission _microphone = Permission.microphone;
PermissionStatus status;
status = await _camera.request();
if (status != PermissionStatus.granted) return false;
status = await _microphone.request();
if (status != PermissionStatus.granted) return false;
return true;
}
@override
void onIMMessageReceive(var msg) {
var msgContent = msg.msgContent.toString();
print(TAG + " onIMMessageReceive fromid = " + msg.fromID);
_msgListTextEdit.text = msg.fromID + " : " + msgContent;
// 发送该消息已读
RtmFlutterPlugin.sendMessageHasRead(msg.fromID, msg.stime);
}
@override
void onEventMessageReceive(var msg) {
print(TAG +
" onEventMessageReceive content = ${msg.msgContent} type = ${msg.extend1} ");
}
@override
void onReadMessageReceive(var msg, int stime) {
// stime之前的消息皆可设为已读
print(TAG + "onReadMessageReceive : $stime");
_msgListTextEdit.text = msg.fromID + " : 已读时间戳为 $stime 的消息";
}
@override
void onIMTokenExpired(String uid, String token) {
isIMAuthed = false;
print(TAG + "onIMTokenExpired uid = " + uid);
}
@override
void onIMAuthSucceed(String uid, String token, int unReadMsgSize) {
isIMAuthed = true;
print(TAG + "onIMAuthSucceed uid = " + uid + " token = " + token);
Fluttertoast.showToast(
msg: "IM 鉴权成功",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER);
}
@override
void onIMAuthFailed(
String uid, String token, int ecode, int rcode, bool isTokenExpired) {
isIMAuthed = false;
print(TAG + "onIMAuthFailed uid = " + uid + " ecode =$ecode ");
}
@override
void onQueryIMToken() {
requestReleaseIMToken();
// requestDebugIMToken();
}
void requestDebugIMToken() {
if (isTokenRequesting) return;
print(TAG + "requestDebugToken start");
isTokenRequesting = true;
RtmFlutterPlugin.requestDebugToken(userId, "Test").then((result) {
isTokenRequesting = false;
int code = result["code"];
String resultMsg = result["result"];
print(
TAG + "requestDebugToken end msg = " + resultMsg + " code = $code");
/// 获取debug token 成功
if (code == 0) {
RtmFlutterPlugin.setIMToken(userId, resultMsg);
}
});
}
void requestReleaseIMToken() {
if (isTokenRequesting) return;
print(TAG + "requestReleaseIMToken start userId = $userId");
isTokenRequesting = true;
Help.requestXMYIMToken(userId).then((value) {
isTokenRequesting = true;
if (value["status"] == "200" && value["data"]["code"] == "200") {
print(TAG + "setIMToken token = ${value["data"]["token"]}");
print(TAG + "setIMToken userId = ${userId}");
RtmFlutterPlugin.setIMToken(userId, value["data"]["token"]);
}
print(TAG + "requestReleaseIMToken end data = $value");
});
// RtmFlutterPlugin.setIMToken(userId, "xxxx");
}
@override
void onIMMessageReadedAcks(List<int> listId) {
// TODO: implement onIMMessageReadedAcks
}
@override
void onIMUserKicked(String uid, int code) {
// TODO: implement onIMUserKicked
}
@override
void onIMConnected() {
// TODO: implement onIMConnected
Fluttertoast.showToast(
msg: "onIMConnected()方法被调用,网络连接",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER);
}
@override
void onIMLosted() {
// TODO: implement onIMLosted
Fluttertoast.showToast(
msg: "onIMLosted()方法被调用,网络断开",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER);
}
@override
void onIMConnectState(int connectState) {
// TODO: implement onIMConnectState
print("onIMConnectState()方法被调用,connectState = $connectState");
Fluttertoast.showToast(
msg: "onIMConnectState()方法被调用,connectState = $connectState",
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.CENTER);
}
@override
void onIMSendMessageReceive(msg) {
}
}