uni-app多端兼容IM掏心实战

一、前言

IM即时通讯(Instant Messaging),实时通信系统,允许二人或多人使用网络实时的传递文字消息、文件、语音或视频交流。美家技术团队在项目早期中应用到了环信IM,其中踩了不少坑。

  • 早期技术选型中,通信两端采用不同的前端技术体系,面向B端的采用了 mpvue,面向C端用户使用了原生微信小程序开发,因此当时遇到了大坑,环信的小程序版(原生)sdk 不适合 mpvue(vue),改造sdk根本不现实,文件依赖引用太多了,改不动[旺柴]。最后的改造方案是聊天IM页面依然使用原生微信小程序,混合mpvue使用,实现了B、C端的通信。
  • 引入该 sdk 极易导致微信小程序主包过大(小程序主包2M限制),只能将该sdk单独分包
  • 每次修改了涉及IM的部分,必须重新运行编译,热刷新不生效

2019.7 C端逛逛美家使用uniapp重构,又遇到了一大问题,环信IM小程序sdk,在uniapp中的并非完全适用,经历再次改造。原生小程序的页面不能用,此处改成了vue,通信websocket建立起来了,B端能发消息,C端能收到;C端发的消息,然而B端却收不到。最后还是把C端的聊天界面全部推到,重新编写才能收发消息。此处只支持文本发送,像视频,图片,语音,定位等的功能都屏蔽了,因为需要改造对应的环信sdk小程序组件。最后变成了阉割版的文字聊天。

后面随着业务的扩展已经产品的迭代,该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使用文档

