网页版直播和聊天室

序言

话说上一回,我说到了直播和聊天室,使用的是原生实现的。然而对我来说这太简单了,不足以体现我技术的优越性。下面开启我的装逼之旅。

效果

1.截图

2.视频

关键看游客模式,登录提醒,跳转登录,发送缓存消息这些功能

网页聊天室效果

直播实现

直播使用的是乐视的标准直播。为什么使用乐视标准直播呢,因为他提供了推流客户端,为什么要使用它的推流客户端呢,首先减少开发成本,其次也是最重要的我将在本文的最后揭晓谜底。

乐视云地址

乐视云

这里进入标准直播

选择直播活动管理,就可以下载云采集了。

Android和IOS都支持

接着大家可以在手机,或者在控制台创建活动

创建成功就是这样了

在操作选择分析活动,就可以拿到HTML代码了,然后网页直播的功能就实现了。

聊天室实现

聊天室的实现就比较有技术含量了,而基于的SDK是LeanCloud的网页聊天室

文档在这里实时通信开发指南 · JavaScript

我遇到的困难有几点

1.实现游客模式,在用户未登录的情况下可以看到聊天内容

2.如果用户有聊天,点击发送按钮必须判断用户是否登录,给出提示,并弹到相应的界面。

3.用户在游客模式下输入的内容,要保存起来,在登录以后发送出去

4.用户clientID与用户名的处理,clicendID必须唯一,但是用户昵称可以重复。

这里面涉及到JavaScript和Java的交互,我先把接口提供出来。

    //用于和JavaScript交互的接口
    class Mobile {

        //保存聊天信息
        @JavascriptInterface
        public void saveMessage(String msg){
            Log.i("zzz","saveMessage() msg="+msg);
            isNeedSendMessage=true;
            needSendMessage=msg;
        }

        //是否需要发送缓存的聊天信息
        @JavascriptInterface
        public boolean isNeedSendMessage(){
         //   Log.i("zzz","isNeedSendMessage() isNeedSendMessage="+isNeedSendMessage);
            return isNeedSendMessage;
        }

        //获取缓存的聊天信息
        @JavascriptInterface
        public String getNeedSendMessage(){
         //   Log.i("zzz","getNeedSendMessage()");
            return needSendMessage;
        }

        //消失已经发送,重置状态
        @JavascriptInterface
        public void  messageHaveSend(){
        //    Log.i("zzz","messageHaveSend()");
            isNeedSendMessage=false;
            needSendMessage="";
        }

        //是否是游客模式
        @JavascriptInterface
        public boolean isTouristMode() {
            return !isLogin();
        }

        //获取游客ID
        @JavascriptInterface
        public String getTouristID() {
            return TouristID;
        }

        //是否已经登录
        @JavascriptInterface
        public boolean isLogin() {
            return isLogin;
        }

        //获取客户端ID
        @JavascriptInterface
        public String getClientID() {
            return clientID;
        }

        //弹出警告
        @JavascriptInterface
        public void alert(String msg) {
            Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }

        //跳转到登录
        @JavascriptInterface
        public void moveToLogin() {
            needLogin = true;
            startActivity(new Intent(MainActivity.this, LoginActivity.class));
        }
    }

这是和聊天相关的JavaScript代码

//判断是否是游客模式
if(moblie.isTouristMode()){
    //如果是游客模式的话,获取游客ID并登陆
    initChatroom(moblie.getTouristID());
}else{
  //如果不是游客模式,则判断是否登录
if(moblie.isLogin()){
        //如果已经登录,则获取clientID
       initChatroom(moblie.getClientID());
   }else{
        //否则弹出提示
       moblie.alert("请登录");
        //跳转到登录界面
       moblie.moveToLogin();
   }
 }

