实现 Web 应用程序即时通信:通过接入腾讯云通信

4,749 阅读4分钟

介绍

腾讯是国内最早也是最大的即时通讯开发商,QQ 和微信已经成为每个互联网用户必不可少的应用。顺应行业数字化转型的趋势,腾讯将高并发、高可靠的即时通讯能力进行开放,您可以轻易地根据腾讯提供的 SDK 将即时通讯功能集成到 App 中,来满足您业务的各种需求。 针对开发者的不同阶段需求及不同场景,云通信 IM 团队提供了一系列解决方案,包括:Android、iOS、Windows、Web 的 SDK 组件、服务端集成 REST API 接口、第三方回调接口 等。利用这些组件和能力,开发者可以简单快捷地构建高可靠且稳定的即时通讯产品,随心所想,触达全球。不多逼逼,我也不太清楚,有需要可以自行查阅 官方文档

准备

在开始撸代码之前我们需要先登录云通信 IM 控制台来创建我们的应用:

云通信控制台

创建应用

我是创建过了才会有我标红框的地方,大家第一次进来是没有的哈,不要介意

这个东西随便填吧,目前好像是没啥影响

配置应用

点击应用配置

账号体系集成这里是比较重要的,请大家定不要忘记,不然没法继续下去的

开发辅助工具

填入我们刚刚下载下来的私钥内容,userid 随便填

然后会生成一个签名,建议大家创建个txt文件,把userid和签名记下来,我们后续会用到。并且大家按照这个步骤多生成几次签名,方便后续的测试

下载 demo

Github 下载 IM SDK H5 开发包。其实这个项目我并没有写太多的代码,因为看了下这个demo 写的很全,我们需要什么功能直接 COPY 然后改一改就OK了

开始 COPY 修修改改

大家个刚下载下来的demo目录应该是这个样子的

我们随便找一个目录创建一个这样的目录

接下来我们需要把 base.jsjquery.jslogin.jsreceive_new_msg.jssend_common_msg.jsshow_one_msg.js 以及 我们的主角 webim.js 复制到我们目录下的js目录下

接下来我们写一下简单的样式,并引入js 和一些配置。先声明哈:我偷了个懒一半写一半复制了demo的样式,不要喷我哈

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>

  <style>
    .lable {
      width: 100px;
      text-align: justify;
      display: inline-block;
    }

    .login {
      margin: 100px auto;
      position: relative;
      padding: 20px;
      width: 300px;
      height: 200px;
      border: 2px dashed #999999;
    }

    .btn-login {
      position: absolute;
      bottom: 50px;
      right: 50px;
      width: 100px;
    }

    #p_my_face {
      position: relative;
      width: 60px;
      height: 60px;
      border: 1px white solid;
      margin: 10px;
      float: left;
    }

    #t_my_name {
      position: relative;
      top: 10px;
      left: 10px;
      float: left;
      font-size: 20px;
      color: white;
    }

    #webim_demo {
      display: none;
    }

    .chatpart {
      width: 539px;
      border: 0px red solid;
      background: #d7eaf3;
      margin: 20px auto;

    }

    .msgflow {
      width: 525px;
      height: 380px;
      border: 1px rgb(181, 178, 178) solid;
      padding: 20px 6px 0 6px;
      background: #f5f5f5;
      overflow: auto;
    }

    .msgflow .onemsg {
      position: relative;
    }

    .msgflow .onemsg .msghead {
      color: green;
      line-height: 12px;
      font-size: 12px;
    }

    .msgflow .onemsg .msgbody {
      margin: 0 0 0 18px;
      line-height: 13px;
      font-size: 14px;
    }

    .msgflow .msgbody img {
      max-width: 500px;
    }

    .msgedit {
      width: 525px;
      height: 100px;
      border: 1px rgb(181, 178, 178) solid;
      background: #f5f5f5;
      padding: 6px 6px;
      line-height: 1.5;
    }

    .sendbar {
      width: 526px;
      height: 30px;
    }

    .sendbtn {
      float: right;
      width: 80px;
      margin-right: 10px;
      font: 10px/1.5 "微软雅黑";
    }

    .headurlClass {
      height: 30px;
      width: 30px;
      border-radius: 50%;
    }
  </style>
</head>

