仅需6步7分钟,用原生 js 接入腾讯云即时通信 IM
- 命令行打开项目文件根目录,`npm init -y` 快速生成 package.json
- 下载腾讯云即时通信 IMSDK:`npm install tim-wx-sdk@latest --production`
- 构建 npm
构建成功后能在项目目录看到 miniprogram_npm 和 tim-wx-sdk
详情-》本地设置-》使用 npm 模块
引入 TIM 模块
import TIM from 'tim-wx-sdk' //app.js App({ onLaunch: function () { // 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例 let options = { SDKAppID: 0 // 接入时需要将0替换为您的即时通信应用的 SDKAppID }; let tim = TIM.create(options); // SDK 实例通常用 tim 表示 // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明 tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用 }, globalData: { userInfo: null } })
- 控制台如果能看到 TIM.VERSION: 2.6.1 的日志,表示接入成功。
- 相关文档
常看文档
cloud.tencent.com/document/pr…
- 新建im.js
import TIM from 'tim-wx-sdk';import { genTestUserSig} from '../debug/GenerateTestUserSig.js';let tim;function initIM() { // 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例 let optionss = { SDKAppID: 1400348947 // 接入时需要将0替换为您的即时通信应用的 SDKAppID }; tim = TIM.create(optionss); // SDK 实例通常用 tim 表示 // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明 tim.setLogLevel(1); // 普通级别,日志量较多,接入时建议使用 }//im登录function imLogin(uid) { // onSdkReady() // onMessageReceived() return tim.login({ userID: uid, userSig: genTestUserSig(uid).userSig })}//自动登录function autoLogin() { //获取本地用户信息 var nickName = wx.getStorageSync("nickName"); var uid = wx.getStorageSync("uid"); //本地有用户信息时自动登录 if (nickName != null && nickName != "" && uid != null && uid != "") { let promise = imLogin(uid); promise.then(function (imResponse) { console.log("IM登录成功"); console.log(imResponse.data); //登录成功 wx.setStorageSync("isLogin", true); }).catch(function (imError) { console.warn('登录失败的相关信息error:', imError); // 登录失败的相关信息 }); }}//退出登录function imLogout() { return tim.logout();}//查看登录状态function isLogin() { return wx.getStorageSync("isLogin");}export { initIM, // imLogin, autoLogin, imLogout, isLogin, TIM, tim}
2、在app.js引入并挂在全局
const IM = require("./api/im");
App({ onLaunch(options) { //腾讯IM初始化 IM.initIM(); }, checkNewVersion: function () { // 检查版本更新 // 获取小程序更新机制兼容 if (wx.canIUse("getUpdateManager")) { const updateManager = wx.getUpdateManager(); updateManager.onCheckForUpdate(function (res) { // 请求完新版本信息的回调 if (res.hasUpdate) { updateManager.onUpdateReady(function () { wx.showModal({ title: "更新提示", content: "新版本已经准备好,是否重启应用?", success: function (res) { if (res.confirm) { // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 updateManager.applyUpdate(); } } }); }); updateManager.onUpdateFailed(function () { // 新的版本下载失败 wx.showModal({ title: "已经有新版本了哟~", content: "新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~" }); }); } }); } else { // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示 wx.showModal({ title: "提示", content: "当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。" }); } }, globalData: {}, IM});
3、新建player文件夹
//player.wxml
<view class="player"><!-- 头部 --> <scroll-view scroll-x class="player_top"> <view class="player_title" wx:for="{{10}}">title税点</view> </scroll-view><!-- 列表 --> <scroll-view scroll-y enable-flex="{{true}}" class="player_item"> <view class="pl_child" wx:for="{{10}}" bindtap="entry"> </view> </scroll-view> </view>
//player.wxss
/* pages/player/player.wxss */page{ height: 100%;}.player{ width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: flex-start;}.player_item{ display: flex; flex-direction: row; justify-content:flex-start; flex-wrap: wrap; height: 100%; width: 100%;}.player_top{ height: 80rpx; width: 100%; white-space:nowrap;}.player_title{ display: inline-block; line-height: 80rpx; padding: 0 30rpx; border: 1rpx solid yellow;}.pl_child{ width: 350rpx; border: 1rpx solid red; height: 100px; margin: 10rpx 0; margin-left: 16rpx;}
player.js
// pages/player/player.jsconst app = getApp();Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { }, // 进入聊天室 entry: function () { var self = this; // 防止两次点击操作间隔太快 var nowTime = new Date(); if (nowTime - this.data.tapTime < 1000) { return; } // let identifier = this.data.users[this.data.index].identifier||' ' // let userConfig = genTestUserSig(identifier)||' '// ?identifier=${identifier}&userSig=${userConfig.userSig} //此处判断横竖屏 开启不同页面展示 var url = `/pages/player/template/fullscreen/fullscreen`; wx.navigateTo({ url: url }); }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady: function () { }, /** * 生命周期函数--监听页面显示 */ onShow: function () { }, /** * 生命周期函数--监听页面隐藏 */ onHide: function () { }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh: function () { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom: function () { }, /** * 用户点击右上角分享 */ onShareAppMessage: function () { }})

4、在player文件夹中新建templete=>子文件fullscreen
fullscreen.wxml
<live-player id="player" src="http://mlive.yunjinji.cn/live/202004111017Test.flv" bindstatechange="statechange" binderror="error"> <cover-view> <cover-view class="btn-box"> <button bindtap="bindPlay" type="primary">播放</button> <button bindtap="bindPause" type="warn">暂停</button> <button bindtap="bindStop" type="warn">停止</button> <button bindtap="bindResume" type="primary">恢复</button> <button bindtap="bindMute" type="warn">静音</button> </cover-view> </cover-view></live-player><!-- 聊天信息 --><scroll-view scroll-y="{{true}}" scroll-top="{{scrollTop}}" class="msgs-wrapper"> <view class="msgs"> <!-- <view class="msgs" wx:for="{{msgs}}" wx:key="index"> --> <!-- <text class="msg-item"><text class="nickname">{{item.fromAccountNick}}</text> : {{item.content}}</text> --> <text class="msg-item" wx:key="{{item.time}}" wx:for="{{msgs}}"><text class="nickname">{{item.nickName}}</text>{{item.payload2==false?item.payload3==false?item.payload.text:'':':'+item.payload.text}}</text> </view></scroll-view><!-- 底部 --><view class="input-section"> <input adjust-position="{{true}}" value="{{msgContent}}" confirm-type="send" placeholder="" bindinput="bindInput" bindconfirm="bindConfirm" /> <!-- <button class="love" bindtap="bindTap"> </button> --> <button class="love" data-value="{{msgContent}}" bindtap="bindConfirm"></button></view><!-- rtmp://58.200.131.2:1935/livetv/hunantv -->
fullscreen.wxss
page{ height: 100%; box-sizing: border-box; overflow: hidden;}.btn-box{ display: flex; margin-top:40rpx;} .btn-box button{ margin-bottom: 30rpx; flex:1; font-size: 24rpx; padding: 0; margin:0 20rpx;}live-player { width: 100%; height: 100%; position:relative;}/* //聊天 */.msgs-wrapper { position: absolute; bottom: 100rpx; left: 10rpx; right: 10rpx; height: 400rpx; overflow: hidden; overflow-y: auto;}.msgs { max-width: 80%; display: block; padding: 5rpx; color: #ffffff; margin: 5rpx 0; word-wrap: break-word; width: 430rpx;}.msg-item { padding: 8rpx 5rpx; display: block; font-size: 14px; background:rgba(0,0,0,1); opacity:0.4; border-radius:10rpx; margin: 10rpx 0;}.nickname { color: #ff7906}.input-section { position: absolute; bottom: 10rpx; left: 10rpx; right: 10rpx;}.input-section input { background: #fff; margin-right: 100rpx; padding: 10rpx;}.input-section .love { background: url(http://avc.qcloud.com/demo/webim/biggroup/mobile/img/like_hover.png); background-size: 100%; width: 70rpx; height: 70rpx; display: block; position: absolute; right: 10rpx; bottom: 0; border: 0; outline: 0;}.input-section .love:after { border: 0}
fullscreen.js
import { autoLogin, isLogin} from '../../../../api/im.js'import { hudong, playerFn} from './method.js'var app = getApp()Page({ data: { // identifier: '', // 当前用户身份标识,必选 // userSig: '', // 当前用户签名,必选 nickName: '', // 当前用户昵称,选填 // avChatRoomId: CONFIG.avChatRoomId, // 群ID, 必选 // motto: 'Hello World', msgs: [],//消息数据 playerName:'LOL直播间',//直播间昵称 msgContent: "",//文本内容 uid:'',//自己id scrollTop:100, togroup:'@TGS#aXV66ILGG'//群聊id }, onReady(res) { this.ctx = wx.createLivePlayerContext('player') }, // 聊天室 ...hudong, //按钮 ...playerFn, //加载 onLoad: function (options) { var that=this //加入群聊室 that.joinGroup(this.data.togroup).then(res => { console.log('joinGroup') console.log(res) if(res.code===0){ // + that.data.playerName let msgobj = { nickName: '欢迎来到直播间!直播内容和评论严禁包含政治,低俗色情,吸烟酗酒等内容,如若违反,将视情节严重程度给予禁播,永久禁播或封停账号处理!',//昵称 payload2: false //控制内容一级(:)是否显示 } let msgarr = that.data.msgs msgarr.push(msgobj) that.setData({ msgs: msgarr }) //滚动 that.scrollFn() } // let msg = '欢迎进入' + data.payload.groupProfile.name // let msgobj = { // nickName: msg,//昵称 // payload: false //控制内容一级(:)是否显示 // } // let msgarr = that.data.msgs // msgarr.push(msgobj) // that.setData({ // msgs: msgarr // }) }) //监听群消息 app.IM.tim.on(app.IM.TIM.EVENT.MESSAGE_RECEIVED,that.onMessageReceived); }, //显示 onShow:function(){ console.log('onShow') // setTimeout(()=>{ // if (isLogin()) {//查看im是否登录 this.setData({ nickName: wx.getStorageSync("phone"), uid: wx.getStorageSync("uid") }) // } // },2000) }, //卸载 onUnload:function(){ app.IM.tim.off(app.IM.TIM.EVENT.MESSAGE_RECEIVED, this.onMessageReceived); this.quitGroup(this.data.togroup) } })
5、新建method.jsimport { autoLogin, isLogin} from '../../../../api/im.js'const IM = require('../../../../api/im.js')//播放function bindPlay() { this.ctx.play({ success: res => { console.log('播放成功') console.log(res) }, fail: res => { console.log('播放失败,失败原因' + res.errMsg) } })}//暂停function bindPause() { this.ctx.pause({ success: res => { console.log('暂停成功') }, fail: res => { console.log('暂停失败,失败原因' + res.errMsg) } })}//停止function bindStop() { this.ctx.stop({ success: res => { console.log('停止成功') }, fail: res => { console.log('停止失败,失败原因' + res.errMsg) } })}//恢复function bindResume() { this.ctx.resume({ success: res => { console.log('恢复成功') }, fail: res => { console.log('恢复失败,失败原因' + res.errMsg) } })}//静音function bindMute() { this.ctx.mute({ success: res => { console.log('静音成功') }, fail: res => { console.log('静音失败,失败原因' + res.errMsg) } })}const hudong = { //监听消息 onMessageReceived: function(event) { console.log(event) let data = event.data[0] //判断是否刚刚进来聊天室 let names = data.payload.operatorID let iD = data.ID let froms = data.from //消息来自哪里 @TIM#SYSTEM(系统) let isSystemMessage = data.isSystemMessage let isower = (this.data.uid != names) let groupJoinType = data.payload.groupJoinType //没有登陆时自己的groupJoinType为0,其他人登录进来为1 if (names != undefined && names != "" && !isSystemMessage && isower && froms == '@TIM#SYSTEM' && groupJoinType!=0) { //别人进直播间 console.log('11111111111111111111111111111111111111111') let msgobj = { nickName:names, //昵称 payload2:false, payload3:false, payload:{ text:'来了' }, } let msgarr = this.data.msgs msgarr.push(msgobj) this.setData({ msgs: msgarr }) //滚动 this.scrollFn() } // if (isSystemMessage) { //自己刚进入聊天系统提示 // console.log('2222222222222222222') // let playenmae = data.payload.groupProfile.name //直播间昵称 // let msgobj = { // nickName: '欢迎进入' + playenmae + '直播间', //昵称 // payload: false // } // let msgarr = this.data.msgs // msgarr.push(msgobj) // this.setData({ // msgs: msgarr // }) // } if (isower && froms != '@TIM#SYSTEM' && froms != this.data.uid) { console.log('33333333333333') let msgobj = { nickName: event.data[0].from, //昵称 payload: event.data[0].payload //消息 } let msgsarr = this.data.msgs msgsarr.push(msgobj) this.setData({ msgs: msgsarr }) //滚动 this.scrollFn() } }, // 发送消息 bindConfirm: function(e) { if (isLogin()) { //查看im是否登录 if (this.data.msgContent != '') { let data = { msg: this.data.msgContent, togroup: this.data.togroup } this.textMessages(data).then(res => { console.log(this.data.msgContent) console.log(res) if (res.code === 0) { res.data.message.nickName = this.data.nickName //获取当前用户昵称 let list = res.data.message let msgs = this.data.msgs msgs.push(list) this.setData({ msgs: msgs }) this.cleartxFn() //滚动 this.scrollFn() } }) } }else{ wx.navigateTo({ url:'/pages/login/login' }) } }, //清除文本内容 cleartxFn: function() { this.setData({ msgContent: '' }) }, //初始化SDK功能 onSdkReady() { // return new Promise((resolve, reject) => { let onSdkReady = function(event) { let message = tim.createTextMessage({ to: '@TGS#aXV66ILGG', //groupID conversationType: TIM.TYPES.CONV_GROUP, //会话类型,取值TIM.TYPES.CONV_C2C(端到端会话) 或 TIM.TYPES.CONV_GROUP(群组会话) payload: { text: 'Hello world!' //消息 } }); tim.sendMessage(message); }; // }) tim.on(TIM.EVENT.SDK_READY, onSdkReady); }, //发送群消息 /* msg@@@===发送的内容消息 togroup@@@===直播间群组id */ textMessages({ msg, togroup }) { // 发送文本消息,Web 端与小程序端相同 // 1. 创建消息实例,接口返回的实例可以上屏 let message = IM.tim.createTextMessage({ to: togroup, conversationType: IM.TIM.TYPES.CONV_GROUP, // 消息优先级,用于群聊(v2.4.2起支持)。如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考:https://cloud.tencent.com/document/product/269/3663#.E6.B6.88.E6.81.AF.E4.BC.98.E5.85.88.E7.BA.A7.E4.B8.8E.E9.A2.91.E7.8E.87.E6.8E.A7.E5.88.B6) // 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST // priority: TIM.TYPES.MSG_PRIORITY_NORMAL, payload: { text: msg } }); // 2. 发送消息 return IM.tim.sendMessage(message); }, //加入聊天室 /* group@@@===直播间群组id */ joinGroup(group) { return IM.tim.joinGroup({ groupID: group, type: IM.TIM.TYPES.GRP_AVCHATROOM }); }, //退出群组 /* group@@@===直播间群组id */ quitGroup(group) { let promise = IM.tim.quitGroup(group); promise.then(function(imResponse) { console.log(imResponse.data.groupID); // 退出成功的群 ID }).catch(function(imError) { console.warn('quitGroup error:', imError); // 退出群组失败的相关信息 }); }, //滚动 scrollFn(){ let msgs = this.data.msgs let top=msgs.length*60 this.setData({ scrollTop: top }) }, //监听输入框 bindInput(e){ this.setData({ msgContent:e.detail.value }) }}const playerFn={ inputFocus(e) { console.log(e, '键盘弹起') var inputHeight = 0 if (e.detail.height) { inputHeight = e.detail.height } }, inputBlur() { console.log('键盘收起') }, statechange(e) { let types = { '2001': '已经连接服务器', '2002': '已经连接 RTMP 服务器,开始拉流', '2003': '网络接收到首个视频数据包(IDR)', '2004': '视频播放开始', '2005': '视频播放进度', '2006': '视频播放结束', '2007': '视频播放Loading', '2008': '解码器启动', '2009': '视频分辨率改变', '-2301': '网络断连,且经多次重连抢救无效,更多重试请自行重启播放', '-2302': '获取加速拉流地址失败', '2101': '当前视频帧解码失败', '2102': '当前音频帧解码失败', '2103': '网络断连, 已启动自动重连', '2104': '网络来包不稳:可能是下行带宽不足,或由于主播端出流不均匀', '2105': '当前视频播放出现卡顿', '2106': '硬解启动失败,采用软解', '2107': '当前视频帧不连续,可能丢帧', '3001': 'RTMP -DNS解析失败', '3002': 'RTMP服务器连接失败', '3003': 'RTMP服务器握手失败', '3005': 'RTMP 读/写失败' } console.log('live-player code:', e.detail.code, '==========', types[e.detail.code]) }, error(e) { console.error('live-player error:', e) },}export { bindPlay, bindPause, bindStop, bindResume, bindMute, hudong, playerFn}