//初始化聊天室
function initChatroom(clientID){
angular.module(‘realTimeModule‘, [])
    .controller(‘realTimeCtrl‘, [‘$scope‘, ‘$timeout‘, function($scope, $timeout) {
        initStatus();
        initData();

        function initStatus() {
            $scope.status = {
                Realtime: AV.Realtime,
                appId: "jPbaegow8uVUDUDw1XS7LCv0-gzGzoHsz",
                region: [‘cn‘, ‘us‘],
                //用户名ID
                clientId:clientID,
                roomId: "57fcac8ea22b9d005b0e9884",
                client: "",
                isLinkSuccess: false,
                isLinkFailed: false,
                isLinking: false,
                messageIterator: "",
                msg: "",
                room: "",
                myMsgs: [],
                members: [],
                historys: []
            };
        }

        function initData() {
            $scope.data = {
                realtime: new $scope.status.Realtime({
                    appId: $scope.status.appId,
                    region: $scope.status.region[0],
                }),
            };
            initChatroom();
            setVideoScale();
            setChatroomHeight();

        }

        /**
         * [initChatroom description] 初始化聊天室
         * @return {[type]} [description]
         */
        function initChatroom() {
            $scope.status.isLinking = true;
            $scope.data.realtime.createIMClient($scope.status.clientId)
                .then(function(client) {
                    $timeout(function() {
                        $scope.status.isLinkSuccess = true;
                        $scope.status.client = client;
                    }, 500);
                    client.on(‘disconnect‘, function() {
                        $scope.status.isLinkFailed = true;
                    });
                    return client.getConversation($scope.status.roomId);
                })
                .then(function(conversation) {
                    if (conversation) {
                        return conversation;
                    } else {
                        return $scope.status.client.createConversation({
                            name: "chatRoom",
                            members: [],
                        });
                    }
                })
                .then(function(conversation) {
                    $scope.status.roomId = conversation.id;
                    return conversation;
                })
                .then(function(conversation) {
                    $scope.status.members = conversation.members;
                    return conversation;
                })
                .then(function(conversation) {
                    return conversation.join();
                })
                .then(function(conversation) {
                    // 获取聊天历史
                    $scope.status.room = conversation;
                    conversation.queryMessages({
                        limit: 50,
                    }).then(function(messages) {
                    var newMessages=new Array();
                   for(var i=0, len=messages.length; i<len; i++){
                        var message=messages[i];
                       handleName(message);
                       newMessages.unshift(message);
                    }
                        $scope.status.historys = newMessages;
                    });
                    conversation.on(‘message‘, function(message) {
                        $timeout(function() {
                           handleName(message);
                            $scope.status.historys.unshift(message);
                        });
                    });
                    //发送游客登录时未发送的消息
                      if(moblie.isNeedSendMessage()){
                                      var msg= moblie.getNeedSendMessage();
                                       $scope.status.msg=msg;
                                           //sendMessage();
                                           sendMsg();
                                           moblie.messageHaveSend();
                                           moblie.alert("评论成功");
                                       }
                });
        }

        function handleName(message){
               var from=message.from;
                 var index=from.indexOf("#");
                      if(index!=-1){
                        from=from.substr(index+1);
                     }
                      message.from=from;
                    //  return message;
        }
        /**
         * [sendMsg description] 发送消息
         * @return {[type]} [description]
         */
        function sendMsg() {
        if(!moblie.isLogin()){
              moblie.saveMessage($scope.status.msg);
              moblie.alert("请登录");
              moblie.moveToLogin();
              return;
         }
            $scope.status.room.send(new AV.TextMessage($scope.status.msg)).then(function(message) {
                $timeout(function() {
                    message.from="自己";
                    $scope.status.historys.unshift(message);
                });
                $scope.status.msg = ‘‘;
            });
        }

        /**
         * [linkToServer description] 连接到服务器
         * @return {[type]} [description]
         */
        $scope.linkToServer = function() {
            initChatroom();
        };

        /**
         * [sendMessage description] 发送消息
         * @return {[type]} [description]
         */
        $scope.sendMessage = function(e) {
            if ((angular.isDefined(e) && e.keyCode == 13) || angular.isUndefined(e)) {
                sendMsg();
            }
        };

        /**
         * [setVideoScale description] 根据16/9的比例设置视频高度
         */
        function setVideoScale() {
            var cw = document.documentElement.clientWidth;
            var scale = 16 / 9;
            var vh = cw / scale;
            var video = document.getElementById("player");
            video.style.height = vh + "px";
        }

        /**
         * [setChatroomHeight description] 设置聊天室的高度(为了移动端一屏展示)
         */
        function setChatroomHeight() {
            var video = document.getElementById("player");
            var chatroomHeader = document.getElementById("chatroomHeader");
            var chatroom = document.getElementById("chatroom");
            var sendBox = document.getElementById("sendBox");
            var ch = document.documentElement.clientHeight;
            var vh = getStyle(video).height;
            var crheader = getStyle(chatroomHeader).height;
            var sbh = getStyle(sendBox).height;
            var crh = parseInt(ch) - parseInt(vh) - parseInt(crheader) - parseInt(sbh);
            if (crh < 1) {
                crh = crh + 500;
            }
            console.log(crh);
            chatroom.style.height = crh + "px";
            chatroom.style.marginBottom = sbh;

        }

        function getStyle(ele) {
            var style = null;
            if (window.getComputedStyle) {
                style = window.getComputedStyle(ele, null);
            } else {
                style = ele.currentStyle;
            }
            return style;
        }

        window.onresize = function() {
            setVideoScale();
            setChatroomHeight();
        };

    }]);
  }

