uni接入腾讯IM—h5端 创建图片对象提示file传入的值必须是dom或file对象

4,015 阅读5分钟

最近公司想要做一个单对单咨询,有跨端的需求(小程序、h5),就用了uni app +腾讯IM
使用cli生成uni项目 利用环境变量区分h5跟小程序环境,分别加载了两套SDK
先说一下tim发送消息的流程

登录 => 初始化SDK => 拉取会话列表 => 根据会话列表ID拉取会话详情 => 选择图片
=> 创建图片对象createImageMessage(在这步会把本地的图片传到腾讯的服务器) => 将创建的图片对象发送出去

发送文字消息很顺利,一到发送图片,就步步坑

贴一下引入的代码 main.js

import Vue from 'vue'
import App from './App'

// 根据不同的开发环境引入不同的SDK
// #ifdef H5
import TIM from 'tim-js-sdk';
import COS from "cos-js-sdk-v5";
// #endif
// #ifdef MP-WEIXIN
import TIM from 'tim-wx-sdk';
import COS from "cos-wx-sdk-v5";
// #endif

// 初始化TIM
let options = {
   SDKAppID: SDKAPPID
}
let tim = TIM.create(options)
wx.$app = tim

// #ifdef H5
wx.$app.registerPlugin({ 'cos-js-sdk': COS })
// #endif
// #ifdef MP-WEIXIN
wx.$app.registerPlugin({ 'cos-wx-sdk': COS })
// #endif

App.mpType = 'app'
const app = new Vue({
   store,
   ...App
})
app.$mount()

遇到的问题

h5端无法发送图片 创建图片对象提示file传入的值必须是dom或file对象

根据uni-app的文档,chooseImage选择图片后,在h5端会返回tempFiles值是file对象,但我打印了返回值之后并不是 file,而是一个包含了路径跟类型的object,在TIM的SDK中,检验了参数类型
同时Uni-app 没有input[type="file"] 所以也无法传入HTML节点

为了这个问题抓了好几天头,之后发现tempFiles 在新版才会返回file对象,于是去更新项目中的版本依赖,不过为什么通过cli生成的项目。依赖会是旧版的。。。

把图片上所有2.0.0-26920200409002依赖全部替换成2.0.0-26920200424005,重新运行npm i
再次运行项目,打印的时候就会发现tempFiles的值变成了file对象

问题解决

微信小程序环境下调用 createImageMessage 接口时,payload.file 不支持传入 File 对象

正当我以为问题解决了,掉了的头发有回报的时候,第二个问题出现了

一开始怀疑是不是sdk引入错误了,只加载js-sdk,也会报这个错误,后来发现在这两个SDK中都有这句话判断

// tim-js-sdk
{
      key: "createImageMessage",
      value: function(e) {
        e.currentUser = this.tim.context.identifier;
        var t = new Vh(e);
        if (ba) {
          var n = e.payload.file;
          // ls方法判断了传入的对象是否是file 是file就会报异常
          if (ls(n)) return void cs.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 (Ra && ls(e.payload.file)) {
          var i = e.payload.file;
          e.payload.file = {
            files: [i]
          }
        }
        var a = new Ml({
          imageFormat: "UNKNOWN",
          uuid: this._generateUUID(),
          file: e.payload.file
        });
        return t.setElement(a),
        this.messageOptionMap.set(t.messageID, e),
        t
      }
    }

这就很令人窒息。。第一个报错提示让我一定要传入file文件,第二个提示让我不能传入file文件。。那应该传什么

没办法了 从源码上动刀吧
为了尽量靠近小程序的传递方式,我修改了源码中对图片的检测,把传入file的检测去掉了,改成了传入完整的chooseimage的回调,与小程序的传参保持一致

第一步要做的就是修改入参的检测,就是要修改遇到的第一个问题

// tim-js
// 格式化后5508行
payload: {
    type: "Object",
    required: !0,
    validator: function (e) {
      if (ms(e.file)) return console.warn("createImageMessage payload.file 不能为 undefined。请参考 https://imsdk-1252463788.file.myqcloud.com/IM_DOC/Web/SDK.html#createImageMessage"),
        !1;
      if (Ra) {
        // 去掉file类型的检测
        // if (!(e.file instanceof HTMLInputElement || ls(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
    }
  }

去掉类型检测后,再修改一下创建图片对象的部分

// tim-js
// 格式化后12200行
{
  key: "createImageMessage",
  value: function (e) {
    e.currentUser = this.tim.context.identifier;
    var t = new Vh(e);
    if (ba) {
      var n = e.payload.file;
      if (ls(n)) return void cs.warn("微信小程序环境下调用 createImageMessage 接口时,payload.file 不支持传入 File 对象");
      var r = n.tempFilePaths[0],
        o = {
          url: r,
          name: r.slice(r.lastIndexOf("/") + 1),
          size: n.tempFiles[0].size,
          // 修改此处 chooseimage的file对象路径没有后缀名,所以用了他的type类型,截取获得后缀
          type: n.tempFiles[0].type.split('/')[1]
          // type: r.slice(r.lastIndexOf(".") + 1).toLowerCase()
        };
      e.payload.file = o
    } else if (Ra && ls(e.payload.file)) {
      var i = e.payload.file;
      e.payload.file = {
        files: [i]
      }
    }
    var a = new Ml({
      imageFormat: "UNKNOWN",
      uuid: this._generateUUID(),
      file: e.payload.file
    });
    return t.setElement(a),
      this.messageOptionMap.set(t.messageID, e),
      t
  }
},

上面有几个地方固定了下标为0,因为uni-app的图片选择暂时只支持单张,所以写死下标可行,目前使用来说没发现什么问题
处理完成之后 外部调用的时候就可以传入整个chooseimage 的回调值,也不用分别处理小程序跟h5

图片上传

你以为这两个问题处理完了就解决了吗,并没有!我又遇到了第三个问题,腾讯IM上传图片视频等需要依赖cos插件,我在main.js中引入并且注册了cos-js-sdk-v5,但是上传的时候提示异常未检测到COS上传插件

玩的这么刺激,头发都要掉完了。。。

这个问题最后还是解决了,我没有去看源码,直接使用了cos-wx-sdk 就能正常上传图片,到现在都不知道为啥

总结

这个一波三折的问题处理完了,接下来还不知道有多少问题等着,整体这几个问题解决用了一天,但是挠了一天半的头,头发也掉了无数根。百度搜了无数次,也问了很多人,感谢uni群里大佬的帮助
文档还是要及时写,隔了一天很多细节都有点忘记了。
写的有点拖沓,请大家见谅