<body>

  <div id="wrapper">
    <img id="p_my_face">
    <p id="t_my_name"></p>
    <div class="login" id="login_dialog">
      <div>
        <span class="lable">identifier:</span>
        <input id="login_account" value="" type="text" placeholder='请输入identifier' />
      </div>
      <div>
        <span class="lable">userSig:</span>
        <input id="login_pwd" value="" type="text" placeholder='userSig' />
      </div>
      <div>
        <span class="lable">selToID:</span>
        <input id="selToID" value="" type="text" placeholder='请输入selToID' />
      </div>
      <button class="btn-login" onclick="independentModeLogin()">登录</button>
    </div>

    <div id="webim_demo">
      <div class="chatpart">
        <div class="msgflow"></div>
        <span id="msg_end" style="overflow:hidden"></span>
        <textarea class="msgedit" cols="82" id="send_msg_text" onkeydown="onTextareaKeyDown()" rows="5"></textarea>
        <div class="sendbar">
          <button class="sendbtn" onclick="onSendMsg()" type="button">发送</button>
        </div>
      </div>
    </div>

    <script src="./js/jquery.js"></script>
    <script src="./js/base.js"></script>
    <script src="./js/webim.js"></script>
    <script src="./js/login.js"></script>
    <script src="./js/show_one_msg.js"></script>
    <script src="./js/send_common_msg.js"></script>
    <script src="./js/receive_new_msg.js"></script>

    <script type="text/javascript">
      // 将以下两个参数替换成您的配置
      var sdkAppID = ''; // 填写第一步获取到的 sdkappid
      //var accountType = ''; // 填写第二步设置账号体系集成获取到的 accountType , 已废弃

      // 登录帐号
      var identifier = '', // 填写第三步输入的 identifier,由您指定,可以在登录页面直接输入
        userSig = ''; //填写第三步生成的userSig,可以在登录页面直接输入

      //帐号模式,0-表示独立模式,1-表示托管模式(托管模式已经停用,请使用独立模式集成帐号)
      var accountMode = 0;

      //当前用户身份
      var loginInfo = {
        'sdkAppID': sdkAppID, //用户所属应用id,必填
        // 'accountType': accountType, //用户所属应用帐号类型, 已废弃
        'identifier': identifier, //当前用户ID,必须是否字符串类型,必填
        'userSig': userSig,
        //当前用户身份凭证,必须是字符串类型,必填
        'identifierNick': null, //当前用户昵称,不用填写,登录接口会返回用户的昵称,如果没有设置,则返回用户的id
        'headurl': './images/me.jpg' //当前用户默认头像,选填,如果设置过头像,则可以通过拉取个人资料接口来得到头像信息
      };

      var AdminAcount = 'qwe101';
      var selType = webim.SESSION_TYPE.C2C; //当前聊天类型
      var selToID = null; //当前选中聊天id(当聊天类型为私聊时,该值为好友帐号,否则为群号)
      var selSess = null; //当前聊天会话对象
      var recentSessMap = {}; //保存最近会话列表
      var reqRecentSessCount = 50; //每次请求的最近会话条数,业务可以自定义

      var isPeerRead = 1; //是否需要支持APP端已读回执的功能,默认为0。是:1,否:0。

      //默认好友头像
      var friendHeadUrl = './images/friend.jpg'; //仅demo使用,用于没有设置过头像的好友
      var infoMap = {}; //初始化时,可以先拉取我的好友和我的群组信息

      //监听连接状态回调变化事件
      var onConnNotify = function (resp) {
        var info;
        switch (resp.ErrorCode) {
          case webim.CONNECTION_STATUS.ON:
            webim.Log.warn('建立连接成功: ' + resp.ErrorInfo);
            break;
          case webim.CONNECTION_STATUS.OFF:
            info = '连接已断开,无法收到新消息,请检查下你的网络是否正常: ' + resp.ErrorInfo;
            // alert(info);
            webim.Log.warn(info);
            break;
          case webim.CONNECTION_STATUS.RECONNECT:
            info = '连接状态恢复正常: ' + resp.ErrorInfo;
            // alert(info);
            webim.Log.warn(info);
            break;
          default:
            webim.Log.error('未知连接状态: =' + resp.ErrorInfo);
            break;
        }
      };

      //IE9(含)以下浏览器用到的jsonp回调函数
      function jsonpCallback(rspData) {
        webim.setJsonpLastRspData(rspData);
      }

      //监听事件
      var listeners = {
        "onConnNotify": onConnNotify //监听连接状态回调变化事件,必填
          ,
        "jsonpCallback": jsonpCallback //IE9(含)以下浏览器用到的jsonp回调函数,
          ,
        "onMsgNotify": onMsgNotify //监听新消息(私聊,普通群(非直播聊天室)消息,全员推送消息)事件,必填
          ,
        "onLongPullingNotify": function (data) {
          console.debug('onLongPullingNotify', data)
        }
      };

      var isAccessFormalEnv = true; //是否访问正式环境

      var isLogOn = false; //是否开启sdk在控制台打印日志

      //初始化时,其他对象,选填
      var options = {
        'isAccessFormalEnv': isAccessFormalEnv, //是否访问正式环境,默认访问正式,选填
        'isLogOn': isLogOn //是否开启控制台打印日志,默认开启,选填
      }

      var msgflow = document.getElementsByClassName("msgflow")[0];
      var bindScrollHistoryEvent = {
        init: function () {
          msgflow.onscroll = function () {
            if (msgflow.scrollTop == 0) {
              msgflow.scrollTop = 10;
              if (selType == webim.SESSION_TYPE.C2C) {
                getPrePageC2CHistoryMsgs();
              } else {
                getPrePageGroupHistoryMsgs();
              }

            }
          }
        },
        reset: function () {
          msgflow.onscroll = null;
        }
      };
    </script>