1.游客模式

实现游客模式的逻辑如下,这是聊天室相关的JavaScript代码。

而游客ID的获取如下,通过拼接两个随机数来实现。

2.登录判断

看关键的JS代码,主要就是在发送消息的时候判断登录状态。

 /**
         * [sendMsg description] 发送消息
         * @return {[type]} [description]
         */
        function sendMsg() {
        //判断是否登录
        if(!moblie.isLogin()){
               //未登录,则保存输入框中的消息
              moblie.saveMessage($scope.status.msg);
              //弹出提示
              moblie.alert("请登录");
              //跳转到登录界面
              moblie.moveToLogin();
              return;
         }
            $scope.status.room.send(new AV.TextMessage($scope.status.msg)).then(function(message) {
                $timeout(function() {
                    message.from="自己";
                    $scope.status.historys.unshift(message);
                });
                $scope.status.msg = ‘‘;
            });
        }

如果需要登录则跳转到登录界面

   //跳转到登录
        @JavascriptInterface
        public void moveToLogin() {
            //表示需要登录
            needLogin = true;
            startActivity(new Intent(MainActivity.this, LoginActivity.class));
        }

LoginActivity如下

public class LoginActivity extends AppCompatActivity {

    EditText et_name;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        et_name = (EditText) findViewById(R.id.et_name);
    }

    public void login(View view) {
        String name = et_name.getText().toString();
        MainActivity.isLogin = true;
        MainActivity.clientID = name;
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
        finish();
    }
}

回来以后在聊天室界面的onResume方法中判断是否需要登录,如果需要通过 webView.reload()重新加载网页。

    @Override
    protected void onResume() {
        super.onResume();
        if (needLogin) {
            webView.reload();
            needLogin = false;
        }
    }

网页每次加载都会执行这个方法,这里就会进入到登录的逻辑了。

//判断是否是游客模式
if(moblie.isTouristMode()){
    //如果是游客模式的话,获取游客ID并登陆
    initChatroom(moblie.getTouristID());
}else{
  //如果不是游客模式,则判断是否登录
if(moblie.isLogin()){
        //如果已经登录,则获取clientID
       initChatroom(moblie.getClientID());
   }else{
        //否则弹出提示
       moblie.alert("请登录");
        //跳转到登录界面
       moblie.moveToLogin();
   }
 }

3.保存未发送信息

