公司需求配合自动贩售机售卖化妆品小样,主要功能用户扫码登录小程序,获取兑换码,输入兑换码取货,管理人员操作贩售机控制界面进行货品数量设置。因为贩售机取货功能是由内置app控制的,它提供给前端一个取货sdk,需要前端设置一个html文件存储到app对应的文件中。但是都2021年了,不想完全使用原生开发界面,所以最后技术方案为,使用一个html文件,在该文件中调取sdk,通过iframe引入Vue写的功能页面,并使用PostMessage进入通信。
一、页面效果图
二、功能实现
1.1 html如何调用贩售机内置app提供的sdk
function spitGoodsByChannelPosition(row, col) {
console.log('位置', row, col)
// 掉货
window.WebViewJavascriptBridge.callHandler(
'spitGoodsByChannelPosition', {
'row': parseInt(row),'col': parseInt(col)},
function(responseData) {
// console.log(responseData)
}
);
}
function connectWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady',function() {
callback(WebViewJavascriptBridge)
},false);
}
}
connectWebViewJavascriptBridge(function(bridge) {
bridge.init(function(message, responseCallback) {
if (responseCallback) {
responseCallback(data);
}
});
bridge.registerHandler("receiveCommandFromSerialPort", function(data, responseCallback) {
appendLog("receiveCommandFromSerialPort: " + data)
if (responseCallback) {
var responseData = "Javascript Says Right back aka!";
responseCallback(responseData);
}
});
bridge.registerHandler("spitGoodsResult", function(data, responseCallback) {
// 这这个回调函数里可以拿到贩售机取货的结果返回值,进行后续与h5页面的通信,或者其他功能。。。
};
};
};
1.2 html中利用iframe引入vue h5链接地址
<div class="vending-machine-container">
<iframe src="vue h5的链接地址" id="myframe" frameborder="0" width="100%"></iframe>
</div>
1.3 html父页面、vue h5子页面互相通信
这里简单介绍下iframe + postMessage跨域通信
web是构建在同源策略基础之上,同源策略是浏览器的行为,是为了保护本地数据不被javascript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收,所以我们可以通过iframe来实现不同域之间互相请求资源。
(1)父页面向子页面传递数据
// 给子页面传递code var myframe = document.getElementById('myframe');
// 获取iframe的ID myframe.contentWindow.postMessage({ code: dataCode.errorCode }, '*');
(2)父页面接口来自子页面的数据
window.addEventListener("message", function(event) {
productCallParams = event.data;
console.log('event', event.data)
if (event.data) {
var row = event.data.position_x;
var col = event.data.position_y;
spitGoodsByChannelPosition(row, col);
}
}, false);
1.4 vue h5子页面(获取兑换码、后台管理)
此处代码就省略啦,一些大家都懂的交互代码。。。
重点说下sign的生成,后端同学为了防止多次重复提交,所以要求每个接口传递前端生成的sign值!
export function getSign(params, kAppSecret) {
let content;
let Base64 = require('js-base64').Base64;
if (typeof params == "string") {
content = params
} else if (typeof params == "object") {
var arr = [];
for (var i in params) {
arr.push(i + "=" + params[i]);
}
content = arr.join("&")
}
let urlStr = content.split("&").sort().join("&");
let hash = CryptoJS.HmacSHA256(urlStr, kAppSecret)
return Base64.encode(hash)
}
总的来说分为:
参与计算的
json数据
{
"key1":value1, # value的类型必需是数字、布尔、浮点或者字符串之一
"key2":value2,
}
秘钥 xxxx
第1步 将json数据结构的key按照ascii码从小到大排序,拼接成一个字符串
第2步 将字符串运行 hmac sha256算法,盐使用秘钥xxxx
第3步 将上一步得到的摘要base64编码,计算完成
坑:这里引入这些加密包的时候,由于贩售机最开始提供的app是安卓6.0系统,没法识别由npm安装的cryptojs包,所以改为直接把代码down下来放在util函数中,费了点儿功夫。
1.5 使用内网穿透工具花生壳实时预览最新测试功能
背景:贩售机内嵌index.html中通过iframe引入的vue h5地址如果做到实时更新,必须把代码发到测试或者正式上面,很麻烦,所以引入花生壳工具进行内网穿透,实时预览最新代码。
(1)没有设置自己的电脑IP,得到一个专有访问域名
(2)然后在vue项目中更改vue.config.js文件
设置publicPath为'./',disableHostCheck为true,重新启动Vue项目就可以了。
以上就是本功能的部分重点难点,仅此记录下。