zoukankan      html  css  js  c++  java
  • python 全栈开发,Day127(app端内容播放,web端的玩具,app通过websocket远程遥控玩具播放内容,玩具管理页面)

    昨日内容回顾

    1. 小爬爬 内容采集
        XMLY 的 儿童频道 requests 
    
    2. 登陆 注册 自动登陆 退出
        mui.post("请求地址",{数据},function(){})
        plus.storage.setItem(key,value)
        plus.storage.getItem(key)
        plus.storage.removeItem(key)
        
    3. app 首页内容部分
        document.createElement("div")
    View Code

    一、app端内容播放

    下载代码

    https://github.com/987334176/Intelligent_toy/archive/v1.0.zip

    注意:由于涉及到版权问题,此附件没有图片和音乐。请参考昨天的代码,手动采集一下!

    请参考链接:

    https://www.cnblogs.com/xiao987334176/p/9647993.html#autoid-3-4-0

    播放页面

    点击首页的图文列表,需要打开播放页面!

    新建一个player.html

    内容如下:

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row">
                    
                </div>
            </div>
    
        </body>
        <script src="js/mui.min.js"></script>
        <script type="text/javascript">
            mui.init()
        </script>
    
    </html>
    View Code

    新建一个目录avatar,用来存放头像。从网上下载2个头像,放到此目录。

    MyApp目录结构如下:

    ./
    ├── avatar
    │   ├── boy.jpg
    │   └── girl.jpg
    ├── css
    │   ├── mui.css
    │   └── mui.min.css
    ├── fonts
    │   └── mui.ttf
    ├── index.html
    ├── js
    │   ├── md5.min.js
    │   ├── mui.js
    │   └── mui.min.js
    ├── login.html
    ├── main.html
    ├── manifest.json
    ├── phone.html
    ├── player.html
    ├── reg.html
    ├── unpackage
    └── user_info.html

    修改player.html,引入图片,将图片设置为圆的

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
            </div>
    
        </body>
        <script src="js/mui.min.js"></script>
        <script type="text/javascript">
            mui.init()
        </script>
    
    </html>
    View Code

    使用HBuilder访问页面,效果如下:

    这个图片应该要设置转圈的,有兴趣的人,可以用cs3语法弄一下! 

    获取列表id

    这个图片,应该是音频的图片。昨天我们已经把音频相关的图片下载下来了!

    那么首页点击的时候,应该要把当前内容的id传递给player.html

    修改main.html,增加点击事件,使用onclick,打印id

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <h1 class="mui-title">首页</h1>
            </header>
            <div class="mui-scroll-wrapper">
                <div class="mui-scroll">
                    <div class="mui-content">
                        <div id="slider" class="mui-slider">
                            <div class="mui-slider-group mui-slider-loop">
                                <!-- 额外增加的一个节点(循环轮播:第一个节点是最后一张轮播) -->
                                <div class="mui-slider-item mui-slider-item-duplicate">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 第一张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1537023056923&amp;di=e50b27f1a9d34e586e421b50ff5cc0b0&amp;imgtype=0&amp;src=http%3A%2F%2Fatt.bbs.duowan.com%2Fforum%2F201508%2F18%2F173910p7045xys71x4zfyh.jpg"
                                            width="300px" height="400px">
                                    </a>
                                </div>
                                <!-- 第二张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 第三张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 第四张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 额外增加的一个节点(循环轮播:最后一个节点是第一张轮播) -->
                                <div class="mui-slider-item mui-slider-item-duplicate">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                            </div>
                            <div class="mui-slider-indicator">
                                <div class="mui-indicator mui-active"></div>
                                <div class="mui-indicator"></div>
                                <div class="mui-indicator"></div>
                                <div class="mui-indicator"></div>
                            </div>
                        </div>
                        <ul class="mui-table-view mui-grid-view mui-grid-9">
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-home"></span>
                                    <div class="mui-media-body">Home</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-email"><span class="mui-badge mui-badge-red">5</span></span>
                                    <div class="mui-media-body">Email</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-chatbubble"></span>
                                    <div class="mui-media-body">Chat</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-location"></span>
                                    <div class="mui-media-body">Location</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-search"></span>
                                    <div class="mui-media-body">Search</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-phone"></span>
                                    <div class="mui-media-body">Phone</div>
                                </a>
                            </li>
                        </ul>
                        <ul class="mui-table-view" id="content_list">
    
                        </ul>
                    </div>
                </div>
    
            </div>
        </body>
    
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            mui('.mui-scroll-wrapper').scroll()
            mui.back = function() {
                mui.toast("不让你点")
            };
            
            mui.plusReady(function(){
                mui.post(
                    window.serv+"/content_list",
                    {},
                    function(data){
                        console.log(JSON.stringify(data));
                        
                        for (var i = 0; i < data.data.length; i++) {
                            create_content(data.data[i])
                        }
                    }
                )
                
            })
            
            document.addEventListener("talk",function(data){
                mui.toast(data.detail.talk);
            })
            
            function create_content(content){    //创建图文列表    
                var litag = document.createElement("li");
                litag.className = "mui-table-view-cell mui-media";
                var atag = document.createElement("a");
                atag.id = content._id;
                // 点击事件
                atag.onclick = function(){
                    console.log(this.id);
                }
                
                var imgtag = document.createElement("img");
                imgtag.className = "mui-media-object mui-pull-left";
                
                imgtag.src = window.serv_imge + content.avatar;
    //            console.log(window.serv_imge + content.avatar);
                
                var divtag = document.createElement("div");
                divtag.className = "mui-media-body";
                divtag.innerText = content.title;
                var ptag = document.createElement("p");
                ptag.className = "mui-ellipsis";
                ptag.innerText = content.intro;
                 
                 litag.appendChild(atag);
                 atag.appendChild(imgtag);
                 atag.appendChild(divtag);
                 divtag.appendChild(ptag);
                 
                 document.getElementById("content_list").appendChild(litag);
            
            }
            
        </script>
    
    </html>
    View Code

    使用模拟器访问,点击图文列表,HBuilder控制台就会输出id:

    这些id是从MongoDB获取,并渲染的!

    修改main.html,新增一个方法openPlayer,用来打开播放页面。传递id参数

    点击图文列表时,就调用次方法。

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <h1 class="mui-title">首页</h1>
            </header>
            <div class="mui-scroll-wrapper">
                <div class="mui-scroll">
                    <div class="mui-content">
                        <div id="slider" class="mui-slider">
                            <div class="mui-slider-group mui-slider-loop">
                                <!-- 额外增加的一个节点(循环轮播:第一个节点是最后一张轮播) -->
                                <div class="mui-slider-item mui-slider-item-duplicate">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 第一张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1537023056923&amp;di=e50b27f1a9d34e586e421b50ff5cc0b0&amp;imgtype=0&amp;src=http%3A%2F%2Fatt.bbs.duowan.com%2Fforum%2F201508%2F18%2F173910p7045xys71x4zfyh.jpg"
                                            width="300px" height="400px">
                                    </a>
                                </div>
                                <!-- 第二张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 第三张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 第四张 -->
                                <div class="mui-slider-item">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                                <!-- 额外增加的一个节点(循环轮播:最后一个节点是第一张轮播) -->
                                <div class="mui-slider-item mui-slider-item-duplicate">
                                    <a href="#">
                                        <img src="http://placehold.it/400x300">
                                    </a>
                                </div>
                            </div>
                            <div class="mui-slider-indicator">
                                <div class="mui-indicator mui-active"></div>
                                <div class="mui-indicator"></div>
                                <div class="mui-indicator"></div>
                                <div class="mui-indicator"></div>
                            </div>
                        </div>
                        <ul class="mui-table-view mui-grid-view mui-grid-9">
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-home"></span>
                                    <div class="mui-media-body">Home</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-email"><span class="mui-badge mui-badge-red">5</span></span>
                                    <div class="mui-media-body">Email</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-chatbubble"></span>
                                    <div class="mui-media-body">Chat</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-location"></span>
                                    <div class="mui-media-body">Location</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-search"></span>
                                    <div class="mui-media-body">Search</div>
                                </a>
                            </li>
                            <li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                                <a href="#">
                                    <span class="mui-icon mui-icon-phone"></span>
                                    <div class="mui-media-body">Phone</div>
                                </a>
                            </li>
                        </ul>
                        <ul class="mui-table-view" id="content_list">
    
                        </ul>
                    </div>
                </div>
    
            </div>
        </body>
    
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            mui('.mui-scroll-wrapper').scroll()
            mui.back = function() {
                mui.toast("不让你点")
            };
            
            mui.plusReady(function(){
                mui.post(
                    window.serv+"/content_list",
                    {},
                    function(data){
                        console.log(JSON.stringify(data));
                        
                        for (var i = 0; i < data.data.length; i++) {
                            create_content(data.data[i])
                        }
                    }
                )
                
            })
            
            document.addEventListener("talk",function(data){
                mui.toast(data.detail.talk);
            })
            
            function create_content(content){    //创建图文列表    
                var litag = document.createElement("li");
                litag.className = "mui-table-view-cell mui-media";
                var atag = document.createElement("a");
                atag.id = content._id;
                // 点击事件
                atag.onclick = function(){
                    console.log(this.id);
                    openPlayer(this.id);  //调用openPlayer方法
                }
                
                var imgtag = document.createElement("img");
                imgtag.className = "mui-media-object mui-pull-left";
                
                imgtag.src = window.serv_imge + content.avatar;
    //            console.log(window.serv_imge + content.avatar);
                
                var divtag = document.createElement("div");
                divtag.className = "mui-media-body";
                divtag.innerText = content.title;
                var ptag = document.createElement("p");
                ptag.className = "mui-ellipsis";
                ptag.innerText = content.intro;
                 
                 litag.appendChild(atag);
                 atag.appendChild(imgtag);
                 atag.appendChild(divtag);
                 divtag.appendChild(ptag);
                 
                 document.getElementById("content_list").appendChild(litag);
            
            }
            
            function openPlayer(content_id){  //打开播放页面
                mui.openWindow({
                    url:"player.html",
                    id:"player.html",
                    // 传递参数content_id
                    extras:{content_id:content_id}
                })
            }
            
        </script>
    
    </html>
    View Code

    修改player.html,接收id

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id='play' >播放</button>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
            })
        </script>
    
    </html>
    View Code

    使用模拟器访问,底部会弹出id,效果如下:

    发送POST请求

    修改player.html,注意js代码部分,是mui.js。因为它依赖mui.js的一个全局变量!

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
            </div>
    
        </body>
        <script src="js/mui.min.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        
                    }
                )
            })
        </script>
    
    </html>
    View Code

    打开flask项目,修改 serv-->content.py,增加视图函数content_one

    from flask import Blueprint, jsonify,request
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    cont = Blueprint("cont", __name__)
    
    
    @cont.route("/content_list", methods=["POST"])
    def content_list():  # 内容列表
        res_list = list(MONGO_DB.sources.find({}))  # 字典转换列表
    
        for index, item in enumerate(res_list):  #返回 enumerate(枚举)对象
            # 由于_id是ObjectId对象,转换为字符串
            res_list[index]["_id"] = str(item.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = res_list
    
        return jsonify(RET)  # 返回json数据
    
    
    @cont.route("/content_one", methods=["POST"])
    def content_one():
        """
        获取一条内容
        :return: settings-->RET
        """
        content_id = request.form.get("content_id")
        # 根据_id获取一条数据
        res = MONGO_DB.sources.find_one({"_id":ObjectId(content_id)})
    
        res["_id"] = str(res["_id"])  # 转换为str
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = res
    
        return jsonify(RET)
    View Code

    使用模拟器,重新点击一次,查看HBuilder控制台输出:

     {"code":0,"data":{"_id":"5b9cd309e125320580da5b94","audio":"a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3","avatar":"a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.jpg","category":"erge","intro":"【一千零一夜】经典儿歌","nickname":"一千零一夜频道","play_count":0,"title":"新年恰恰"},"msg":""} at player.html:39

    既然数据有了,就可以渲染页面了!

    修改player.html

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
    
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        // 修改标题
                        document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
                        // 修改图片地址
                        document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
                    }
                )
            })
        </script>
    
    </html>
    View Code

    使用模拟器,重新点击。播放如下:

    现在需要播放这首歌曲,如何实现呢?

    听歌是一个新的接口,使用Audio模块

    Audio模块

    Audio模块用于提供音频的录制和播放功能,可调用系统的麦克风设备进行录音操作,也可调用系统的扬声器设备播放音频文件。通过plus.audio获取音频管理对象。

    参考链接:

    http://www.html5plus.org/doc/zh_cn/audio.html

    AudioPlayer

    音频播放对象

    interface AudioPlayer {
        function void play( successCB, errorCB );
        function void pause();
        function void resume();
        function void stop();
        function void seekTo( position );
        function Number getDuration();
        function Number getPosition();
        function void setRoute( route );
    }

    说明:

    音频播放对象,用于音频文件的播放。不能通过new方法直接创建,只能通过audio.createPlayer方法创建。

    方法:

    参考链接:

    http://www.html5plus.org/doc/zh_cn/audio.html#plus.audio.AudioPlayer

    由于音频在后端,前端播放时,获取的是一个远程音频。能播放吗?

    先测试一下本地播放

    测试本地播放

    使用HBuilder 新建一个文件夹audiotest,

    在此目录,放一个音频文件123.mp3

    修改player.html,增加一个button按钮。设置点击事件,播放123.mp3

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
    
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        // 修改标题
                        document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
                        // 修改图片地址
                        document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
                        
                    }
                );
                
                function play_anything(content) {  //播放音频
                    // 创建播放对象
                    player = plus.audio.createPlayer(content);
                    player.play();  // 播放音频
                }
                
                document.getElementById("play").addEventListener("tap", function() {
                    // 播放指定音乐
                    play_anything("audiotest/123.mp3");
                });
            })
        </script>
    
    </html>
    View Code

    打开模拟器,点击任意的图文列表。跳转到播放页面,点击播放,就会有声音了!

    如果没有声音,打开音量合成器。将模拟器的音量设置和系统一样

     

    参考链接:

    https://www.yeshen.com/faqs/HyentzDUZ

    如果还是没有声音,重启夜神模拟器。再次播放,就有声音了!

    我就是这么解决的!

    播放远程音频

    既然本地的解决了,删除目录audiotest目录!

    下面来测试一下播放远程音频。

    修改mui.js,增加全局变量serv_audio

    ...
    window.serv = "http://192.168.11.86:9527"
    window.serv_imge = window.serv+"/get_image/";
    window.serv_audio = window.serv+"/get_audio/";
    ...

    修改 player.html,设置为远程地址

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
    
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        // 修改标题
                        document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
                        // 修改图片地址
                        document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
                        // 调用自定义方法,播放音频
                        // data是后端返回的数据,data.audio是音频文件名
                        play_anything(data.data.audio);
                    }
                );
                
                function play_anything(content) {  //播放音频
                    // 创建播放对象,拼接路径
                    player = plus.audio.createPlayer(window.serv_audio + content);
                    console.log(window.serv_audio + content);  //打印路径
                    //  http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
                    player.play();  // 播放音频
                }
                
                document.getElementById("play").addEventListener("tap", function() {
                    // 播放指定音乐
    //                play_anything("audiotest/123.mp3");
                });
            })
        </script>
    
    </html>
    View Code

    使用模拟器访问,点击一个列表,就会自动播放

     如果要其他功能,比如暂停,继续,停止。

    修改player.html,增加按钮,并增加3个方法。

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
                <button type="button" class="mui-btn mui-btn-yellow mui-btn-block" id="pause">暂停</button>
                <button type="button" class="mui-btn mui-btn-green mui-btn-block" id="resume">继续</button>
                <button type="button" class="mui-btn mui-btn-red mui-btn-block" id="stop">停止</button>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;  //当前web页面
            var player = null;  //播放对象
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
    
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        // 修改标题
                        document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
                        // 修改图片地址
                        document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
                        // 调用自定义方法,播放音频
                        // data是后端返回的数据,data.audio是音频文件名
                        play_anything(data.data.audio);
                    }
                );
                
                function play_anything(content) {  //播放音频
                    // 创建播放对象,拼接路径
                    player = plus.audio.createPlayer(window.serv_audio + content);
                    console.log(window.serv_audio + content);  //打印路径
                    //  http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
                    player.play();  // 播放音频
                }
                
                document.getElementById("play").addEventListener("tap", function() {
                    player.play();
                });
        
                document.getElementById("pause").addEventListener("tap", function() {
                    player.pause();  //暂停
                });
                
                document.getElementById("resume").addEventListener("tap", function() {
                    player.resume();  //继续
                });
                
                document.getElementById("stop").addEventListener("tap", function() {
                    player.stop(); // 停止,直接清空player中的对象
                });
                
            })
        </script>
    
    </html>
    View Code

    使用模拟器访问,点击一首歌。会自动播放!

    点击暂停-->继续,暂停-->继续,再点击停止。最后点击播放,就没有声音了!

    注意:停止,是直接清空player中的对象

    二、web端的玩具

    小故事

    先来讲一个小故事:前期开发时,由于软件部需要测试。但是硬件部暂时无法拿出板子给软件部测试!

    为了解决这个问题,硬件部使用了工程版的面板做了low版的样品,给软件部测试。第一天测试了几个小时,到了中午时间,同事都去吃饭了!

    回来时,发现板子烧了!桌子烧一个大洞!键盘没了一半,显示器...

    为啥呢?因为芯片程序,没有写任何保护措施。触发了一个死循环,导致板子过热!

    为了避免重蹈覆辙,不允许使用工程版!

    软件部为了测试,做了一个web版玩具页面!使用websocket

    web版玩具页面

    之前后端写的 manager.py,是用来提供资源服务的。

    现在和玩具交互,使用websocket,它是通讯类服务。需要单独起一个进程,和资源进程分开!

    录音

    新建文件 im_serv.py

    from flask import Flask, request
    from geventwebsocket.websocket import WebSocket
    from geventwebsocket.handler import WebSocketHandler
    from gevent.pywsgi import WSGIServer
    import json
    
    
    app = Flask(__name__)
    
    user_socket_dict = {}  # 空字典,用来存放用户名和发送消息
    
    
    @app.route("/toy/<tid>")
    def toy(tid):
        # 获取请求的WebSocket对象
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
        if user_socket:
            # 设置键值对
            user_socket_dict[tid] = user_socket
            print(user_socket_dict)
            # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>}
    
        # 循环,接收消息
        while True:
            # 接收消息
            msg = user_socket.receive()
            print(msg)  # 打印
    
    
    if __name__ == '__main__':
        # 创建一个WebSocket服务器
        http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler)
        # 开始监听HTTP请求
        http_serv.serve_forever()
    View Code

    在templates 目录创建文件index.html,将之前的单聊的页面拿过来

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
    </head>
    <body>
    <audio src="" autoplay controls id="player"></audio>
    <br>
    <button onclick="start_reco()">开始废话</button>
    <br>
    <button onclick="stop_reco()">发送语音</button>
    </body>
    <script src="/static/recorder.js"></script>
    <script type="application/javascript">
        // 获取音频文件
        var get_file = "http://192.168.11.86:9527/get_audio/";
        // 创建 WebSocket 对象
        var ws = new WebSocket("ws://192.168.11.86:9528/toy/123456");
        var reco = null;
        // 创建AudioContext对象
        var audio_context = new AudioContext();
        //要获取音频和视频
        navigator.getUserMedia = (navigator.getUserMedia ||
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.msGetUserMedia);
    
        // 拿到媒体对象,允许音频对象
        navigator.getUserMedia({audio: true}, create_stream, function (err) {
            console.log(err)
        });
    
        //创建媒体流容器
        function create_stream(user_media) {
            var stream_input = audio_context.createMediaStreamSource(user_media);
            // 给Recoder 创建一个空间,麦克风说的话,都可以录入。是一个流
            reco = new Recorder(stream_input);
    
        }
    
        function start_reco() {  //开始录音
            reco.record();  //往里面写流
        }
    
        function stop_reco() {  //停止录音
            reco.stop();  //停止写入流
            get_audio();  //调用自定义方法
            reco.clear();  //清空容器
        }
    
        function get_audio() {  // 获取音频
            reco.exportWAV(function (wav_file) {
                ws.send(wav_file);  //使用websocket连接发送数据给后端
            })
        }
    
        ws.onmessage = function (data) {  // 客户端接收服务端数据时触发
            // console.log(get_file + data.data);
            var content = JSON.parse(data.data);
            // 修改id为player的src属性,实现自动播放
            document.getElementById("player").src = get_file + content.data;
            console.log(content.from_user + "给你点了一首歌");
        }
    
    
    </script>
    </html>
    View Code

    将recorder.js,放到static目录。

    github下载地址为:

    https://github.com/mattdiamond/Recorderjs

    修改 manager.py,渲染index.html页面

    from flask import Flask, request,jsonify,render_template
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    from serv import get_file
    from serv import content
    
    app = Flask(__name__)
    
    app.register_blueprint(get_file.getfile)
    app.register_blueprint(content.cont)
    
    @app.route('/')
    def hello_world():
        return render_template("index.html")
    
    
    @app.route('/login',methods=["POST"])
    def login():
        """
        登陆验证
        :return: settings -> RET
        """
        try:
            RET["code"] = 1
            RET["msg"] = "用户名或密码错误"
            RET["data"] = {}
    
            username = request.form.get("username")
            password = request.form.get("password")
    
            user = MONGO_DB.users.find_one({"username": username, "password": password})
    
            if user:
                # 由于user中的_id是ObjectId对象,需要转化为字符串
                user["_id"] = str(user.get("_id"))
                RET["code"] = 0
                RET["msg"] = "欢迎登陆"
                RET["data"] = {"user_id": user.get("_id")}
    
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "登陆失败"
    
        return jsonify(RET)
    
    
    @app.route('/reg',methods=["POST"])
    def reg():
        """
        注册
        :return: {"code":0,"msg":"","data":""}
        """
        try:
            username = request.form.get("username")
            password = request.form.get("password")
            age = request.form.get("age")
            nickname = request.form.get("nickname")
            gender = request.form.get("gender")
            phone = request.form.get("phone")
    
            user_info = {
                "username": username,
                "password": password,
                "age": age,
                "nickname": nickname,
                "gender": gender,
                "phone": phone
            }
    
            res = MONGO_DB.users.insert_one(user_info)
            user_id = str(res.inserted_id)
    
            RET["code"] = 0
            RET["msg"] = "注册成功"
            RET["data"] = user_id
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "注册失败"
    
        return jsonify(RET)
    
    
    @app.route('/user_info', methods=["POST"])
    def user_info():
        user_id = request.form.get("user_id")
    
        # "password": 0 表示忽略密码字段
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}, {"password": 0})
        if res:
            res["_id"] = str(res.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = res
    
        return jsonify(res)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 9527, debug=True)
    View Code

    此时目录结构如下:

    ./
    ├── audio
    ├── audio_img
    ├── im_serv.py
    ├── manager.py
    ├── serv
    │   ├── content.py
    │   └── get_file.py
    ├── setting.py
    ├── static
    │   └── recorder.js
    ├── templates
    │   └── index.html
    └── xiaopapa.py

    访问首页:

    http://127.0.0.1:9527/

    注意:千万不要用IP访问,否则点击开始废话时,console会报错!

    DOMException: Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).
    (index):44 Uncaught TypeError: Cannot read property 'record' of null

    提示 只有安全的来源是允许的。什么意思呢?就是说,这个链接,必须使用HTTPS连接。涉及HTTPS,必然就要买证书了!

    当然了,证书又很贵!这里推荐bootcdn使用的免费证书,参考链接:

    https://blog.bootcdn.cn/only-https/

    访问首页之后,Pycharm控制台就会输出:

    {'123456': <geventwebsocket.websocket.WebSocket object at 0x0000016DFC2BBE18>}

    这个123456是从哪里来的呢?是用index.html来的,看这一行代码

    var ws = new WebSocket("ws://192.168.11.86:9528/toy/123456");

    这里,我指定的id为123456,后端接收后,以id为键。那么打印出一个字典!

    点击页面的开始废话,再点击停止

    查看Pycharm控制台输出:

    bytearray(b'RIFF$@x03x00WAVEfmt...)

     输出了bytearray数据类型,它可以直接保存为音频文件!

    修改im_serv.py,判断类型,保存文件

    from flask import Flask, request
    from geventwebsocket.websocket import WebSocket
    from geventwebsocket.handler import WebSocketHandler
    from gevent.pywsgi import WSGIServer
    import json
    
    
    app = Flask(__name__)
    
    user_socket_dict = {}  # 空字典,用来存放用户名和发送消息
    
    
    @app.route("/toy/<tid>")
    def toy(tid):
        # 获取请求的WebSocket对象
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
        if user_socket:
            # 设置键值对
            user_socket_dict[tid] = user_socket
            print(user_socket_dict)
            # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>}
    
        # 循环,接收消息
        while True:
            # 接收消息
            msg = user_socket.receive()
            print(msg)  # 打印
            if type(msg) == bytearray:
                with open('123.wav','wb') as f:
                    f.write(msg)  # 写入文件
    
    
    if __name__ == '__main__':
        # 创建一个WebSocket服务器
        http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler)
        # 开始监听HTTP请求
        http_serv.serve_forever()
    View Code

    重启im_serv.py

    再次访问首页,录一段音。查看flask项目,会生成一个123.wav文件

    直接播放这个文件,是有声音的!

    注意:这个页面,就代指了玩具!

    三、app通过websocket远程遥控玩具播放内容

    现在手机APP,也需要通过websocket连接服务器。那么手机能不能也连接 ws://192.168.11.86:9528/toy/123456 

    呢?可以的!但是我不想让手机连接它。因为手机发送的数据,不一定是bytearray,也有可能是字符串。

    需要重新写一个接口

    修改im_serv.py,增加视图函数user_app

    from flask import Flask, request
    from geventwebsocket.websocket import WebSocket
    from geventwebsocket.handler import WebSocketHandler
    from gevent.pywsgi import WSGIServer
    import json
    
    
    app = Flask(__name__)
    
    user_socket_dict = {}  # 空字典,用来存放用户名和发送消息
    
    
    @app.route("/toy/<tid>")
    def toy(tid):  # 玩具连接
        # 获取请求的WebSocket对象
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
        if user_socket:
            # 设置键值对
            user_socket_dict[tid] = user_socket
            print(user_socket_dict)
            # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>}
    
        # 循环,接收消息
        while True:
            # 接收消息
            msg = user_socket.receive()
            print(msg)  # 打印
            if type(msg) == bytearray:
                print(11)
                with open('123.wav','wb') as f:
                    f.write(msg)  # 写入文件
    
    
    @app.route("/app/<uid>")
    def user_app(uid):  # 手机app连接
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
        if user_socket:
            user_socket_dict[uid] = user_socket
            # { uid : websocket}
            print(user_socket_dict)
        while True:  # 手机听歌 把歌曲发送给 玩具 1.将文件直接发送给玩具 2.将当前听的歌曲名称或ID发送到玩具
            msg = user_socket.receive()
            print(msg)
    
    
    if __name__ == '__main__':
        # 创建一个WebSocket服务器
        http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler)
        # 开始监听HTTP请求
        http_serv.serve_forever()
    View Code

    修改MyApp里面的player.html,增加按钮,发送给玩具

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
                <button type="button" class="mui-btn mui-btn-yellow mui-btn-block" id="pause">暂停</button>
                <button type="button" class="mui-btn mui-btn-green mui-btn-block" id="resume">继续</button>
                <button type="button" class="mui-btn mui-btn-red mui-btn-block" id="stop">停止</button>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="send2toy">发送给玩具</button>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;  //当前web页面
            var player = null;  //播放对象
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
    
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        // 修改标题
                        document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
                        // 修改图片地址
                        document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
                        // 调用自定义方法,播放音频
                        // data是后端返回的数据,data.audio是音频文件名
                        play_anything(data.data.audio);
                    }
                );
                
                function play_anything(content) {  //播放音频
                    // 创建播放对象,拼接路径
                    player = plus.audio.createPlayer(window.serv_audio + content);
                    console.log(window.serv_audio + content);  //打印路径
                    //  http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
                    player.play();  // 播放音频
                }
                
                document.getElementById("play").addEventListener("tap", function() {
                    player.play();
                });
        
                document.getElementById("pause").addEventListener("tap", function() {
                    player.pause();  //暂停
                });
                
                document.getElementById("resume").addEventListener("tap", function() {
                    player.resume();  //继续
                });
                
                document.getElementById("stop").addEventListener("tap", function() {
                    player.stop(); // 停止,直接清空player中的对象
                });
                
            })
        </script>
    
    </html>
    View Code

    使用模拟器访问,效果如下:

    建立连接

    需要在APP中使用websocket,那么在什么时候,建立连接呢?

    应该是在用户登录之后,点击首页时,建立websocket连接

    修改mui.js,增加全局变量 ws_serv

    ...
    window.ws_serv = "192.168.11.86:9528";
    window.serv = "http://192.168.11.86:9527";
    window.serv_imge = window.serv+"/get_image/";
    window.serv_audio = window.serv+"/get_audio/";
    ...

    修改index.html,判断登录状态,建立连接

    <!DOCTYPE html>
    <html>
    
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <title></title>
            <script src="js/mui.js"></script>
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <nav class="mui-bar mui-bar-tab">
                <a class="mui-tab-item mui-active" id="index">
                    <span class="mui-icon mui-icon-home"></span>
                    <span class="mui-tab-label">首页</span>
                </a>
                <a class="mui-tab-item" id="phone">
                    <span class="mui-icon mui-icon-phone"></span>
                    <span class="mui-tab-label">电话</span>
                </a>
                <a class="mui-tab-item">
                    <span class="mui-icon mui-icon-email"></span>
                    <span class="mui-tab-label">邮件</span>
                </a>
                <a class="mui-tab-item" id="login">
                    <span class="mui-icon mui-icon-gear"></span>
                    <span class="mui-tab-label">设置</span>
                </a>
            </nav>
        </body>
        <script type="text/javascript" charset="utf-8">
            var ws = null;  // websocket对象
            mui.init({
                subpages: [{
                    url: "main.html",
                    id: "main.html",
                    styles: window.styles
                }]
            });
            mui.plusReady(function() {
    //            console.log(JSON.stringify(plus.webview.currentWebview()))
                if(plus.storage.getItem("user")) {  // 判断是否登录
                    console.log('已结登录了!');
                    //连接websocket连接
                    ws = new WebSocket("ws://"+window.ws_serv+"/app/"+plus.storage.getItem("user"))
                    // 客户端接收服务端数据时触发
                    ws.onmessage = function() {};
                } 
            });
    
            document.getElementById("phone").addEventListener("tap", function() {
                mui.toast("你點擊了電話按鈕");
    
                mui.openWindow({
                    url: "phone.html",
                    id: "phone.html",
                    styles: window.styles,
                    extras: {
                        user_id: 123456
                    }
                })
            })
    
            document.getElementById("index").addEventListener("tap", function() {
                mui.openWindow({
                    url: "main.html",
                    id: "main.html",
                    styles: window.styles
                })
            })
    
            document.getElementById("login").addEventListener("tap", function() {
                mui.openWindow({
                    url: "login.html",
                    id: "login.html",
                    styles: window.styles
                })
            })
            
            document.addEventListener("login",function(data){
                // fire事件接收消息,使用data.detail
                // index是为做显示区分
                mui.toast("index"+data.detail.msg)
            })
        </script>
    
    </html>
    View Code

    注意:必须写在 mui.plusReady 里面

    使用模拟器打开登录页面

    登录成功之后,点击首页

    查看Pycharm控制台输出

    {'5b9bb768e1253281608e96eb': <geventwebsocket.websocket.WebSocket object at 0x0000027DC1F0BE18>}

    这个时候,建立了一个连接!

    前面的 5b9bb768e1253281608e96eb是MongoDB用户表记录的_id字段!

    那么在后端flask里面的im_sevr.py中。user_socket_dict保存了所有的websocket连接!它们之间,就可以进行一对一通讯了!

    一对一通讯

    需求:播放页面的歌曲,通过websocket,将歌曲名发给web玩具进行播放!

    修改player.html,需要将歌曲名发送给index.html页面。为什么呢?因为index.html建立了websocket连接。注意:index.html的webview的视图id为HBuilder

    使用fire传值

    <!doctype html>
    <html>
    
        <head>
            <meta charset="UTF-8">
            <title></title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title" id="title_text">正在播放</h1>
            </header>
            <div class="mui-content">
                <div class="mui-row" style="text-align: center;margin-top: 5px;">
                    <img src="avatar/girl.jpg" style=" 250px;height: 250px; border-radius: 50%;" id="avatar" />
                </div>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="play">播放</button>
                <button type="button" class="mui-btn mui-btn-yellow mui-btn-block" id="pause">暂停</button>
                <button type="button" class="mui-btn mui-btn-green mui-btn-block" id="resume">继续</button>
                <button type="button" class="mui-btn mui-btn-red mui-btn-block" id="stop">停止</button>
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="send2toy">发送给玩具</button>
            </div>
    
        </body>
        <script src="js/mui.js"></script>
        <script type="text/javascript">
            mui.init();
            var Sdata = null;  //当前web页面
            var music_name = null;  //歌曲名
            var player = null;  //播放对象
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();  // 当前web页面
                mui.toast(Sdata.content_id);  // 弹窗显示由main.html传递的content_id
    
                //发送post请求
                mui.post(
                    window.serv + "/content_one", {
                        // 参数为content_id
                        content_id: Sdata.content_id
                    },
                    function(data) {
                        // 打印响应数据
                        console.log(JSON.stringify(data));
                        // 修改标题
                        document.getElementById("title_text").innerText = "正在播放 : " + data.data.title;
                        // 修改图片地址
                        document.getElementById("avatar").src = window.serv_imge + data.data.avatar;
                        // 调用自定义方法,播放音频
                        // data是后端返回的数据,data.audio是音频文件名
                        music_name = data.data.audio;  // 歌曲名
                        play_anything(music_name);  //播放歌曲
                    }
                );
                
                function play_anything(content) {  //播放音频
                    // 创建播放对象,拼接路径
                    player = plus.audio.createPlayer(window.serv_audio + content);
                    console.log(window.serv_audio + content);  //打印路径
                    //  http://192.168.11.86:9527/get_audio/a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3
                    player.play();  // 播放音频
                }
                
                document.getElementById("play").addEventListener("tap", function() {
                    player.play();
                });
        
                document.getElementById("pause").addEventListener("tap", function() {
                    player.pause();  //暂停
                });
                
                document.getElementById("resume").addEventListener("tap", function() {
                    player.resume();  //继续
                });
                
                document.getElementById("stop").addEventListener("tap", function() {
                    player.stop(); // 停止,直接清空player中的对象
                });
                
                //发送给玩具
                document.getElementById("send2toy").addEventListener("tap", function() {
                    var index = plus.webview.getWebviewById("HBuilder");  //index.html页面
                    mui.fire(index, "send_music", {  //发送音乐
                        music_name: music_name,  //歌曲名
                        toy_id:"123456"  // 发给玩具id为12345
                    })
                });
                
            })
        </script>
    
    </html>
    View Code

    修改index.html,监听send_music事件

    <!DOCTYPE html>
    <html>
    
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <title></title>
            <script src="js/mui.js"></script>
            <link href="css/mui.min.css" rel="stylesheet" />
        </head>
    
        <body>
            <nav class="mui-bar mui-bar-tab">
                <a class="mui-tab-item mui-active" id="index">
                    <span class="mui-icon mui-icon-home"></span>
                    <span class="mui-tab-label">首页</span>
                </a>
                <a class="mui-tab-item" id="phone">
                    <span class="mui-icon mui-icon-phone"></span>
                    <span class="mui-tab-label">电话</span>
                </a>
                <a class="mui-tab-item">
                    <span class="mui-icon mui-icon-email"></span>
                    <span class="mui-tab-label">邮件</span>
                </a>
                <a class="mui-tab-item" id="login">
                    <span class="mui-icon mui-icon-gear"></span>
                    <span class="mui-tab-label">设置</span>
                </a>
            </nav>
        </body>
        <script type="text/javascript" charset="utf-8">
            var ws = null;  // websocket对象
            mui.init({
                subpages: [{
                    url: "main.html",
                    id: "main.html",
                    styles: window.styles
                }]
            });
            mui.plusReady(function() {
    //            console.log(JSON.stringify(plus.webview.currentWebview()))
                if(plus.storage.getItem("user")) {  // 判断是否登录
                    console.log('已结登录了!');
                    //连接websocket连接
                    ws = new WebSocket("ws://"+window.ws_serv+"/app/"+plus.storage.getItem("user"))
                    // 客户端接收服务端数据时触发
                    ws.onmessage = function() {};
                } 
            });
    
            document.getElementById("phone").addEventListener("tap", function() {
                mui.toast("你點擊了電話按鈕");
    
                mui.openWindow({
                    url: "phone.html",
                    id: "phone.html",
                    styles: window.styles,
                    extras: {
                        user_id: 123456
                    }
                })
            })
    
            document.getElementById("index").addEventListener("tap", function() {
                mui.openWindow({
                    url: "main.html",
                    id: "main.html",
                    styles: window.styles
                })
            })
    
            document.getElementById("login").addEventListener("tap", function() {
                mui.openWindow({
                    url: "login.html",
                    id: "login.html",
                    styles: window.styles
                })
            })
            
            document.addEventListener("login",function(data){
                // fire事件接收消息,使用data.detail
                // index是为做显示区分
                mui.toast("index"+data.detail.msg)
            });
            
            document.addEventListener("send_music", function(data) {  //监听send_music事件
                var music_name = data.detail.music_name;  //获取player.html使用fire发送的music_name值
                var toy_id = data.detail.toy_id;  //获取发送的玩具id
                
                send_str = {  //构造数据
                    music_name:music_name,
                    toy_id:toy_id
                }  
                // 发送数据给后端,注意要json序列化
                ws.send(JSON.stringify(send_str));
            });
            
        </script>
    
    </html>
    View Code

    刷新web玩具页面,此时有2个websocket连接

    {'5b9bb768e1253281608e96eb': <geventwebsocket.websocket.WebSocket object at 0x0000027DC1FE1F50>, '123456': <geventwebsocket.websocket.WebSocket object at 0x0000027DC20001E8>}
    View Code

    使用模拟器访问首页,随便点击一首歌。它会自动播放,点击暂停,再点击发送给玩具

    此时Pycharm输出一条信息:

    {"music_name":"a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3","toy_id":"123456"}

    歌曲名,获取到了。这里面的123456,是有player.html发送给index.html的!

    网页播放音乐

    这个时候,需要后端接收消息并处理了

    修改im_serv.py

    from flask import Flask, request
    from geventwebsocket.websocket import WebSocket
    from geventwebsocket.handler import WebSocketHandler
    from gevent.pywsgi import WSGIServer
    import json
    
    
    app = Flask(__name__)
    
    user_socket_dict = {}  # 空字典,用来存放用户名和发送消息
    
    
    @app.route("/toy/<tid>")
    def toy(tid):  # 玩具连接
        # 获取请求的WebSocket对象
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
        if user_socket:
            # 设置键值对
            user_socket_dict[tid] = user_socket
            print(user_socket_dict)
            # {'123456': <geventwebsocket.websocket.WebSocket object at 0x00000176ABD92E18>}
    
        # 循环,接收消息
        while True:
            # 接收消息
            msg = user_socket.receive()
            print(msg)  # 打印
            if type(msg) == bytearray:
                print(11)
                with open('123.wav','wb') as f:
                    f.write(msg)  # 写入文件
    
    
    @app.route("/app/<uid>")
    def user_app(uid):  # 手机app连接
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
        if user_socket:
            user_socket_dict[uid] = user_socket
            # { uid : websocket}
            print(user_socket_dict)
        while True:  # 手机听歌 把歌曲发送给 玩具 1.将文件直接发送给玩具 2.将当前听的歌曲名称或ID发送到玩具
            msg = user_socket.receive()
            msg_dict = json.loads(msg)  # 接收值,由于APP发送的是json,需要反序列化
            # {"music_name": "a6d680fe-fa80-4a54-82b8-b203f5a9c7b4.mp3", "toy_id": "123456"}
            user_id = msg_dict.get("toy_id")  # 获取toy_id
            music_name = msg_dict.get("music_name")  # 获取歌曲名
            # 从user_socket_dict这个大字典中获取
            other_user_socket = user_socket_dict.get(user_id)  # 获取APP用户的websocket对象
            # 构造数据
            send_str = {
                "code": 0,
                "from_user": uid,  # APP用户id
                "data": music_name  # 歌曲名
            }
            
            # 发送给web玩具页面,注意:不能是jsonify,它是针对于HTTP请求,会设置响应头
            # 这里是websocket连接,只能用json.dumps
            other_user_socket.send(json.dumps(send_str))
    
    if __name__ == '__main__':
        # 创建一个WebSocket服务器
        http_serv = WSGIServer(("0.0.0.0", 9528), app, handler_class=WebSocketHandler)
        # 开始监听HTTP请求
        http_serv.serve_forever()
    View Code

    重启 im_serv.py

    重启之后,websocket连接就丢失了!

    先访问web玩具页面

    http://127.0.0.1:9527/

    将模拟器中的HBuilder进程关闭,重启开启,并登陆。

    点击一首歌曲,点击暂停,再点击一次发送给玩具!

    此时,播放按钮,会播放音乐。

    效果如下:

    为什么,点击网页的播放按钮,就能播放指定的音乐呢?

    查看flask中的templates-->index.html,这一段代码

    ws.onmessage = function (data) {  // 客户端接收服务端数据时触发
            // console.log(get_file + data.data);
            var content = JSON.parse(data.data);
            // 修改id为player的src属性,实现自动播放
            document.getElementById("player").src = get_file + content.data;
            console.log(content.from_user + "给你点了一首歌");
        }

    注意:ws.onmessage是接收到数据时,会自动触发!

    那么它接收到什么数据了呢?接收了一个json数据。序列化之后,应该是这个样子

    {code: 0, from_user: "5b9bb768e1253281608e96eb", data: "4ed490e8-aded-4f23-8a7c-c845e48ec778.mp3"}

    那么它就会修改页面的src属性。那么页面点击播放,就可以播放音乐了!

    四、玩具管理页面

    默认登录之后,会跳转到用户信息页面,这里需要展示用户头像。

    但是数据库少了头像字段。

    使用客户端工具访问用户表

    默认的ORM语句为:

    db.users.find({})

    目前只有一个用户

     

    增加一个字段avatar,这个表示头像

    db.users.updateMany({"username":"xiao"},{$set:{"avatar":"boy.jpg"}})

    修改flask后端的 的注册函数,增加avatar字段

    from flask import Flask, request,jsonify,render_template
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    from serv import get_file
    from serv import content
    
    app = Flask(__name__)
    
    app.register_blueprint(get_file.getfile)
    app.register_blueprint(content.cont)
    
    @app.route('/')
    def hello_world():
        return render_template("index.html")
    
    
    @app.route('/login',methods=["POST"])
    def login():
        """
        登陆验证
        :return: settings -> RET
        """
        try:
            RET["code"] = 1
            RET["msg"] = "用户名或密码错误"
            RET["data"] = {}
    
            username = request.form.get("username")
            password = request.form.get("password")
    
            user = MONGO_DB.users.find_one({"username": username, "password": password})
    
            if user:
                # 由于user中的_id是ObjectId对象,需要转化为字符串
                user["_id"] = str(user.get("_id"))
                RET["code"] = 0
                RET["msg"] = "欢迎登陆"
                RET["data"] = {"user_id": user.get("_id")}
    
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "登陆失败"
    
        return jsonify(RET)
    
    
    @app.route('/reg',methods=["POST"])
    def reg():
        """
        注册
        :return: {"code":0,"msg":"","data":""}
        """
        try:
            username = request.form.get("username")
            password = request.form.get("password")
            age = request.form.get("age")
            nickname = request.form.get("nickname")
            gender = request.form.get("gender")
            phone = request.form.get("phone")
    
            user_info = {
                "username": username,
                "password": password,
                "age": age,
                "nickname": nickname,
                # 判断gender==2,成立时为girl.jpg,否则为boy.jpg
                "avatar": "girl.jpg" if gender == 2 else "boy.jpg",
                "gender": gender,
                "phone": phone
            }
    
            res = MONGO_DB.users.insert_one(user_info)
            user_id = str(res.inserted_id)
    
            RET["code"] = 0
            RET["msg"] = "注册成功"
            RET["data"] = user_id
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "注册失败"
    
        return jsonify(RET)
    
    
    @app.route('/user_info', methods=["POST"])
    def user_info():
        user_id = request.form.get("user_id")
    
        # "password": 0 表示忽略密码字段
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}, {"password": 0})
        if res:
            res["_id"] = str(res.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = res
    
        return jsonify(res)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 9527, debug=True)
    View Code

    进入HBuilder的项目MyApp,修改user_info.html,增加头像

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <h1 class="mui-title">用户信息</h1>
            </header>
            <div class="mui-content">
                <ul class="mui-table-view">
                    <div class="mui-row" style="text-align: center;">
                        <img src="" id="avatar" style=" 250px;height: 250px; border-radius: 100%;"/>
                    </div>
                    <li class="mui-table-view-cell"><span>用户名</span><span id="username" class="mui-pull-right">111</span></li>
                    <li class="mui-table-view-cell"><span>昵称</span><span id="nickname" class="mui-pull-right">22</span></li>
                </ul>
    
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="logout">退出登陆</button>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            mui.back = function() {};
            mui.plusReady(function() {
                var Sdata = plus.webview.currentWebview();
                mui.post(
                    window.serv + "/user_info", {
                        user_id: Sdata.user_id
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        console.log("wfdsfdsafdsafas");
                        document.getElementById("username").innerText = data.username;
                        document.getElementById("nickname").innerText = data.nickname;
                        // 修改头像地址
                        document.getElementById("avatar").src = "avatar/" + data.avatar;
    //                    console.log("avatar/" + data.avatar);
                    }
                )
            })
    
            document.getElementById("logout").addEventListener("tap", function() {
                plus.storage.removeItem("user")
                mui.openWindow({
                    url: "login.html",
                    id: "login.html",
                    styles: window.styles
                })
            });
            
    
        </script>
    
    </html>
    View Code

    使用模拟器重新登录,效果如下:

    修改user_info.html,增加一行,用来管理玩具。并增加点击事件

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <h1 class="mui-title">用户信息</h1>
            </header>
            <div class="mui-content">
                <ul class="mui-table-view">
                    <div class="mui-row" style="text-align: center;">
                        <img src="" id="avatar" / style=" 250px;height: 250px; border-radius: 100%;">
                    </div>
                    <li class="mui-table-view-cell"><span>用户名</span><span id="username" class="mui-pull-right">111</span></li>
                    <li class="mui-table-view-cell"><span>昵称</span><span id="nickname" class="mui-pull-right">22</span></li>
                </ul>
                <ul class="mui-table-view">
                    <li class="mui-table-view-cell" id="toy_manager"><i class="mui-icon mui-icon-qq"></i>管理我的玩具</li>
    
                </ul>
    
                <button type="button" class="mui-btn mui-btn-blue mui-btn-block" id="logout">退出登陆</button>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            mui.back = function() {};
            mui.plusReady(function() {
                var Sdata = plus.webview.currentWebview();
                mui.post(
                    window.serv + "/user_info", {
                        user_id: Sdata.user_id
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        console.log("wfdsfdsafdsafas");
                        document.getElementById("username").innerText = data.username;
                        document.getElementById("nickname").innerText = data.nickname;
                        // 修改头像地址
                        document.getElementById("avatar").src = "avatar/" + data.avatar;
    //                    console.log("avatar/" + data.avatar);
                    }
                )
            })
    
            document.getElementById("logout").addEventListener("tap", function() {
                plus.storage.removeItem("user")
                mui.openWindow({
                    url: "login.html",
                    id: "login.html",
                    styles: window.styles
                })
            });
            
            // 管理玩具页面
            document.getElementById("toy_manager").addEventListener("tap", function() {
                mui.openWindow({
                    url: "toy_manager.html",
                    id: "toy_manager.html",
                })
            });
            
    
        </script>
    
    </html>
    View Code

    新建文件 toy_manager.html

    新建目录image,用来保存添加按钮的图片

    从网络上面,搜索一个添加按钮图片,放到此目录!

    此时,目录结构如下:

    ./
    └── MyApp
        ├── avatar
        │   ├── boy.jpg
        │   └── girl.jpg
        ├── css
        │   ├── mui.css
        │   └── mui.min.css
        ├── fonts
        │   └── mui.ttf
        ├── images
        │   └── add.png
        ├── index.html
        ├── js
        │   ├── md5.min.js
        │   ├── mui.js
        │   └── mui.min.js
        ├── login.html
        ├── main.html
        ├── manifest.json
        ├── phone.html
        ├── player.html
        ├── reg.html
        ├── toy_manager.html
        ├── unpackage
        └── user_info.html
    View Code

    修改 toy_manager.html

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">管理我的玩具</h1>
            </header>
            <div class="mui-content">
                <ul class="mui-table-view" id="toy_list">
                    <li class="mui-table-view-cell mui-media">
                        <a id="add_toy">
                            <img class="mui-media-object mui-pull-left" src="images/add.png">
                            <div class="mui-media-body">
                                你还没有玩具
                                <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p>
                            </div>
                        </a>
                    </li>
                </ul>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
    
            function create_content(content) {
                var litag = document.createElement("li");
                litag.className = "mui-table-view-cell mui-media";
                var atag = document.createElement("a");
                atag.id = content._id;
                // 点击事件 周一把这儿写了 绑定事件
                atag.onclick = function() {
                    console.log(this.id);
                    openPlayer(this.id);
                }
    
                var imgtag = document.createElement("img");
                imgtag.className = "mui-media-object mui-pull-left";
    
                imgtag.src = window.serv_imge + content.avatar;
    
                var divtag = document.createElement("div");
                divtag.className = "mui-media-body";
                divtag.innerText = content.title;
                var ptag = document.createElement("p");
                ptag.className = "mui-ellipsis";
                ptag.innerText = content.intro;
    
                litag.appendChild(atag);
                atag.appendChild(imgtag);
                atag.appendChild(divtag);
                divtag.appendChild(ptag);
    
                document.getElementById("toy_list").appendChild(litag);
    
            }
    
            document.getElementById("add_toy").addEventListener("tap", function() {
                mui.openWindow({
                    url: "扫描二维码.html",
                    id: "扫描二维码.html",
                })
            })
        </script>
    
    </html>
    View Code

    重新登录,效果如下:

    总结:

    1. app端内容播放
        听歌:plus.audio
        创建:var player = plus.audio.createPlay(内容的URL路径) //苹果暂时不支持HTTP
        开始播放 : player.play()
        暂停播放 :player.pause()
        继续播放 :player.resume()
        停止播放 :player.stop() 清空player中对象
        
    
    2. 手动写一个web端的玩具(小剧情)
        硬件需要时间,咱们先写一个协议,然后开发一个初级硬件暂时先顶上,用了一周的事件做了一个LowB的硬件
        事件:    中午吃饭忘了关闭硬件,结果芯片过热,造成芯片烧毁,烧毁了一个桌面,烫坏了一个显示器,键盘没了一半儿
                老张呵斥硬件部:工程开发板不允许再次使用,所有压力全部在软件部,自己写一个Web模拟玩具收发消息
            
        
    
    3. app通过websocket 事件远程遥控玩具播放内容
    websocket 在整个app中只能存在一个
    app 端 :
        mui.fire(ws页面,"事件",{data})
    ws页面:
        document.addEventListener("事件",function(data){
            data.detail
        })
    
    开启websocket服务 - 
    两个接口 app toy - 
    两个前端 连接 websocket - 
    {user:websocket,toy:websocket}
    appuser 发送了一个字符串给服务端 {toy_id:123456,content_id:tyuiop123r234}
    通过字符串中的toy_id 拿到 websocket_dict 中的 toy websocket
    可以给 toy 中的websocket 发送消息了
    toy.send(json.dumps({}))
    View Code

    完整代码,请参考github:

    https://github.com/987334176/Intelligent_toy/archive/v1.1.zip

  • 相关阅读:
    shell变量解析
    visual studio code(vscode)使用
    linux虚拟机安装
    算法总结系列之八:复读机的故事散列表及其在.NET中的应用浅析(上集)
    对改善Dictionary时间性能的思考及一个线程安全的Dictionary实现
    算法总结系列之八:复读机的故事 散列表.NET应用的研究(下集)
    使用WiX打包你的应用程序之二向WiX脚本传递信息(属性)的几种方式
    当心Dictionary带来的一种隐式内存泄漏
    从DWG到XAML (II) DWFx格式解析及其和XPS的关系
    从DWG到XAML (I) 浅谈DWG历史,现状及方向
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9662372.html
Copyright © 2011-2022 走看看