1.在发送消息的时候,如果没有登录,则通过Java接口保存消息

 /**
         * [sendMsg description] 发送消息
         * @return {[type]} [description]
         */
        function sendMsg() {
        //判断是否登录
        if(!moblie.isLogin()){
               //未登录,则保存输入框中的消息
              moblie.saveMessage($scope.status.msg);
              //弹出提示
              moblie.alert("请登录");
              //跳转到登录界面
              moblie.moveToLogin();
              return;
         }
            $scope.status.room.send(new AV.TextMessage($scope.status.msg)).then(function(message) {
                $timeout(function() {
                    message.from="自己";
                    $scope.status.historys.unshift(message);
                });
                $scope.status.msg = ‘‘;
            });
        }

在登录聊天室成功以后,发送保存的信息

                      //发送游客登录时未发送的消息
                      if(moblie.isNeedSendMessage()){
                              //获取保存的消息
                             var msg= moblie.getNeedSendMessage();
                             $scope.status.msg=msg;
                             //发送消息
                             sendMsg();
                             //重置状态
                             moblie.messageHaveSend();
                              //提示用户
                              moblie.alert("评论成功");
                       }

4.用户ID

这个处理我用在实际的项目中了,这Demo没有,大致的说一样原理

为了实现ClientID唯一,我选择了使用LeanCloud的ObjectID做ClientID但是现实的效果是

一大堆的数字字母串,聊天的时候就这这样了,没有显示用户昵称,效果和差。

aojogo80900nfjf3883949:我是李四
oiigjiooiijglle9939948:我是张三,你的名字好奇怪

于是我使用了ObjectID:昵称 这种形式。比如

aogoijsojgoij5651211sdjk:李四

在获取到消息以后就只截取后面的昵称用来显示

李四:我是李四
张三:我是张三

效果很不错,而且解决了唯一性和易用性的问题,我在真实项目中已经实现了,所以大家也不要怀疑是实用性了。

源码

结构

realtime.html是聊天室界面

realtime.js是聊天室逻辑

大家只需要替换,AppID,和roomID为你们自己的就可以用在自己的项目中了

关于弹幕,在获取到消息以后实用JavaScript以弹幕的方式显示就行了。

下载

下载地址

总结

这个项目主要的难度是考察了我Java和JavaScript的交互能力,和我的JavaScript的水平。realtime.js中的所有和客户端交互的逻辑都是我自己写的,这里需要重点表扬一下。还有一点可以说明一下,通过这种方式,我们的IOS也可以实现一样的效果,所有小伙伴们不要害怕,如果你们的IOS端做不出来,只能说明水平太菜,一个小插曲就是我的Mobile这个单词写错了,已改是mobile,不过无关大雅。然后说说我们会什么要使用网页实现直播和聊天室,为什么我要在这儿装逼,全都是被逼的,在上一篇博客结束以后,我们告诉客户我们准备用百度云SDK,客户说:”什么!我们乐视云都已经付费了,必须用乐视“。在上一篇文章我就说过乐视云根本不能用,客户不信,于是就有了下面这个。

还有这个

由于移动直播根本不能用,于是改用标准直播,还有他们官方的推流工具,但是官方的推流工具在Android端依然有兼容性问题。

奉劝大家,真心不要用乐视,这是我曾经的一些坑,如果能帮到你,那我这个逼也就没有白装了。

时间: 2024-10-12 14:41:38

网页版直播和聊天室的相关文章

swoole学习--图文直播和聊天室