本文略,详情请查看 即时通信 IM 集成 SDK(Web & 小程序)(https://cloud.tencent.com/document/product/269/37413)

四、TIM 在 uni-app 中应用

tim 初始化应用Example

// #ifdef MP-WEIXIN || APP-PLUS
// 小程序、App端使用该sdk
import TIMWX from 'tim-wx-sdk';
// #endif

// #ifdef H5
// uniapp h5版本的微信小程序SDK上传图片出现问题,不能兼容,需要单独修改
import TIMH5 from '@/static/h5/tim-wx-sdk/tim-js';
// #endif

let TIM = null;
// #ifdef MP-WEIXIN || APP-PLUS
TIM = TIMWX;
// #endif
// #ifdef H5
TIM = TIMH5;
// #endif

import COS from 'cos-wx-sdk-v5';

// 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例
let options = {
  SDKAppID0 // 接入时需要将0替换为您的即时通信应用的 SDKAppID
};
let tim = TIM.create(options); // SDK 实例通常用 tim 表示
// 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明
tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用
// tim.setLogLevel(1); // release级别,SDK 输出关键信息,生产环境时建议使用

// 将腾讯云对象存储服务 SDK (以下简称 COS SDK)注册为插件,IM SDK 发送文件、图片等消息时,需要用到腾讯云的 COS 服务
// HTML5 环境,注册 COS SDK
tim.registerPlugin({'cos-js-sdk': COS});

// 微信小程序环境,注册 COS SDK
//tim.registerPlugin({'cos-wx-sdk': COS}); // 微信小程序环境请取消本行注释,并注释掉 tim.registerPlugin({'cos-js-sdk': COS});

// 监听事件,如:
tim.on(TIM.EVENT.SDK_READY, function(event{
  // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
  // event.name - TIM.EVENT.SDK_READY
});

tim.on(TIM.EVENT.MESSAGE_RECEIVED, function(event{
  // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
  // event.name - TIM.EVENT.MESSAGE_RECEIVED
  // event.data - 存储 Message 对象的数组 - [Message]
});

tim.on(TIM.EVENT.MESSAGE_REVOKED, function(event{
  // 收到消息被撤回的通知。使用前需要将SDK版本升级至v2.4.0或以上。
  // event.name - TIM.EVENT.MESSAGE_REVOKED
  // event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isRevoked 属性值为 true
});

tim.on(TIM.EVENT.MESSAGE_READ_BY_PEER, function(event{
  // SDK 收到对端已读消息的通知,即已读回执。使用前需要将SDK版本升级至v2.7.0或以上。仅支持单聊会话。
  // event.name - TIM.EVENT.MESSAGE_READ_BY_PEER
  // event.data - event.data - 存储 Message 对象的数组 - [Message] - 每个 Message 对象的 isPeerRead 属性值为 true
});

tim.on(TIM.EVENT.CONVERSATION_LIST_UPDATED, function(event{
  // 收到会话列表更新通知,可通过遍历 event.data 获取会话列表数据并渲染到页面
  // event.name - TIM.EVENT.CONVERSATION_LIST_UPDATED
  // event.data - 存储 Conversation 对象的数组 - [Conversation]
});

tim.on(TIM.EVENT.GROUP_LIST_UPDATED, function(event{
  // 收到群组列表更新通知,可通过遍历 event.data 获取群组列表数据并渲染到页面
  // event.name - TIM.EVENT.GROUP_LIST_UPDATED
  // event.data - 存储 Group 对象的数组 - [Group]
});

tim.on(TIM.EVENT.PROFILE_UPDATED, function(event{
  // 收到自己或好友的资料变更通知
  // event.name - TIM.EVENT.PROFILE_UPDATED
  // event.data - 存储 Profile 对象的数组 - [Profile]
});

tim.on(TIM.EVENT.BLACKLIST_UPDATED, function(event{
  // 收到黑名单列表更新通知
  // event.name - TIM.EVENT.BLACKLIST_UPDATED
  // event.data - 存储 userID 的数组 - [userID]
});

tim.on(TIM.EVENT.ERROR, function(event{
  // 收到 SDK 发生错误通知,可以获取错误码和错误信息
  // event.name - TIM.EVENT.ERROR
  // event.data.code - 错误码
  // event.data.message - 错误信息
});

tim.on(TIM.EVENT.SDK_NOT_READY, function(event{
  // 收到 SDK 进入 not ready 状态通知,此时 SDK 无法正常工作
  // event.name - TIM.EVENT.SDK_NOT_READY
});

tim.on(TIM.EVENT.KICKED_OUT, function(event{
  // 收到被踢下线通知
  // event.name - TIM.EVENT.KICKED_OUT
  // event.data.type - 被踢下线的原因,例如 :
  //   - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
  //   - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
  //   - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢(v2.4.0起支持)。
});

tim.on(TIM.EVENT.NET_STATE_CHANGE, function(event{
  // 网络状态发生改变(v2.5.0 起支持)。
  // event.name - TIM.EVENT.NET_STATE_CHANGE
  // event.data.state 当前网络状态,枚举值及说明如下:
  //   - TIM.TYPES.NET_STATE_CONNECTED - 已接入网络
  //   - TIM.TYPES.NET_STATE_CONNECTING - 连接中。很可能遇到网络抖动,SDK 在重试。接入侧可根据此状态提示“当前网络不稳定”或“连接中”
  //   - TIM.TYPES.NET_STATE_DISCONNECTED - 未接入网络。接入侧可根据此状态提示“当前网络不可用”。SDK 仍会继续重试,若用户网络恢复,SDK 会自动同步消息
});

wx.TIM = TIM;  // 绑定TIM到全局对象wx下 
wx.$app = tim; // 绑定tim到全局对象wx.$app下

// 开始登录
tim.login({userID'your userID'userSig'your userSig'});

uni-app支持将小程序、H5、Andorid/iOS编译打包到各平台,其中各平台均使用了IM通信功能,使用了腾讯云IM中的集成SDK(web&小程序), App 端和微信小程序均可使用小程序版 SDK

  • uni-app支持微信小程序版本,使用一般不存在问题。
  • App 中使用的问题正常,除了发送视频外,由于App中的视频使用的是原生组件,不能覆盖,滚动聊天面板的时候出现视频覆盖在内容上,影响体验效果。暂时也没有很好的解决方法,nvue的改造工作量大,先将IM聊天中的发送视频屏蔽。
  • h5 版本,小程序与h5的sdk还是有很大的区别,这里不使用小程序版,通过uni-app的条件编译使用h5版本tim-js
  1. 编写条件编译,区别小程序与h5中引用的sdk
  // #ifdef MP-WEIXIN || APP-PLUS
  // 小程序、App端使用该sdk
  import TIMWX from 'tim-wx-sdk';
  // #endif

  // #ifdef H5
  // uniapp h5版本的微信小程序SDK上传图片出现问题,不能兼容,需要单独修改
  import TIMH5 from '@/static/h5/tim-wx-sdk/tim-js';
  // #endif
  1. 编译运行到h5,tim 初始化成功
uni-app多端兼容IM掏心实战
tim运行提示
  1. 登陆tim账号
  tim.login({userID'your userID'userSig'your userSig'});

tim 登录成功,并认证成功

uni-app多端兼容IM掏心实战
tim运行提示
  1. SDK is ready,此监听事件,回调函数中后面可以调用 sendMessage(发送消息) 等需要鉴权的接口
// 监听ready事件
tim.on(TIM.EVENT.SDK_READY, function(event{
  // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
  // event.name - TIM.EVENT.SDK_READY
});
uni-app多端兼容IM掏心实战
tim运行提示
  1. 通过轮询收发实时信息
uni-app多端兼容IM掏心实战
tim运行提示
  1. 进入聊天界面,发送文字,表情正常
uni-app多端兼容IM掏心实战
tim运行提示
  1. 选取图片,发送报错如何解决h5发送图片报错问题,也就解决了tim在uniapp中的兼容性
uni-app多端兼容IM掏心实战
tim运行提示

uni-app的app端其实是一个强化版的小程序引擎,所以支持小程序sdk在app端使用。但这些sdk在h5端、支付宝百度等小程序平台无法使用

解决 uni-app 在h5中使用 TIM 发送图片失败的问题

正常来说,腾讯云IM提供了小程序版以及h5版本的SDK,同时 uni-app 使用了条件编译区分了该两个不同环境下所使用的SDK,那么为什么h5还出现发送图片失败? 原因是由于TIM的全局对象wxuni-app 全局对象uni所代理,是同一个对象,即有

  // 以下两个对象uni和wx比较,返回true,即为同一个对象
  uni === wx
uni-app多端兼容IM掏心实战
tim运行分析

因此当 tim 的sdk判断当前运行环境(小程序还是h5环境)会出现问题(下文会贴代码),wx 已经不再是原来的单纯的那个对象,而是注入了 uni 对象的各种方法

uni-app多端兼容IM掏心实战
tim运行分析
uni-app多端兼容IM掏心实战
tim运行提示

由于该SDK不开源,找不到源码,只有压缩过后的js文件,h5 TIM SDK 地址(https://github.com/tencentyun/TIMSDK/blob/master/H5/sdk/tim-js.js)格式化该文件,(格式化后的文件行数及变量名可能不同)

下文提到的代码行数,均指格式化后的源代码行数

分析如下:

uni-app多端兼容IM掏心实战
分析源码

由该格式可得,此为 umd 通用模块定义, 即为多种模块组合

  !(function (window, factory{
    if ('object' == typeof exports && 'undefined' != typeof module) {
      // CommonJS 模式
      module.exports = factory()
    } else if ('function' == typeof define && define.amd) {
      // RequireJS 模式
      define(factory)
    } else {
      // IIFE
      window.TIM = factory()
    }
  }(this, (function (){
    // *** 省略逻辑代码
    // 返回Object
    return {
      ...
    }
  }))

继续往下阅读,基本就是一些函数定义,暂时识别不出有意义部分。回到 TIM 的警告和报错提示

uni-app多端兼容IM掏心实战
分析源码

格式化源码文档中搜索 createImageMessage payload.file 的类型必须是 HTMLInputElement 或 File,大概 6115 行,找到信息,结合报错提示 TIM [createImageMessage] Invalid params: custom validator check failed for params.

uni-app多端兼容IM掏心实战
源码分析

以下为点击图片上传,调用TIM的创建图片消息逻辑代码

  wx.chooseImage({
    sourceType: [name],
    count1,
    successfunction (res{
      message = wx.$app.createImageMessage({ // 创建图片消息
        to: self.$store.getters.toAccount,
        conversationType: self.$store.getters.currentConversationType,
        payload: {
          file: res
        },
        onProgresspercent => {
          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”)

uni-app多端兼容IM掏心实战
源码分析

搜索得到8个结果,找到变量定义地方

uni-app多端兼容IM掏心实战
源码分析
var ws = "undefined" != typeof window
  , Ns = "undefined" != typeof wx && "function" == typeof wx.getSystemInfoSync
  , Ls = ws && window.navigator && window.navigator.userAgent || ""

// 上面使用关键字var同时定义多个变量,使用逗号分隔, 关键字 typeof 变量类型判断

// "undefined" != typeof window 判断是否为浏览器环境,window是浏览器宿主对象,true为浏览器环境,false为非浏览器环境,此处ws为true

// "undefined" != typeof wx && "function" == typeof wx.getSystemInfoSync,此处判断wx对象是否有定义,且wx.getSystemInfoSync是否为函数类型,true为小程序环境,false为非小程序环境,此处Ns变量为true

如上面所提到的,由于 wxuni 为同一个对象,导致 Ns 变量为true,即此处既是浏览器环境(ws),又是微信小程序环境(Ns),因此使用 Ns 判断的地方有可能会出现问题

回到上面截图,源码分析,第6113行,变量 ws 为浏览器环境,正确,结合error log信息,

TIM [createImageMessage] Invalid params: custom validator check failed for params.

结合 6113 行附近代码判断,此处代码为 tim 定义方法 createImageMessage 的函数参数校验器,推测错误原因应该是环境判断错误,可能是调用了小程序 wx 的专用方法(h5不支持), 因此需要继续查找真正定义方法 createImageMessage 的逻辑代码,继续搜索关键字 createImageMessage,得到关键信息

uni-app多端兼容IM掏心实战
源码分析

13950 行,此处使用了变量 Ns ,该变量表示微信小程序环境,由于开始的环境判断异常,导致h5中的某些程序代码走了小程序的逻辑,因此此处封装的小程序环境的参数payload.file与h5环境存在差异,不能通过 createImageMessage 方法参数校验。那么,直接修改变量 Nsfalse,是否就可以高枕无忧了?修改2555行变量 Nsfalse

uni-app多端兼容IM掏心实战
源码分析

重新点击发送图片[惊]

uni-app多端兼容IM掏心实战
分析源码

依然是之前的错误,文件参数校验失败问题,原因分析:调用 tim 方法 createImageMesssage 发送图片消息, 上面关键代码wx.chooseImagewx.$app.createImageMessage先选择图片,再创建 tim 图片消息,

 wx.chooseImage({
   sourceType: [name],
   count1,
   successfunction (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 选项的图片对象,

uni-app多端兼容IM掏心实战
源码分析

h5文件对象的格式

uni-app多端兼容IM掏心实战
源码分析

窘,虽说 tim sdk 内部已修改了逻辑,但是调用 tim.createImageMessasge 的时候并不能保证传入的参数(wx.chooseImage所得,回调中的参数并不是完全的h5文件对象(HTMLInputElement或File))能通过校验。到此,有两个修改方向

  1. 调用 wx.chooseImage 时,处理回调的参数 response 符合 h5 文件对象,类型是 HTMLInputElement 或 File
  2. 依旧走小程序逻辑,实际调用时才统一处理 payload.file 格式

看第一种解决方向,所有h5代码处,发送图文消息 createImageMessage 时,都需要去处理 payload.file 为原生h5文件格式,尤其是多端情况下, 兼容小程序以及App,代码量大,分散,易遗漏,暂不考虑。

第二种情况,只修改 timh5 sdk,并不涉及页面的逻辑处理。先按此思路实现。

回到代码处,变量 Ns 就不理解成微信小程序环境了,在此应该理解成统一封装了API的超集。

撤销源码第 2555 行变量 Ns 的修改

, Ns = "undefined" != typeof wx && "function" == typeof wx.getSystemInfoSync

变量 ws 确实为浏览器环境,为让 createImageMessage 的参数校验器通过,因此将 ws 条件判断注释掉,如下代码所示,因为 wx.chooseImage 方法的传参不能满足该校验器。

  {
    ...,
    createImageMessage: {
      to: {
          type"String",
          required: !0
      },
      conversationType: {
          type"String",
          required: !0
      },
      payload: {
          type"Object",
          required: !0,
          validatorfunction(e{
              if (va(e.file))
                  return console.warn("createImageMessage payload.file 不能为 undefined。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage"),
                  !1;
              // if (ws) {
              //     if (!(e.file instanceof HTMLInputElement || 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.file instanceof HTMLInputElement && 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,
              validatorfunction(e{
                  return va(e) && console.warn("createImageMessage 没有 onProgress 回调,您将无法获取图片上传进度。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage"),
                  !0
              }
          }
      }
    },
    ...
  }

重新点击图片上传,提示如下:

uni-app多端兼容IM掏心实战
源码分析

Blob 对象表示一个不可变、原始数据的类文件对象。图中的报错提示

n: 只允许上传 jpg png jpeg gif 格式的图片

该格式的判断有可能是根据文件的扩展名称而来。因此,回归到代码 tim.createImageMessage 方法的调用,关键代码

 {
    key"createImageMessage",
    valuefunction(e{
        e.currentUser = this.tim.context.identifier;
        var t = new Uf(e);
        if (Ns) {
            var n = e.payload.file;
            if (pa(n))
                return void la.warn("微信小程序环境下调用 createImageMessage 接口时,payload.file 不支持传入 File 对象");
            var r = n.tempFilePaths[0]
              , o = {
                url: r,
                name: r.slice(r.lastIndexOf("/") + 1),
                size: n.tempFiles[0].size,
                type: r.slice(r.lastIndexOf(".") + 1).toLowerCase()
            };
            e.payload.file = o
        } else if (ws && pa(e.payload.file)) {
            var i = e.payload.file;
            e.payload.file = {
                files: [i]
            }
        }
    }
  }

根据上面分析,Ns 布尔值为 true ,并且需要处理传入参数,显而易见,上面 var n = e.payload.file中的变量 n 即为 tim.createImageMessasge 入参,变量 n 的值其实就是点击图片选取时调用的 wx.chooseImage 的返回值

uni-app多端兼容IM掏心实战
源码分析

比较分析

 // 代入上面的变量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'
var r = 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]

代码如下:

 var r = 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的 file blob对象路径没有后缀名,所以用了对应n.tempFiles[0]的type类型,截取获得后缀
    type: n.tempFiles[0].type.split('/')[1]
  };

重新点击选取图片,报错依然

uni-app多端兼容IM掏心实战
源码分析

点击报错连接

uni-app多端兼容IM掏心实战
源码分析

或者根据提示直接打开源代码第 18983

{
  {
    key"uploadImage"// 定义上传图片方法
    value: function(e{
        if (!e.file) // 判断入参
            return id(new Sp({
                code: Ep.MESSAGE_IMAGE_SELECT_FILE_FIRST,
                message: qp
            }));
        var t = this._checkImageType(e.file); // 检查图片类型
        if (!0 !== t)
            return t;
        var n = this._checkImageMime(e.file); // 检查图片Mine类型
        if (!0 !== n)
            return n;
        var r = this._checkImageSize(e.file); // 检查图片大小
        return !0 !== r ? r : this.upload(e)  // 上传
    }
  },
  {
    key"_checkImageType"// 定义图片类型检查方法
    value: function(e{
        var t = "";
        // 变量 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"]
        // 最后 return false
        return t = 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(new Sp({
            coe: Ep.MESSAGE_IMAGE_TYPES_LIMIT,
            message: Fp
        }))
    }
  }
}

uni-app多端兼容IM掏心实战
源码分析

此处依然是上传图片类型问题错误导致,上面提到上传对象 eurlblob 类型字符串,因此不能通过该 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),

上传图片成功!!

uni-app多端兼容IM掏心实战
源码分析

总结 tim 修改的三处地方

  1. 源码 6113 附近, 放弃 tim.createImageMessage 对原生h5文件的类型校验,已注释掉
  // ************************* BEGIN 第一处修改  BEGIN***********************************
  // if (ws) {
  //     if (!(e.file instanceof HTMLInputElement || 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.file instanceof HTMLInputElement && 0 === e.file.files.length)
  //         return console.warn("createImageMessage 您没有选择文件,无法发送。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage"),
  //         !1
  // }
  // ************************* BEGIN 第一处修改  BEGIN***********************************
  1. 修改并重新获取 tim.createImageMessage 上传图片类型,源码 13964 行附近
  // ************************* BEGIN 第二处修改  BEGIN***********************************
  // type: r.slice(r.lastIndexOf(".") + 1).toLowerCase()
  // 修改此处 wx.chooseImage的 file blob对象路径没有后缀名,所以用了对应n.tempFiles[0]的type类型,截取获得后缀
  type: n.tempFiles[0].type.split('/')[1]
  // ************************* BEGIN 第二处修改  BEGIN***********************************
  1. 修改上传图片前的图片文件类型校验,源码 19002 行附近
  // ************************* BEGIN 第三处修改  BEGIN***********************************
  // 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),
  // ************************* END 第三处修改  END***************************************

适用于 uni-app 的h5腾讯云IM tim sdk,解决对话中的图片发送问题,去下载(http://3vj-vda.3vjia.com/meijia_oss_pro/static/wangpu/h5/tim-js.js) 

总结

此为项目中真实遇到的问题,使用 uni-app 开发多端项目H5,微信小程序,App(iOS/Android)应用,使用腾讯云IM作为聊天工具。使用腾讯云IM的(Web&小程序)sdk,其中h5版本不兼容。原因 uni-app 为兼容微信小程序开发,微信小程序专用全局对象 wxuni 代理劫持,开发者能直接使用 wx 而不报错, h5版本的 sdk 代码中仍有 wx 对象,某些逻辑h5和小程序环境混用。

  • 遇到问题,结合项目,具体分析
  • 根据 warnerror 提示,定位目标代码,分析关键代码,推测原因
  • 文档资料查阅,对比结果(意料或意外),分析其中的差异性
  • 验证,整理结果

当然,实际工作过程中,遇到的问题肯定比本文所列举的还要多,本文有点啰嗦,希望在遇到问题时能抛砖引玉。

参考资料

腾讯云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)


原文始发于微信公众号(三维家技术实践):uni-app多端兼容IM掏心实战

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/30686.html

(1)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!