动手实现微信小程序和小游戏编译打包和运行环境平台(核心篇二)
发表时间:2023-11-21 17:13:32
文章来源:炫佑科技
浏览次数:148
菏泽炫佑科技 菏泽炫佑小程序开发 菏泽炫佑app制作 炫佑科技
动手实现微信小程序和小游戏编译打包和运行环境平台(核心篇二)
上面我们了解到小程序开发工具中的消息是通过协议来发送和接收的。 当然,这并不是凭空说出来的。 由小程序逻辑层.js源码中的代码表示。 至于它还有一些消息格式我没有列出。 比如它的数据分析以及上报给自己服务器的一些消息格式需要首先关注。
我先给大家展示一下查找.js源代码文件的过程。
可以看到它的链接地址以及数据发送和接收的部分代码。 由于图片大小,我折叠了部分代码。 你可以自己仔细看看。
我先简单介绍一下一些知识,可能有些同学对这方面还不是很熟悉。 具体的本文就不赘述了,后面会专门写一篇介绍。
什么是
其实这些内容我们可以通过搜索获取很多资料,但是是否真正了解是否可以在自己的项目中灵活设计应用或者简单的使用文档API,还需要我们更多的探索和思考我们自己的。
下图为协议内容:
可以理解为:该协议允许在受控环境中运行不受信任代码的用户代理和选择从该代码进行通信的远程主机之间进行双向通信。简单的描述是:客户端之间存在持久连接和服务器,双方可以随时随地互相发送数据。
为什么使用
一个新标准或者一项新技术的诞生,一定是为了解决或者改进之前解决方案的缺点,这样进步才能持续下去。
我们使用 HTTP 并且它之前运行良好。 但随着一些应用的要求,如聊天、炒股游戏等对数据实时性要求较高的情况,如果采用HTTP协议发送数据,则只能由客户端发起单方请求。 服务器响应以获取*新数据。 如果服务器上的数据变化很快,比如股票信息,那么只能定期请求,效率低下动手实现微信小程序和小游戏编译打包和运行环境平台(核心篇二),浪费资源,而且数据不实时同步。 为了解决这些问题,我们对协议进行了研究。 首次亮相。
一些优点:
如何使用
这一点是比较宽泛的。 新方案、新技术的产生都会经历一个由浅入深的发展过程。 主要还是看每个人自己的具体设计和使用。 下面的知识点链接可以让大家先了解一下这个概念和基本使用。 本章不再衍生相关内容。
(如果您对深度学习感兴趣,请关注我后续专栏)
这是一个比较简单的网页,可以在线查看效果。
如果有同学想自己尝试一下,我在我的仓库里写了一个*简单的服务端和客户端的案例。 总共10行以上代码比较方便。 有兴趣的朋友可以查看案例地址()
执行index.js后效果如下:
在接下来的内容中,我将结合一些应用程序设计和部分代码展示来实现这个小程序的运行环境。
我们回到正题,首先在源码.js的发送和接收区域添加一些日志保存。 这里我们必须要完全退出工具进程才可以打开,否则是无法工作的。
然后我们重新进入开发工具,打开一个小程序项目。 我打开官方的云开发项目示例可以看到:
从这张图中我们可以看到一些信息。 我给大家简单介绍一下:
数据发送部分
send===>{"command":"APPSERVICE_INVOKE","data":{"api":"operateWXData","args":{"data":{"api_name":"qbase_commapi","data":{"qbase_api_name":"tcbapi_init","qbase_req":"{\"trace_user\":true}","qbase_options":{},"qbase_meta":{"session_id":"1587696384156","sdk_version":"wx-miniprogram-sdk/2.9.5 (1578926697000)"},"cli_req_id":"1587696386661_0.5287857917854695"},"operate_directly":false},"isImportant":false,"requestInQueue":false,"apiName":"qbase_commapi","reqData":{"qbase_api_name":"tcbapi_init","qbase_req":"{\"trace_user\":true}","qbase_options":{},"qbase_meta":{"session_id":"1587696384156","sdk_version":"wx-miniprogram-sdk/2.9.5 (1578926697000)"},"cli_req_id":"1587696386661_0.5287857917854695"}},"callbackID":20}}
可以观察一些字段和对象(这是普通云开发项目默认打开时的状态微信小程序开发例子,是没有任何操作的例子,对象比较复杂)
你可能对这个API不是很熟悉,因为这个API不是微信外部的,而是内部使用的。 这不是我们现在要讲的重点。 我们现在要描述的内容是相关的。 至于API的实现,我们下面讨论如何实现小程序 小程序外部API进行了描述和解释。 这里我们需要知道的是它的消息传输格式。
数据接收部分
<====12receive {"command":"APPSERVICE_INVOKE_CALLBACK","data":{"callbackID":20,"res":{"errMsg":"operateWXData:ok","data":{"data":"{\"baseresponse\":{\"errcode\":0,\"stat\":{\"qbase_cost_time\":141}},\"tcb_api_list\":[{\"apiname\":\"tcbapi_db_adddocument\",\"status\":1},{\"apiname\":\"tcbapi_callfunction\",\"status\":1},{\"apiname\":\"tcbapi_component_gettempfileurl\",\"status\":1},{\"apiname\":\"tcbapi_db_countdocument\",\"status\":1},{\"apiname\":\"tcbapi_db_deletedocument\",\"status\":1},{\"apiname\":\"tcbapi_deletefile\",\"status\":1},{\"apiname\":\"tcbapi_downloadfile\",\"status\":1},{\"apiname\":\"tcbapi_gettempfileurl\",\"status\":1},{\"apiname\":\"tcbapi_db_querydocument\",\"status\":1},{\"apiname\":\"tcbapi_db_setdocument\",\"status\":1},{\"apiname\":\"tcbapi_slowcallfunction\",\"status\":1},{\"apiname\":\"tcbapi_slowcallfunction_v2\",\"status\":1},{\"apiname\":\"tcbapi_traceuser\",\"status\":1},{\"apiname\":\"tcbapi_uploadfile\",\"status\":1},{\"apiname\":\"tcbapi_db_updatedocument\",\"status\":1},{\"apiname\":\"tcbapi_init\",\"status\":1}],\"config\":{\"db_doc_size_limit\":524288,\"upload_max_file_size\":52428800,\"get_temp_file_url_max_requests\":50,\"call_function_poll_max_retry\":10,\"call_function_max_req_data_size\":5242880,\"call_function_client_poll_timeout\":15000,\"call_function_valid_start_retry_gap\":100000}}"}}}}
通过对比,我们可以看到上面核心章节所说的内容:
send===> "command":"APPSERVICE_INVOKE" "callbackID":20
receive===>"command":"APPSERVICE_INVOKE_CALLBACK" "callbackID":20
消息类型由发送层接收处理
实现浏览器运行环境服务通信设计的代码
这里使用node方法启动的服务首先创建一个服务器:
const ws = require('ws');
const EventEmitter = require('events');
class SocketServer extends EventEmitter {
constructor (options) {
super();
this.port = options.port;
this.wss = new ws.Server({ port: this.port });
this.socketClientMap = new SocketClientMap();
}
async start () {
this.wss.on('connection', ws => {
this.socketClientMap.addSocketClient(ws);
ws.on('close', () => {
this.socketClientMap.removeSocketClient(ws.protocol);
});
ws.on('message', async message => {
await this.handle(message);
});
});
this.on(SEND_MSG_TO_CONTROLLER, (message) => {
this.sendMessageToController(message);
});
this.on(SEND_MSG_TO_SPECIAL_WEBVIEW, ({ webviewId, message }) => {
this.sendMessageToSpecialWebview(webviewId, message);
});
this.running = true;
}}
创建客户端链接以发送和接收:
const WebSocket = require('ws');
class SocketClient {
constructor (ws) {
this.ws = ws;
this.msgQueue = [];
}
setWebSocket (ws) {
this.ws = ws;
this.msgQueue.forEach(msg => {
this.ws.send(JSON.stringify(msg));
});
this.msgQueue = [];
}
removeWebSocket () {
this.ws = null;
}
send (msg) {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
this.msgQueue.push(msg);
} else {
this.ws.send(JSON.stringify(msg));
}
}
}
上面两个类文件是比较简单的服务和客户端的创建。 这里创建了一个集合类:
class SocketClientMap {
constructor () {
this.socketClients = new Map();
}
addSocketClient (ws) {
let socketClient = this.socketClients.get(ws.protocol);
if (!socketClient) {
socketClient = new SocketClient(ws);
} else {
socketClient.setWebSocket(ws);
}
this.socketClients.set(ws.protocol, socketClient);
}
getSocketClient (protocol) {
let socketClient = this.socketClients.get(protocol);
if (!socketClient) {
socketClient = new SocketClient(protocol);
this.socketClients.set(protocol, socketClient);
}
return socketClient;
}
removeSocketClient (protocol) {
this.socketClients.delete(protocol);
}
loop (cb) {
this.socketClients.forEach((value, key) => cb(value, key));
}
};
新添加的方法
意思是,如果不存在,则在ws的基础上创建一个新的,否则,用新的ws替换旧的ws,这样消息队列中的消息被替换后可以立即发送到新的ws,保证可用性。
方法
调用该函数总是返回一个实例,以便用户可以随时发送消息。
以上几点主要集中在消息的格式和内容以及几个接收者和发送者的顺序上。 在下一篇文章中,我将通过几个常用的外部API以及具体代码的实现来描述具体的流程。