其实这个也没有什么好值得记录的,但是前面都记下来了,我也顺便说说吧: 1.为了方便,最好把http服务声明为超全局变量. 2.在一些地方里面,你声明的http超全局变量是用不了的,你只能用他自己内置的服务对象: public function pushLive($da, $serv) { $key = 'live_game_key'; $res = Predis::getInstance()->smembers($key); foreach ($res as $k => $v) { $serv

HTML5 - websocket的应用 之 简易聊天室

需要知识点: 前端知识 jq操作dom nodejs socket.io 关于websocket api的知识点,见上篇章<HTML5-Websocket>. 聊天室思路/原理: A和B聊天: A发送消息到中间“聊天服务器”, 服务器发送消息给B B接收A的消息,实现第一次消息传输 B再给A回消息的原理同上三步骤 其中原始HTTP协议和H5新增Websocket协议不同的地方在于: “服务器发送消息给B”这里. HTTP协议中,服务器是基于“请求 到 响应”的一个模型的 .也就是说,服务器无法

Web版的各种聊天工具

直到近期为止,我们经常使用的即时聊天工具(QQ.msn等)了Web版,大家不用下载庞大软件,直接打开网页就能够与自己的好友聊天,非常方便.在此将时汇总 ?????? 便于大家查找 ?????? 节约大家一点时间 此都是官方站点 ?????? 请大家放心使用: 1.先说我们最经常使用的QQ 在线聊天Web版地址: http://webqq.qq.com/ (刚建的 ?????? 现正在測试 ?????? 须要申请 ?????? 日前还不太稳定 ?????? 有待完好) 2.msn在线聊天Web版地

如何在微信公众号的菜单里加入一个免费的H5聊天室

影圈H5网页聊天室 - 简单对接,经济实用! 官方网站:https://www.pyingquan.com 您只需跳转或嵌入一个H5网页,即可实现聊天室功能. 目前支持文字发送.表情发送.图片发送. 影圈的天气api系统已提供约1.5亿次服务,服务稳定高效.请放心使用! 使用方法: 登录影圈云平台  (没有账号需要先注册个账号) 进入聊天室后台, 创建房间, 如图 点击获取聊天室链接或二维码(前提是勾选 允许匿名进入),把链接添加到 公众号菜单 就可以使用啦!赶快体验一下吧!!! 扫描二维码体验

3分钟实现网页版多人文本、视频聊天室 (含完整源码)

基于SimpleWebRTC快速实现网页版的多人文本.视频聊天室. 1 实现方法 复制下面的代码,保存为一个html文件 <!DOCTYPE html> <html> <head> <script src="https://code.jquery.com/jquery-1.9.1.js"></script> <script src="http://simplewebrtc.com/latest.js"

基于WebSocket实现网页版聊天室

WebSocket ,HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,其使用简单,应用场景也广泛,不同开发语言都用种类繁多的实现,仅Java体系中,Tomcat,Jetty,Spring等都提供了对WS的API支持.本篇不做理论探究,仅自娱自乐,简单实现网页版的聊天室功能,在实际开发场景中变通使用即可.废话不叽歪,直接撸出来—— 1  简单页面 <!DOCTYPE html> <html lang="en"> <head> &l

WebRTC实现网页版多人视频聊天室

因为产品中要加入网页中网络会议的功能,这几天都在倒腾 WebRTC,现在分享下工作成果. 话说 WebRTC Real Time Communication 简称 RTC,是谷歌若干年前收购的一项技术,后来把这项技术应用到浏览器中并开源出来,而且搞了一套标准提交给W3C,称为WebRTC,官方地址是:http://www.webrtc.org/.WebRTC要求浏览器内置实时传输音视频的功能,并提供一致的API供JS使用.目前实现这套标准的浏览器有:Chrome.FireFox.Opera.微软

vue仿微信网页版|vue+web端聊天室|仿微信客户端vue版

一.项目介绍 基于Vue2.5.6+Vuex+vue-cli+vue-router+vue-gemini-scrollbar+swiper+elementUI等技术混合架构开发的仿微信web端聊天室——vueWebChat,实现了发送消息.表情(动图),图片.视频预览,右键菜单.截屏.截图可直接粘贴至文本框进行发送. 二.技术框架 MVVM框架:Vue2.5.6 状态管理:Vuex 页面路由:Vue-router iconfont图标:阿里巴巴字体图标库 自定义滚动条:vue-gemini-sc

网页版WebRTC多人聊天Demo

网页版WebRTC多人聊天Demo 本文基于Codelab中step7,在其基础上作简单修改,使其支持多人视频通讯,本文暂时只支持星状结构三人聊天,多人聊天可以在基础上扩展,原理相同. 一.源码分析 该工程包括三个文件:server.js,main.js,index.html. 1.server.js if (numClients == 0){ socket.join(room); socket.emit('created', room); } else if (numClients == 1)