一、前言
IM即时通讯(Instant Messaging),实时通信系统,允许二人或多人使用网络实时的传递文字消息、文件、语音或视频交流。美家技术团队在项目早期中应用到了环信IM,其中踩了不少坑。
后面随着业务的扩展已经产品的迭代,该IM聊天咨询功能已不能满足需求,至少在该基础上仅有的文字聊天满足不了。需求还涉及到自定义消息,系统消息,未读消息等等。在此基础上,简单对比了两款产品的优劣。
二、腾讯云IM和环信IM应用比较 IM平台厂家通信方式易用性扩展性客服引用方式在线文档手册腾讯云IM腾讯polling 轮询易,文档详实,包含相应的短视频介绍,实例丰富丰富,自定义消息,系统消息,未读消息在线工单npm 包模块产品手册 (https://main.qcloudimg.com/raw/document/product/pdf/269_1497_cn.pdf)在线文档(https://cloud.tencent.com/document/product/269/37413)环信IM北京易掌云峰科技有限公司websocket较难,文档及案例较简单,建立链接后需要手动处理的逻辑复杂较少在线客服手动copy脚步到项目下,import在线文档
(http://docs-im.easemob.com/im/applet/intro)
三、腾讯云IM使用文档
四、TIM 在 uni-app 中应用
tim 初始化应用Example
tim运行提示登陆tim账号tim.login({userID:’youruserID’,userSig:’youruserSig’});
tim 登录成功,并认证成功
tim运行提示SDK is ready,此监听事件,回调函数中后面可以调用 sendMessage(发送消息) 等需要鉴权的接口//监听ready事件tim.on(TIM.EVENT.SDK_READY,function(event){//收到离线消息和会话列表同步完毕通知,接入侧可以调用sendMessage等需要鉴权的接口//event.name-TIM.EVENT.SDK_READY});
tim运行提示通过轮询收发实时信息
tim运行提示进入聊天界面,发送文字,表情正常
tim运行提示选取图片,发送报错,如何解决h5发送图片报错问题,也就解决了tim在uniapp中的兼容性
tim运行提示
解决 uni-app 在h5中使用 TIM 发送图片失败的问题
//以下两个对象uni和wx比较,返回true,即为同一个对象uni===wx
tim运行分析
tim运行分析
tim运行提示
下文提到的代码行数,均指格式化后的源代码行数
分析如下:
分析源码
由该格式可得,此为 umd 通用模块定义, 即为多种模块组合
!(function(window,factory){if(‘object’==typeofexports&&’undefined’!=typeofmodule){//CommonJS模式module.exports=factory()}elseif(‘function’==typeofdefine&&define.amd){//RequireJS模式define(factory)}else{//IIFEwindow.TIM=factory()}}(this,(function(){//***省略逻辑代码//返回Objectreturn{…}}))
继续往下阅读,基本就是一些函数定义,暂时识别不出有意义部分。回到 TIM 的警告和报错提示
分析源码
格式化源码文档中搜索 createImageMessage payload.file 的类型必须是 HTMLInputElement 或 File,大概 6115 行,找到信息,结合报错提示 TIM [createImageMessage] Invalid params: custom validator check failed for params.
源码分析
wx.chooseImage({sourceType:[name],count:1,success:function(res){message=wx.$app.createImageMessage({//创建图片消息to:self.$store.getters.toAccount,conversationType:self.$store.getters.currentConversationType,payload:{file:res},onProgress:percent=>{self.percent=percent}})self.$store.commit(‘sendMessage’,message)wx.$app.sendMessage(message).then(()=>{self.percent=0}).catch((err)=>{console.log(err)})}})
综上, tim 创建图文消息的 payload.file 参数类型错误,该图片的文件类型是从 wx.chooseImage 中返回,一般不能更改。回到源码分析,第 6113 行,此处变量 ws 的布尔类型为 true ,才会执行报错提示代码,因此需要搜索变量 ws 所定义的位置,(小技巧,搜索的时候添加一个后面的空格,即“ws”)
源码分析
搜索得到8个结果,找到变量定义地方
回到上面截图,源码分析,第6113行,变量 ws 为浏览器环境,正确,结合error log信息,
TIM [createImageMessage] Invalid params: custom validator check failed for params.,
源码分析
源码分析
分析源码
依然是之前的错误,文件参数校验失败问题,原因分析:调用 tim 方法 createImageMesssage 发送图片消息, 上面关键代码wx.chooseImage,wx.$app.createImageMessage先选择图片,再创建 tim 图片消息,
wx.chooseImage({sourceType:[name],count:1,success:function(res){//此处选取的文件格式res可能就已经不是单纯的h5环境的文件图片格式message=wx.$app.createImageMessage({//创建图片消息to:self.$store.getters.toAccount,conversationType:self.$store.getters.currentConversationType,payload:{file:res//wx.chooseImage获取图片的格式传入createImageMessage并非h5的文件格式}})self.$store.commit(‘sendMessage’,message)wx.$app.sendMessage(message).then(()=>{self.percent=0}).catch((err)=>{console.log(err)})}})
整个项目使用uni-app构建,那么就不是只有 tim 中的 h5 sdk 使用到了 wx,可以说,整个项目中的 wx 全局都被 uni 劫持代理,上面的 wx.chooseImage 将选择的图片格式包装了一层,不是原生的h5文件对象。打印 wx.chooseImage 选项的图片对象,
源码分析
h5文件对象的格式
源码分析
窘,虽说 tim sdk 内部已修改了逻辑,但是调用 tim.createImageMessasge 的时候并不能保证传入的参数(wx.chooseImage所得,回调中的参数并不是完全的h5文件对象(HTMLInputElement或File))能通过校验。到此,有两个修改方向
第二种情况,只修改 tim 的 h5 sdk,并不涉及页面的逻辑处理。先按此思路实现。
撤销源码第 2555 行变量 Ns 的修改
,Ns=”undefined”!=typeofwx&&”function”==typeofwx.getSystemInfoSync
变量 ws 确实为浏览器环境,为让 createImageMessage 的参数校验器通过,因此将 ws 条件判断注释掉,如下代码所示,因为 wx.chooseImage 方法的传参不能满足该校验器。
{…,createImageMessage:{to:{type:”String”,required:!0},conversationType:{type:”String”,required:!0},payload:{type:”Object”,required:!0,validator:function(e){if(va(e.file))returnconsole.warn(“createImageMessage payload.file 不能为 undefined。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage”),!1;//if(ws){//if(!(e.fileinstanceofHTMLInputElement||pa(e.file)))// return console.warn(“createImageMessage payload.file 的类型必须是 HTMLInputElement 或 File。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage”),//!1;//if(e.fileinstanceofHTMLInputElement&&0===e.file.files.length)// return console.warn(“createImageMessage 您没有选择文件,无法发送。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage”),//!1//}return!0},onProgress:{type:”Function”,required:!1,validator:function(e){returnva(e)&&console.warn(“createImageMessage 没有 onProgress 回调,您将无法获取图片上传进度。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage”),!0}}}},…}
源码分析
Blob 对象表示一个不可变、原始数据的类文件对象。图中的报错提示
n: 只允许上传 jpg png jpeg gif 格式的图片
该格式的判断有可能是根据文件的扩展名称而来。因此,回归到代码 tim.createImageMessage 方法的调用,关键代码
源码分析
比较分析
//代入上面的变量n,变量r的值为字符串blob:http://172.18.10.159/2e507f2d-b2a8-4d7c-930a-81eddcbd97ce//对象o的属性type的值为r.slice(r.lastIndexOf(“.”) 1).toLowerCase(),代入处理得’159/2e507f2d-b2a8-4d7c-930a-81eddcbd97ce’varr=n.tempFilePaths[0];,o={url:r,name:r.slice(r.lastIndexOf(“/”) 1),size:n.tempFiles[0].size,type:r.slice(r.lastIndexOf(“.”) 1).toLowerCase()};
此处type的值为 ‘159/2e507f2d-b2a8-4d7c-930a-81eddcbd97ce’,显然不是正常图片的格式
因此 o.type 修改为 n.tempFiles[0].type,调整后运行结合提示 n: 只允许上传 jpg png jpeg gif 格式的图片
最终修改为 n.tempFiles[0].type.split(‘/’)[1]
代码如下:
varr=n.tempFilePaths[0],o={url:r,name:r.slice(r.lastIndexOf(“/”) 1),size:n.tempFiles[0].size,//type:r.slice(r.lastIndexOf(“.”) 1).toLowerCase()//修改此处wx.chooseImage的fileblob对象路径没有后缀名,所以用了对应n.tempFiles[0]的type类型,截取获得后缀type:n.tempFiles[0].type.split(‘/’)[1]};
源码分析
源码分析
或者根据提示直接打开源代码第 18983 行
{{key:”uploadImage”,//定义上传图片方法value:function(e){if(!e.file)//判断入参returnid(newSp({code:Ep.MESSAGE_IMAGE_SELECT_FILE_FIRST,message:qp}));vart=this._checkImageType(e.file);//检查图片类型if(!0!==t)returnt;varn=this._checkImageMime(e.file);//检查图片Mine类型if(!0!==n)returnn;varr=this._checkImageSize(e.file);//检查图片大小return!0!==r?r:this.upload(e)//上传}},{key:”_checkImageType”,//定义图片类型检查方法value:function(e){vart=””;//变量Ns为true//e.url值为blob:http://172.18.10.159/2e507f2d-b2a8-4d7c-930a-81eddcbd97ce,因此该处逻辑判段出了问题//t为159/2e507f2d-b2a8-4d7c-930a-81eddcbd97ce//Of从源码搜索出为Of=[“jpg”,”jpeg”,”gif”,”png”]//最后returnfalsereturnt=Ns?e.url.slice(e.url.lastIndexOf(“.”) 1):e.files[0].name.slice(e.files[0].name.lastIndexOf(“.”) 1),Of.indexOf(t.toLowerCase())>=0||id(newSp({coe:Ep.MESSAGE_IMAGE_TYPES_LIMIT,message:Fp}))}}}
源码分析
此处依然是上传图片类型问题错误导致,上面提到上传对象 e 的 url 为 blob 类型字符串,因此不能通过该 url 值获取图片类型,
需要修改为 e.type,
即源码 18996 行代码修改为:
return t = Ns ? e.url.slice(e.url.lastIndexOf(“.”) 1) : e.files[0].name.slice(e.files[0].name.lastIndexOf(“.”) 1),
return t = Ns ? e.type : e.files[0].name.slice(e.files[0].name.lastIndexOf(“.”) 1),
上传图片成功!!
源码分析总结 tim 修改的三处地方源码 6113 附近, 放弃 tim.createImageMessage 对原生h5文件的类型校验,已注释掉//*************************BEGIN第一处修改BEGIN***********************************//if(ws){//if(!(e.fileinstanceofHTMLInputElement||pa(e.file)))// return console.warn(“createImageMessage payload.file 的类型必须是 HTMLInputElement 或 File。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage”),//!1;//if(e.fileinstanceofHTMLInputElement&&0===e.file.files.length)// return console.warn(“createImageMessage 您没有选择文件,无法发送。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage”),//!1//}//*************************BEGIN第一处修改BEGIN***********************************修改并重新获取 tim.createImageMessage 上传图片类型,源码 13964 行附近//*************************BEGIN第二处修改BEGIN***********************************//type:r.slice(r.lastIndexOf(“.”) 1).toLowerCase()//修改此处wx.chooseImage的fileblob对象路径没有后缀名,所以用了对应n.tempFiles[0]的type类型,截取获得后缀type:n.tempFiles[0].type.split(‘/’)[1]//*************************BEGIN第二处修改BEGIN***********************************修改上传图片前的图片文件类型校验,源码 19002 行附近//*************************BEGIN第三处修改BEGIN***********************************//returnt=Ns?e.url.slice(e.url.lastIndexOf(“.”) 1):e.files[0].name.slice(e.files[0].name.lastIndexOf(“.”) 1),returnt=Ns?e.type:e.files[0].name.slice(e.files[0].name.lastIndexOf(“.”) 1),//*************************END第三处修改END***************************************
适用于 uni-app 的h5腾讯云IM tim sdk,解决对话中的图片发送问题,去下载(http://3vj-vda.3vjia.com/meijia_oss_pro/static/wangpu/h5/tim-js.js)
总结
遇到问题,结合项目,具体分析根据 warn、error 提示,定位目标代码,分析关键代码,推测原因文档资料查阅,对比结果(意料或意外),分析其中的差异性验证,整理结果
当然,实际工作过程中,遇到的问题肯定比本文所列举的还要多,本文有点啰嗦,希望在遇到问题时能抛砖引玉。
参考资料
腾讯云IM(https://cloud.tencent.com/document/product/269/37413)
uni-app(https://uniapp.dcloud.io/README)
MDN web docs(https://developer.mozilla.org/zh-CN/docs/Web/API/Blob)