前言:因为我所做的项目需求是,接到后端推送视频消息,APP端点击消息跳转到通话页面进行1对1通话,而后端已经进行账号好友等的处理,环信提供的demo很多功能前端暂时用不到了,以下就把我用到的罗列出来。
PS:本人并不是前端大神,第一次分享文章,有写不对的欢迎提出来哦,请大佬们多多包涵!
效果:
一、引入插件
- 首先,在插件市场https://ext.dcloud.net.cn/plugin?id=3507,按照官方文档集成参考说明,把所用到插件导入到你的项目中
- 下载环信demo,以下是需要直接复制粘贴到你的项目中的sdk和组件以及你所用到的图片,图片暂不展示
- 音视频SDK在emediaSDK/emedia_for_miniProgram.js里,引入SDK方法:在App.vue页面引入
let emedia = uni.emedia = require("./emediaSDK/emedia_for_miniProgram");
emedia.config({useUniappPlugin: true}) // 设置使用uniapp插件
二、改造demo实现我的项目需求
- 项目只是单纯实现接听视频通话,所以思路大概如下:
(1)项目需求直接用项目的账号进行登录,后端已处理环信的账号登录、好友绑定、创建群聊等,所以我这边登录项目的账号的时候已经跟后端的账号好友绑定了。现在展示一下环信登录的代码:
(appKey是每个项目使用环信的唯一标识,就相当于微信小程序的appid)
// //接收环信多人视频
var options = {
apiUrl: 'https://a1.easemob.com',
user: XX,
pwd: XX,
appKey: XX
};
//环信登录
WebIM.conn.open(options);
(2)在App.vue入口页,通过onTextMessage()函数监听到后端传来的视频参数,接收到我的账号、发出视频邀请的账号、会议Id,接收到的参数直接传入groupChatRoom页面:
(这里只展示关键代码,后面附上groupChatRoom页面完整代码)
WebIM.conn.listen({
onTextMessage(message) {
console.log("onTextMessage", message);
if (message) {
if (onMessageError(message)) {
msgStorage.saveReceiveMsg(message, msgType.TEXT);
}
var my = uni.getStorageSync("myUsername");
var nameList = {
myName: my,
your: message.from,
groupId: message.ext.conferenceId
};
uni.navigateTo({
url: "/pages/groupChatRoom/groupChatRoom?username=" + JSON.stringify(nameList)
});
calcUnReadSpot(message);
ack(message);
}
},
(3)groupChatRoom页面里展示的是接收群聊消息,因为后端已做好好友绑定、创建群聊,所以这里我只需列出后端传来的最新消息即可,以下是demo提供的处理数据的代码,有一些数据我的项目需求用不到,不过懒得整理了,处理最后得到的array数据,存入浏览器本地,之后需要调用到:
getChatList() {
var array = [];
var member = uni.getStorageSync("member");
var myName = uni.getStorageSync("myUsername");
var listGroups = uni.getStorageSync('listGroup') || [];
for (let i = 0; i < member.length; i++) {
let newChatMsgs = uni.getStorageSync(member[i].name + myName) || [];
let historyChatMsgs = uni.getStorageSync("rendered_" + member[i].name + myName) || [];
let curChatMsgs = historyChatMsgs.concat(newChatMsgs);
if (curChatMsgs.length) {
let lastChatMsg = curChatMsgs[curChatMsgs.length - 1];
lastChatMsg.unReadCount = newChatMsgs.length;
if (lastChatMsg.unReadCount > 99) {
lastChatMsg.unReadCount = "99+";
}
let dateArr = lastChatMsg.time.split(' ')[0].split('-');
let timeArr = lastChatMsg.time.split(' ')[1].split(':');
let month = dateArr[2] < 10 ? '0' + dateArr[2] : dateArr[2];
lastChatMsg.dateTimeNum = `${dateArr[1]}${month}${timeArr[0]}${timeArr[1]}${timeArr[2]}`;
lastChatMsg.time = `${dateArr[1]}月${dateArr[2]}日 ${timeArr[0]}时${timeArr[1]}分`;
array.push(lastChatMsg);
}
}
for (let i = 0; i < listGroups.length; i++) {
let newChatMsgs = uni.getStorageSync(listGroups[i].groupid + myName) || [];
let historyChatMsgs = uni.getStorageSync("rendered_" + listGroups[i].groupid + myName) || [];
let curChatMsgs = historyChatMsgs.concat(newChatMsgs);
if (curChatMsgs.length) {
let lastChatMsg = curChatMsgs[curChatMsgs.length - 1];
lastChatMsg.unReadCount = newChatMsgs.length;
if (lastChatMsg.unReadCount > 99) {
lastChatMsg.unReadCount = "99+";
}
let dateArr = lastChatMsg.time.split(' ')[0].split('-') let timeArr = lastChatMsg.time.split(' ')[1].split(':') let month = dateArr[2] < 10 ? '0' + dateArr[2] : dateArr[2] lastChatMsg.time = `${dateArr[1]}月${dateArr[2]}日 ${timeArr[0]}时${timeArr[1]}分`
lastChatMsg.dateTimeNum = `${dateArr[1]}${month}${timeArr[0]}${timeArr[1]}${timeArr[2]}`lastChatMsg.groupName = listGroups[i].groupname array.push(lastChatMsg);
}
}
array.sort((a, b) = >{
return b.dateTimeNum - a.dateTimeNum;
});
console.log('array:', array)
//2021/02/01新加
uni.setStorageSync("newChatMsg", array);
return array;
},
array得到的数据格式:
[{
"info": {
"from": "nzXXXXXXfk", //对方的账号
"to": "lXXXXXX5" //你的账号
},
"username": "nzXXXXXXfk",
"yourname": "nzXXXXXXfk",
"msg": {
"type": "txt",
"url": "",
"data": [{
"data": "快来加入会议 - LBJ13H055XXXXXXXXXXXXXC65666",
"type": "txt"
}],
"ext": {
"conferenceId": "LBJ13H05522QATI4O4DEXH00C65666", //会议id,后端每发一个视频流对应一个id
"msg_extension": "{\"inviter\":\"nzXXXXXXfk\"}", //处理过的对方的账号
"password": ""//会议密码
}
},
"style": "",
"time": "2月1日 15时41分",
"mid": "txt835802715723401212",
"chatType": "chat",
"unReadCount": 10,
"dateTimeNum": "201154124"
}]
上面的array将会传到comps/chat/chat.vue–comps/chat/msglist/msglist.vue组件里处理,这个组件放的就是群聊窗口,而msglist就是处理消息列表的。
chatMsg获取之前的array值,遍历出msgList消息列表值
let timer = setTimeout(function() {
me.username = uni.username;
let username = me.username;
let myUsername = uni.getStorageSync("myUsername");
let sessionKey = username.groupId ? username.groupId + myUsername: username.your + myUsername;
// let chatMsg = uni.getStorageSync(sessionKey) || [];
// 2021/02/01 新增 !!!!!
let chatMsg = uni.getStorageSync("newChatMsg"); //更改了这里!!!
console.log('chatMsg:', chatMsg) me.renderMsg(null, null, chatMsg, sessionKey);
uni.setStorageSync(sessionKey, null);
disp.on('em.error.sendMsgErr',
function(err) {
curMsgMid = err.data.mid;
isFail = true;
console.log('发送失败了');
return;
let msgList = me.chatMsg;
msgList.map(item = >{
if (item.mid.substring(item.mid.length - 10) == curMsgMid.substring(curMsgMid.length - 10)) {
item.msg.data[0].isFail = true;
item.isFail = true;
me.setData({
chatMsg: msgList
});
}
});
console.log('msgList:', msgList)
if (me.curChatMsg[0].mid == curMsgMid) {
me.curChatMsg[0].msg.data[0].isShow = false;
me.curChatMsg[0].isShow = false;
}
uni.setStorageSync("rendered_" + sessionKey, msgList);
});
msgStorage.on("newChatMsg", this.dispMsg);
},
1000);
(4)comps/chat/chat.vue页面里点击消息列表,引用父级页面groupChatRoom的onClickInviteMsg方法,并跳转到视频通话页面:emedia页面
comps/chat/chat.vue页面
clickMsg(msg) {
this.$emit('onClickInviteMsg', msg) console.log('点击消息上一级', msg)
},
groupChatRoom页面
<chat
id="groupchat"
ref="chat"
:username="username"
:groupId="groupId"
chatType="chatRoom"
@onMakeVideoCall="makeVideoCall"
@onClickInviteMsg="onClickMsg">
</chat>
export default {
methods: {
onClickMsg(msg){
msg.action = 'join'
uni.navigateTo({
url: "../emedia/index?srcData="+JSON.stringify(msg)
});
}
}
}
(5)emedia页面
插件市场里所展示的代码就写在这个页面里边,此时效果已经出来了。
< emlive - player id = "livePlayer"ref = "livePlayer"objectFit = "fit"@bindstatechange = "playerStateChange"@bindnetstatus = "playerNetChange": data - streamId = "item.id": muted = "false": enableCamera = "true": openSpeaker = "openSpeaker"@callbackData = "onPlayerData"style = "width:170px;height:170px; margin: 5px" > </emlive-player>
三、附上groupChatRoom页面完整代码:
<template>
<chat
id="groupchat"
ref="chat"
:username="username"
:groupId="groupId"
chatType="chatRoom"
@onMakeVideoCall="makeVideoCall"
@onClickInviteMsg="onClickMsg">
</chat>
</template>
<script>
let disp = require("../../utils/broadcast");
import chat from "../../comps/chat/chat.vue";
var WebIM = require("../../utils/WebIM")["default"];
export default {
data() {
return {
username: {
your: ""
},
search_btn: true,
search_chats: false,
show_mask: false,
yourname: "",
unReadSpotNum: 0,
unReadNoticeNum: 0,
messageNum: 0,
unReadTotalNotNum: 0,
arr: [],
show_clear: false,
member: "",
isIPX: false,
gotop: false,
input_code: ""
};
},
components: {
chat
},
props: {
groupId:{
type:String,
default:''
}
},
// options = 系统传入的 url 参数
onLoad(options) {
let me = this;
let username = JSON.parse(options.username);
this.setData({
username: username
});
uni.username = username;
uni.setNavigationBarTitle({
title: username.your
});
this.getRoster();
},
onShow: function () {
this.setData({
arr: this.getChatList()
});
if (getApp().globalData.isIPX) {
this.setData({
isIPX: true
});
}
},
onUnload() {
disp.fire("em.chatroom.leave");
},
methods: {
getRoster() {
let me = this;
let rosters = {
success(roster) {
var member = [];
for (let i = 0; i < roster.length; i++) {
if (roster[i].subscription == "both") {
member.push(roster[i]);
}
}
uni.setStorage({
key: "member",
data: member
});
me.setData({
member: member
});
me.listGroups(); //if(!systemReady){
disp.fire("em.main.ready"); //systemReady = true;
//}
// me.getChatList()
me.setData({
arr: me.getChatList(),
unReadSpotNum: getApp().globalData.unReadMessageNum > 99 ? '99+' : getApp().globalData.unReadMessageNum
});
},
error(err) {
console.log(err);
}
};
WebIM.conn.getRoster(rosters);
},
listGroups() {
var me = this;
return WebIM.conn.getGroup({
limit: 50,
success: function (res) {
uni.setStorage({
key: "listGroup",
data: res.data
});
me.getChatList();
},
error: function (err) {
console.log(err);
}
});
},
makeVideoCall(data){
console.log('data:', data)
if(false){
uni.showToast({
title: '请输入会议Id',
duration: 2000
});
return
}
uni.navigateTo({
url: "../emedia/index?srcData="+JSON.stringify(data)
});
},
// 不包含陌生人版本
getChatList() {
var array = [];
var member = uni.getStorageSync("member");
var myName = uni.getStorageSync("myUsername");
var listGroups = uni.getStorageSync('listGroup') || [];
for (let i = 0; i < member.length; i++) {
let newChatMsgs = uni.getStorageSync(member[i].name + myName) || [];
let historyChatMsgs = uni.getStorageSync("rendered_" + member[i].name + myName) || [];
let curChatMsgs = historyChatMsgs.concat(newChatMsgs);
if (curChatMsgs.length) {
let lastChatMsg = curChatMsgs[curChatMsgs.length - 1];
lastChatMsg.unReadCount = newChatMsgs.length;
if (lastChatMsg.unReadCount > 99) {
lastChatMsg.unReadCount = "99+";
}
let dateArr = lastChatMsg.time.split(' ')[0].split('-');
let timeArr = lastChatMsg.time.split(' ')[1].split(':');
let month = dateArr[2] < 10 ? '0' + dateArr[2] : dateArr[2];
lastChatMsg.dateTimeNum = `${dateArr[1]}${month}${timeArr[0]}${timeArr[1]}${timeArr[2]}`;
lastChatMsg.time = `${dateArr[1]}月${dateArr[2]}日 ${timeArr[0]}时${timeArr[1]}分`;
array.push(lastChatMsg);
console.log('array1:', array)
}
}
for(let i = 0; i < listGroups.length; i++){
let newChatMsgs = uni.getStorageSync(listGroups[i].groupid + myName) || [];
let historyChatMsgs = uni.getStorageSync("rendered_" + listGroups[i].groupid + myName) || [];
let curChatMsgs = historyChatMsgs.concat(newChatMsgs);
if(curChatMsgs.length){
let lastChatMsg = curChatMsgs[curChatMsgs.length - 1];
lastChatMsg.unReadCount = newChatMsgs.length;
if(lastChatMsg.unReadCount > 99) {
lastChatMsg.unReadCount = "99+";
}
let dateArr = lastChatMsg.time.split(' ')[0].split('-')
let timeArr = lastChatMsg.time.split(' ')[1].split(':')
let month = dateArr[2] < 10 ? '0' + dateArr[2] : dateArr[2]
lastChatMsg.time = `${dateArr[1]}月${dateArr[2]}日 ${timeArr[0]}时${timeArr[1]}分`
lastChatMsg.dateTimeNum = `${dateArr[1]}${month}${timeArr[0]}${timeArr[1]}${timeArr[2]}`
lastChatMsg.groupName = listGroups[i].groupname
array.push(lastChatMsg);
console.log('array2:', array)
}
}
array.sort((a, b) => {
return b.dateTimeNum - a.dateTimeNum;
});
console.log('array3:', array)
//2021/02/01新加
uni.setStorageSync("newChatMsg" , array);
return array;
},
onClickMsg(msg){
msg.action = 'join'
uni.navigateTo({
url: "../emedia/index?srcData="+JSON.stringify(msg)
});
}
}
};
</script>
<style>
@import "./groupChatRoom.css";
</style>
四、总结与遇到的问题
- 重点!:遇到视频出不来或黑屏,很有可能是因为emedia/index.nvue文件里的getName方法没改成自己的appkey 的appname。 如你的appkey为:1101246581426371#chatdemoui,以下红框改成相应内容
(这里真的很坑,是问了环信客服才知道)- 注意:groupChatRoom模块、emedia模块等建议不要放在自己新建的子目录里,而直接放在pages目录下,要不然会出现路径错误而无法正常运行。
- 要用自定义基座运行,公共测试证书就行,要不然视频会黑屏。
- 整理demo时因为很多参数被封装了,单独引入很容易出错,建议直接复制,然后再把不需要的代码删掉。