uniapp即时通讯
- 1,初始化(刚开始就紧跟着文档走)
- 2,App.vue中项目引入腾讯云,(附上账号在其他地方登陆的监听)
- 3,登录前必需
- 3.1,获取登录id
- 3.2,生成userSig,独立封装一下
- 3.2.1,文档下载生成UserSig的内容
- 3.2.2,新建GenerateTestUserSig.js
- 3.2.3,页面使用生成Usersig
- 3.3,App.vue中的onshow要监听登录,因为IM的sdk会在app重新进入的时候登出
- 3.4,登录完,你可以获取用户信息来更新IM的用户信息,为将来用户列表的头像和昵称做铺垫
- 4,用户模块,先给看一下成品的消息推送的截图
- 4.0,先上一下HTMl截图
- 4.1,先发送消息,然后才能获取用户列表
- 4.2,滚动到底部的代码
- 4.3,发送图片
- 4.4,历史聊天记录
- 4.5,监听对面发来的消息
- 4.5,向上拉到获取旧历史记录
- 4.6,向上拉到获取旧历史记录
- 4.7,当用户列表展示未读数量的时候,进来聊天页面需要将消息已读
- 5,用户列表展示,先看一下HTML截图
- 5,嘿嘿,提供思路~
附上腾讯云文档链接:https://cloud.tencent.com/document/product/269/75285
1,初始化(刚开始就紧跟着文档走)
// 从v2.11.2起,SDK 支持了 WebSocket,推荐接入;v2.10.2及以下版本,使用 HTTP
npm install tim-wx-sdk --save
// 发送图片、文件等消息需要腾讯云 即时通信 IM 上传插件
npm install tim-upload-plugin --save
// 拦截或替换敏感词需要本地审核插件
npm install tim-profanity-filter-plugin --save
2,App.vue中项目引入腾讯云,(附上账号在其他地方登陆的监听)
<script>
import TIM from 'tim-wx-sdk';
import TIMUploadPlugin from 'tim-upload-plugin';
import TIMProfanityFilterPlugin from 'tim-profanity-filter-plugin';
import Vue from 'vue'
export default {
onLaunch: function() {
console.log('App Launch')
let options = {
SDKAppID: xxxx// 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID
};
// 秘钥e8e585a65c480847f1a53046d5ba92c383168ba50dfd7dd8cb54325f18bc4fd5
// 创建 SDK 实例,`TIM.create()`方法对于同一个 `SDKAppID` 只会返回同一份实例
let tim = TIM.create(options); // SDK 实例通常用 tim 表示
// 设置 SDK 日志输出级别,详细分级请参见 setLogLevel https://web.sdk.qcloud.com/im/doc/zh-cn/SDK.html#setLogLevel 接口的说明</a>
tim.setLogLevel(1); // 普通级别,日志量较多,接入时建议使用
// tim.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用
// 注册腾讯云即时通信 IM 上传插件
tim.registerPlugin({
'tim-upload-plugin': TIMUploadPlugin
});
// 注册腾讯云即时通信 IM 本地审核插件
tim.registerPlugin({
'tim-profanity-filter-plugin': TIMProfanityFilterPlugin
});
let onKickedOut = function(event) {
console.log(event.data.type, "被踢了,被踢了");
uni.showToast({
title: "账号在其他地方登陆,请重新登录!",
icon: "none"
})
uni.clearStorage()
setTimeout(() => {
uni.reLaunch({
url: "/pages/login/login"
})
}, 1000)
// TIM.TYPES.KICKED_OUT_MULT_ACCOUNT(Web 端,同一帐号,多页面登录被踢)
// TIM.TYPES.KICKED_OUT_MULT_DEVICE(同一帐号,多端登录被踢)
// TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED(签名过期)
// TIM.TYPES.KICKED_OUT_REST_API(REST API kick 接口踢出。v2.20.0起支持)
};
tim.on(TIM.EVENT.KICKED_OUT, onKickedOut);
//注册为全局变量
Vue.prototype.$tim = tim
Vue.prototype.$TIM = TIM
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
</style>
3,登录前必需
3.1,获取登录id
这个id相当于用户标识,一般采用用户id,但注意,传的 时候要转成字符串格式
3.2,生成userSig,独立封装一下
3.2.1,文档下载生成UserSig的内容
点击去下载:
3.2.2,新建GenerateTestUserSig.js
import LibGenerateTestUserSig from '@/common/lib-generate-test-usersig-es.min.js'
const _SECRETKEY = '';
/*
* Module: GenerateTestUserSig
*
* Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。
* 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。
*
* Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
*
* 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
* 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
* 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
*
* 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
* 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
*
* Reference:https://cloud.tencent.com/document/product/647/17275#Server
*/
function genTestUserSig(userID) {
//调用的时候,传入userID
/**
* 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
*
* 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId,
* 它是腾讯云用于区分客户的唯一标识。
*/
var SDKAPPID = xxxx;//替换为您自己账号下的 SDKAppId
/**
* 签名过期时间,建议不要设置的过短
* <p>
* 时间单位:秒
* 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
*/
var EXPIRETIME = 604800;
/**
* 计算签名用的加密密钥,获取步骤如下:
*
* step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个,
* step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
* step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
*
* 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
* 文档:https://cloud.tencent.com/document/product/647/17275#Server
*/
var SECRETKEY = 'xxxxx';//填入秘钥哦
var generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME);
var userSig = generator.genTestUserSig(userID);
return {
sdkappid: SDKAPPID,
userSig: userSig
};
}
export {
genTestUserSig
}
3.2.3,页面使用生成Usersig
import {
genTestUserSig
} from "@/common/GenerateTestUserSig.js"
getlogin() {
let that = this
that.POST('/login', {
mobile: this.form.mobile,
password: this.form.password,
}).then(res => {
console.log(res)
if (res.code == 1) {
let userid = String(res.data.userinfo.id)//拿到id
let UserSig = genTestUserSig(userid).userSig //生成UserSig
console.log(UserSig, "")
let getlogin = that.$tim.login({
userID: userid,
userSig: UserSig
});
getlogin.then(function(imResponse) {
console.log(imResponse, "登陆成功"); // 登录成功
uni.setStorageSync('userinfo', res.data.userinfo)
uni.setStorageSync('token', res.data.userinfo.token)
if (imResponse.data.repeatLogin === true) {
// 标识帐号已登录,本次登录操作为重复登录。v2.5.1 起支持
console.log(imResponse.data.errorInfo);
that.myuserinfo()
} else {
that.myuserinfo()
}
}).catch(function(imError) {
console.warn('重复登录', imError); // 登录失败的相关信息
});
} else {
uni.showToast({
title: res.msg,
icon: "none"
})
}
}).catch(err => {
console.log(err)
})
3.3,App.vue中的onshow要监听登录,因为IM的sdk会在app重新进入的时候登出
onShow: function() {
console.log('App Show')
if (uni.getStorageSync('token')) {
let that = this
let userinfo = uni.getStorageSync('userinfo')
let userid = String(userinfo.id)
let UserSig = genTestUserSig(userid).userSig //生成UserSig
let getlogin = that.$tim.login({
userID: userid,
userSig: UserSig
});
getlogin.then(function(imResponse) {
console.log(imResponse, "登陆成功"); // 登录成功
if (imResponse.data.repeatLogin === true) {
// 标识帐号已登录,本次登录操作为重复登录。v2.5.1 起支持
console.log(imResponse.data.errorInfo);
} else {
}
}).catch(function(imError) {
console.warn('重复登录', imError); // 登录失败的相关信息
});
}
},
3.4,登录完,你可以获取用户信息来更新IM的用户信息,为将来用户列表的头像和昵称做铺垫
//个人信息
myuserinfo() {
let that = this
that.GET('/uInfo').then((res) => {
if (res.code == 1) {
let user;
user = res.data
setTimeout(() => {
console.log(user)
// 修改个人标配资料
let promise = that.$tim.updateMyProfile({
nick: user.shop_name ? user.shop_name : user.nickname,
avatar: user.avatar,
gender: that.$TIM.TYPES.GENDER_UNKNOWN,
selfSignature: user.shop_name ? user.shop_name : '用户',
allowType: that.$TIM.TYPES.ALLOW_TYPE_ALLOW_ANY
});
promise.then(function(imResponse) {
console.log(imResponse.data, "更新成功"); // 更新资料成功
uni.switchTab({
url: "/pages/index/index"
})
}).catch(function(imError) {
console.warn('updateMyProfile error:',
imError); // 更新资料失败的相关信息
})
}, 500)
} else {
uni.showToast({
title: res.msg,
icon: "none"
})
}
})
},
4,用户模块,先给看一下成品的消息推送的截图
4.0,先上一下HTMl截图
4.1,先发送消息,然后才能获取用户列表
//发送消息
Go() {
// 发送文本消息,Web 端与小程序端相同
// 1. 创建消息实例,接口返回的实例可以上屏
let that = this
let message = that.$tim.createTextMessage({
to: that.To_user_id,//接受者ID
conversationType: 'C2C',//c2c代表单聊
payload: {
text: that.Keyword,//要发送的内容
},
cloudCustomData:"",//
needReadReceipt: true
});
// 2. 发送消息
let promise = that.$tim.sendMessage(message);
promise.then(function(imResponse) {
// 发送成功.输入框清空
that.Keyword = ""
//消息列表push当前消息
that.chatlist.push(imResponse.data.message)
//列表滚动到底部
that.scrollToBottom()
}).catch(function(imError) {
// 发送失败
console.warn('sendMessage error:', imError);
});
}
4.2,滚动到底部的代码
//滚动至聊天底部
scrollToBottom() {
let that = this
that.$nextTick(() => {
that.intoindex = "text" + Number(that.chatlist.length - 1)
})
},
4.3,发送图片
//发送图片
GoImage() {
let that = this
uni.chooseImage({
count: 2,
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album'], // 从相册选择
success: (res) => {
console.log(res)
let message = that.$tim.createImageMessage({
// to: '5MYfeMTrSEvmAF1cLct',
to: that.To_user_id,
conversationType: 'C2C',
payload: {
file: res
},
onProgress: function(event) {
console.log('file uploading:', event)
}
});
// 3. 发送图片
let promise = that.$tim.sendMessage(message);
promise.then(function(imResponse) {
// 发送成功
console.log(imResponse);
that.chatlist.push(imResponse.data.message)
that.scrollToBottom()
}).catch(function(imError) {
// 发送失败
console.warn('sendMessage error:', imError);
});
}
});
},
4.4,历史聊天记录
// 拉取历史消息
GetMessageList(groupid) {
let that = this
// 根据 sequence 拉群漫游消息,direction 0 向上拉,拉更旧的消息,direction 1 向下拉,拉更新的消息
let promise = this.$tim.getMessageListHopping({
conversationID: 'C2C' + that.To_user_id,
count: 15,
direction: 0
});
promise.then(function(imResponse) {
console.log(imResponse, '历史消息')
const messageList = imResponse.data.messageList; // 消息列表。
that.nextReqMessageID = imResponse.data.messageList[0].ID; // 用于续拉,分页续拉时需传入该字段。
console.log(that.nextReqMessageID)
that.chatlist = messageList
console.log(that.chatlist[that.chatlist.length - 1].type == "TIMImageElem")
that.scrollToBottom()
});
},
4.5,监听对面发来的消息
// 接收消息监听
function accentmiss(event) {
vue.accentmiss(event)
}
export default {
data() {
return {
};
},
onLoad(options) {
this.To_user_id = String(options.To_user_id)
// 接收消息监听
this.$tim.on(this.$TIM.EVENT.MESSAGE_RECEIVED, accentmiss);
}
methods:{
// 接收消息
accentmiss(event) {
console.log(event, "收到消息了")
this.chatlist.push(event.data[0])
this.readmiss()
this.scrollToBottom()
}
},
// 页面卸载,关闭监听
onUnload() {
this.$tim.off(this.$TIM.EVENT.MESSAGE_RECEIVED, accentmiss);
},
},
4.5,向上拉到获取旧历史记录
上面第一次获取历史记录的时候,拿到了历史记录的第一条历史记录ID,nextReqMessageID
接下来,pages.json,开启为true
onPullDownRefresh() {
// 下拉查看更多消息
let that = this
let promise = this.$tim.getMessageList({
conversationID: 'C2C' + that.To_user_id,//c2c是必要的
nextReqMessageID: that.nextReqMessageID,
direction: 0,//0向上,1向下
count: 15,//拉取数量
});
promise.then(function(imResponse) {
console.log(imResponse)
setTimeout(function() {
uni.stopPullDownRefresh();
}, 1000);
that.nextReqMessageID = imResponse.data.messageList[0].ID; // 用于续拉,分页续拉时需传入该字段。
that.chatlist = [...imResponse.data.messageList, ...that.chatlist]//通过扩展运算符,向前拼接
});
},
4.6,向上拉到获取旧历史记录
//聊天图片放大功能
openimg(index) {
console.log(index)
let that = this
let list = []
list.push(that.chatlist[index].payload.imageInfoArray[0].url)
uni.previewImage({
urls: list,
current: 1,
longPressActions: {
// itemList: ['发送给朋友', '保存图片', '收藏'],
success: function(data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function(err) {
console.log(err.errMsg);
}
}
});
},
4.7,当用户列表展示未读数量的时候,进来聊天页面需要将消息已读
//消息已读
readmiss() {
// 将某会话下所有未读消息已读上报
let that = this
let promise = that.$tim.setMessageRead({
conversationID: 'C2C' + that.To_user_id
});
promise.then(function(imResponse) {
console.log("已读成功")
// 已读上报成功,指定 ID 的会话的 unreadCount 属性值被置为0
}).catch(function(imError) {
// 已读上报失败
console.warn('setMessageRead error:', imError);
});
},
5,用户列表展示,先看一下HTML截图
//获取会话列表
getchatlist() {
let that = this
that.userlist = []
let promise = that.$tim.getConversationList();
promise.then(function(imResponse) {
that.conversationList = imResponse.data.conversationList; // 全量的会话列表,用该列表覆盖原有的会话列表
that.conversationList.forEach(item => {
item.lastMessage.lastTime1 = that.stampTime(item.lastMessage.lastTime * 1000)//最新消息的时间
})
console.log(that.conversationList)
const isSyncCompleted = imResponse.data.isSyncCompleted; // 从云端同步会话列表是否完成
}).catch(function(imError) {
console.warn('getConversationList error:', imError); // 获取会话列表失败的相关信息
});
},