</body>

</html>

特别提醒 =============================> sdkAppID: 必填

在这里我只取了我需要的代码块,少了很多东西,不要慌张

这是我们的一个初始页面哈,identifuer 就是你的 useriduserSig 就是你生成的签名, selToID 就是你要聊天的对象,对方的 userid,我是偷懒才这么玩的,大家实际项目中不要这么搞哈。 接下来我们需要做登录功能

登录

大家有没有注意到这个方法 independentModeLogin

其实这个方法在 base.js里 我们来进行改造

//点击登录按钮(独立模式)
function independentModeLogin () {
    if ($("#login_account").val().length == 0) {
        alert('请输入帐号');
        return;
    }
    if ($("#login_pwd").val().length == 0) {
        alert('请输入UserSig');
        return;
    }
    
    /***************************************/
    if ($("#selToID").val().length == 0) {
        alert('请输入selToID');
        return;
    }
    /***************************************/
   
    loginInfo.identifier = $('#login_account').val();
    loginInfo.userSig = $('#login_pwd').val();
    
    /***************************************/
    selToID = $('#selToID').val();
    /***************************************/
    
    webimLogin(function () {
        $('#login_dialog').hide();
    }, function () { });
}

因为我们需要对方的 userid 所以我在这加了两段代码

接下来我们看到这里有个 webimLogin 方法,一看这就是登录的主要逻辑代码,那肯定是在 login.js里了

function webimLogin (successCB, errorCB) {
    webim.login(
        loginInfo, listeners, options,
        function (resp) {
            successCB && successCB(resp);
            loginInfo.identifierNick = resp.identifierNick; //设置当前用户昵称
            loginInfo.headurl = resp.headurl; //设置当前用户头像
            initDemoApp();
        },
        function (err) {
            alert(err.ErrorInfo);
            errorCB && errorCB(err);
        }
    );
}

其实这里我们并不需要改什么,我们看到这里有个 initDemoApp 的方法,这应该是做一些初始化的操作,我们继续追踪

发现还是在 base.js

function initDemoApp () {
    $("body").css("background-color", '#2f2f2f');
    $("#webim_demo").show();
    document.getElementById("p_my_face").src = loginInfo.headurl || './images/me.jpg';
    if (loginInfo.identifierNick) {
        document.getElementById("t_my_name").innerHTML = webim.Tool.formatText2Html(loginInfo.identifierNick);
    } else {
        document.getElementById("t_my_name").innerHTML = webim.Tool.formatText2Html(loginInfo.identifier);
    }
}

代码逻辑也都不难,大家一看也大概能看的明白

聊天

现在大家尝试登录,进来后会是这个样子,并且我们看到有个发送按钮,我们来追一下这个方法

然后我们在 send_common_msg.js 文件中找到这个方法,并发现在这个方法体内去调用了 handleMsgSend 这个方法,其实大家在这个文件中不需要去改任何东西

function onSendMsg () {
    ....
    
    //发消息处理
    handleMsgSend(msgContent);
}

handleMsgSend 这个方法里我们看到了 addMsg 我们来对他进行改造

//聊天页面增加一条消息

function addMsg (msg, prepend) {
    
    /*********************************/
    onemsg.style.clear = "both";
    
    // 如果是发出的消息
    if (isSelfSend) {
        onemsg.style.float = "right";
        msgbody.style.textAlign = 'right'
        //昵称  消息时间
        msghead.innerHTML = webim.Tool.formatText2Html(webim.Tool.formatTimeStamp(msg.getTime()) + "&nbsp;&nbsp;" + fromAccountNick) + "&nbsp;&nbsp;" + "<img class='headurlClass' src='" + fromAccountImage + "'>";
    }

    // 如果是发给自己的消息
    if (!isSelfSend) {
        msghead.style.color = "blue";
        onemsg.style.float = "left";
        //昵称  消息时间
        msghead.innerHTML = "<img class='headurlClass' src='" + fromAccountImage + "'>" + "&nbsp;&nbsp;" + webim.Tool.formatText2Html(fromAccountNick + "&nbsp;&nbsp;" + webim.Tool.formatTimeStamp(msg.getTime()));
    }
   /**************************************/
}

这个时候我们看到已经可以发送消息了,但是接收消息呢?? 继续追。。。

我们去找到这个方法,看看有没有什么需要改的

//监听新消息事件
var msgList = [];
var dateStart = null;
var dateEnd = null;
//newMsgList 为新消息数组,结构为[Msg]
function onMsgNotify (newMsgList) {
    //console.warn(newMsgList);
    var sess, newMsg;
    //获取所有聊天会话
    var sessMap = webim.MsgStore.sessMap();

   ....
}

看了一下好像也没有什么需要改的,那我们再登录一个账号测试下成果吧