如何在web浏览器页面使用IC卡读卡器并且兼容所有浏览器
2018-10-10 15:33:33
诺塔斯智能科技
385
随着H5技术的不断发展与推广,H5技术被广泛用于移动设备,PC终端等众多领域。同时,越来越多的应用都基于B/S(浏览器/服务器)模式,降低开发难度的同时还能更好的普及和应用,突破了硬件设备的兼容性问题。然而,嵌入式开发的设备并没有跟上H5技术的脚步,现在很多嵌入式设备并不支持或者不能友好的支持浏览器应用。举个例子,如何在web浏览器页面使用IC卡读卡器并且兼容所有浏览器?针对这个问题,有人肯定会说利用active X控件就可以了啊!确实如果是基于IE或者IE内核的浏览器使用active X是没有任何问题,但是现在除了使用IE浏览器还有大部分使用Chrome和Firefox等多种内核和版本的浏览器,为了让嵌入式设备更好的兼容所有浏览器,我们提供了一套基于在嵌入式设备中内置WebSocket组件的方案,希望能帮助大家在解决使用浏览器集成嵌入式设备中遇到的难题,一下仅以我司智能卡读写器做详细介绍。
传统的ActiveX组件,通过javascript页面与设备进行信息交互。
<HTML><HEAD><TITLE>第二代居民身份证网页ActiveX控件测试网页</TITLE> <OBJECT ID=LotusCardDriver Visible=false WIDTH=0 HEIGHT=0 CLASSID="CLSID:BD1874A5-3810-4639-8B70-3DDD607BAADB" CODEBASE="./lotus.CAB#version=1,0,0,4"> </OBJECT> <SCRIPT language=JavaScript> <!-- function ReadIDCard() { var nHandle = 0; //设备句柄 var bResult = 0; var strTextInfo = ""; var nErrorCode = 0; clearForm(); nHandle = LotusCardDriver.OpenDevice("",0,0,0); if(nHandle <=0 ) { alert("打开设备失败,或者你没有插入读卡器!购买读卡器,请点击 确定 "); window.location.href="https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-7912663678.8.HdHoCq&id=542822138758"; return; } bResult = LotusCardDriver.Beep(nHandle,10); if(bResult!=1) { alert("蜂鸣失败!"); LotusCardDriver.CloseDevice(nHandle); return; } bResult = LotusCardDriver.SetCardType(nHandle, 'B'); if(bResult!=1) { alert("设置卡类型失败!"); LotusCardDriver.CloseDevice(nHandle); return; } //使用1.0服务器 //bResult = LotusCardDriver.GetTwoIdInfoByServer(nHandle, '120.24.253.33'); //bResult = LotusCardDriver.GetTwoIdInfoByServer(nHandle, '192.168.1.101'); //使用调度服务器 bResult = LotusCardDriver.GetTwoIdInfoByMcuServer(nHandle, '112.124.37.59', 'UserName', 'Password', 2); if(bResult!=1) { nErrorCode = LotusCardDriver.GetTwoIdErrorCode(nHandle); alert("读取二代证信息失败!"+nErrorCode +LotusCardDriver.GetTwoIdErrorInfo(nHandle, nErrorCode)); LotusCardDriver.CloseDevice(nHandle); return; } //解析WL bResult = LotusCardDriver.WlDecodeByServer(nHandle, '120.24.249.49');//120.24.253.33 211.149.188.24 LotusCardDriver.CloseDevice(nHandle); fillForm(); /* var ret = CVR_IDCard.ReadCard(); if (ret == "0"){ fillForm(); return; } alert("读卡错误,错误原因:" + ret);*/ } function fillForm() { var pName=LotusCardDriver.TwoId_Name; var pSex=LotusCardDriver.TwoId_Sex; var pNation=LotusCardDriver.TwoId_Nation; var pBorn=LotusCardDriver.TwoId_Birthday; var pAddress=LotusCardDriver.TwoId_Address; var pCardNo=LotusCardDriver.TwoId_No; var pPolice=LotusCardDriver.TwoId_SignedDepartment; var pActivityLFrom=LotusCardDriver.TwoId_ValidityPeriodBegin; var pActivityLTo=LotusCardDriver.TwoId_ValidityPeriodEnd; var pDeviceNo=0;//LotusCardDriver.CardReaderId; var pPhotoBuffer=LotusCardDriver.TwoId_PhotoB64; document.all['Name'].value = pName; document.all['Sex'].value = pSex; document.all['Nation'].value = pNation; document.all['Born'].value = pBorn; document.all['Address'].value = pAddress; document.all['CardNo'].value = pCardNo; document.all['Police'].value = pPolice; document.all['ActivityLFrom'].value = pActivityLFrom; document.all['DeviceNo'].value = pDeviceNo; document.all['ActivityLTo'].value = pActivityLTo; document.all['PhotoBuffer'].value = pPhotoBuffer; document.all['PhotoDisplay'].src = 'data:image/jpg;base64,' + pPhotoBuffer; } function clearForm() { document.all['Name'].value = ''; document.all['Sex'].value = ''; document.all['Nation'].value = ''; document.all['Born'].value = ''; document.all['Address'].value = ''; document.all['CardNo'].value = ''; document.all['Police'].value = ''; document.all['ActivityLFrom'].value = ''; document.all['ActivityLTo'].value = ''; document.all['PhotoBuffer'].value = ''; document.all['PhotoDisplay'].src = ''; document.all['DeviceNo'].value = ''; } //--> </SCRIPT> <script> function gobackhome(){ window.location.href="index.html"; }
这种方式在非IE浏览器模式下无法使用,更别提Android和IOS系统上的浏览器了。为了解决在非IE浏览器模式下将我们智能卡读写器嵌入在浏览器中,而且能兼容所有浏览器。我们将读写器单片机里面内置了Websocket组件,读写器采用TCP/IP网络通信,不管是PC浏览器还是Android、IOS浏览器均能实现完美兼容。
范例代码如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>LotusCard WEB Socket演示页面</title> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name = "viewport" content = "width = 320, initial-scale = 1.0, user-scalable = yes"> <script language="javascript" type="text/javascript"> function getNowFormatDate() { var date = new Date(); var seperator1 = "-"; var seperator2 = ":"; var month = date.getMonth() + 1; var strDate = date.getDate(); var socket = null; var nCommandIndex = 0; var strIp = ""; var strPort = ""; var wsUrl = ""; if (month >= 1 && month <= 9) { month = "0" + month; } if (strDate >= 0 && strDate <= 9) { strDate = "0" + strDate; } var currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate + " " + date.getHours() + seperator2 + date.getMinutes() + seperator2 + date.getSeconds() + seperator2 + date.getMilliseconds(); return currentdate; } function ConnectServer(){ try { nCommandIndex = 0; strIp = document.getElementById('strLotusCardDeviceIp').value; strPort = document.getElementById('strLotusCardDevicePort').value; wsUrl = 'ws://'+ strIp +':'+strPort; socket = new WebSocket(wsUrl); } catch (evt) { document.getElementById('log').innerHTML = '<li><b>'+getNowFormatDate()+'#new WebSocket error:'+ evt.data+'</b></li>' + document.getElementById('log').innerHTML; socket = null; if (typeof(connCb) != "undefined" && connCb != null) connCb("-1", "connect error!"); return; } socket.onopen = function () { document.getElementById('log').innerHTML = '<li><b>'+getNowFormatDate()+'#连接服务器成功</b></li>' + document.getElementById('log').innerHTML; document.getElementById('status').innerHTML = 'Socket Open'; document.getElementById('status').className = 'online'; }; socket.onclose =function(event) { document.getElementById('log').innerHTML = '<li><b>'+getNowFormatDate()+'#断开连接:' + event.wasClean + '</b></li>' + document.getElementById('log').innerHTML; document.getElementById('status').innerHTML = 'Socket Closed'; document.getElementById('status').className = 'offline'; }; socket.onmessage = function(event) { var arrString; strLastResult = event.data; document.getElementById('log').innerHTML = '<li><b>'+getNowFormatDate()+'#收到数据:' + event.data + '</b></li>' + document.getElementById('log').innerHTML; // arrString = strLastResult.split(','); // if(COMMAND_OPEN_DEVICE == arrString[0]) // { // if(arrString.length>2) m_nHandle = arrString[2]; // document.getElementById('log').innerHTML = '<li><b>#获取设备句柄:' + m_nHandle + '</b></li>' + document.getElementById('log').innerHTML; // } //document.getElementById('log').innerHTML = '<li><b>#received:' + arrString[0] + '</b></li>' + document.getElementById('log').innerHTML; //document.getElementById('log').innerHTML = '<li><b>#received:' + arrString.length + '</b></li>' + document.getElementById('log').innerHTML; }; socket.onerror = function(event) { document.getElementById('log').innerHTML = '<li><b>#disconnected:' + event.message + '</b></li>' + document.getElementById('log').innerHTML; document.getElementById('status').innerHTML = 'Socket Error'; document.getElementById('status').className = 'error'; }; } function ExecStringCommand(strCommand) { strLastResult = ''; nCommandIndex++; if (socket.readyState == WebSocket.OPEN) { socket.send(strCommand+','+nCommandIndex); } else { document.getElementById('log').innerHTML = '<li><b>#send failed. websocket not open. please check.</b></li>' + document.getElementById('log').innerHTML; } } functionGetSocketStatus() { if(null == socket) return "socket is null"; switch (socket.readyState) { case socket.CONNECTING: return "connecting"; break; case socket.OPEN: return "open"; break; case socket.CLOSING: return "closing"; break; case socket.CLOSED: return "closed"; break; default: return "undefined"; break } }; </script> <style> body { font-family:Verdana,Arial,"Times New Roman"; } #status { padding: 5px; color: #fff; background: #ccc; } #status.error { background: #c00; font-weight: bold; } #status.offline { background: #c00; font-weight: bold; } #status.online { background: #0c0; font-weight: bold; } </style> </head> <body> <h1>LotusCard WEB Socket 演示页面</h1> <table width="100%"> <tr style="width:100px; height:40px;"> <td> 读卡器IP: </td> <td> <input type="text" value="192.168.1.252" id="strLotusCardDeviceIp" style="width:150px; height:30px;" /> </td> </tr> <tr style="width:100px; height:40px;"> <td> 读卡器PORT: </td> <td> <input type="text" value="31213" id="strLotusCardDevicePort" style="width:150px; height:30px;" /> </td> </tr> <tr style="width:100px; height:40px;"> <td> 状态 </td> <td> <p id="status"></p> </td> </tr> <tr style="width:100px; height:40px;"> <td colspan="2"> <h3>通信函数:1、连接服务器 2、执行字符串函数并解析结果 3、断开连接</h3> </td> </tr> <tr style="width:100px; height:40px;"> <td> 连接服务器: </td> <td> <INPUT id = "ConnectServer"type=button value="ConnectServer" onclick="javascript:ConnectServer();" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 关闭连接: </td> <td> <INPUT id = "CloseConnection"type=button value="CloseConnection" onclick="javascript:socket.close();" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 获取连接状态: </td> <td> <INPUT id = "ConnectionStatus"type=button value="ConnectionStatus" onclick="javascript:document.getElementById('log').innerHTML = '<li><b>#status:' + GetSocketStatus() + '</b></li>' + document.getElementById('log').innerHTML;" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 获取MCU序列号: </td> <td> <INPUT id = "OpenDevice"type=button value="GetMcuSerailNo" onclick="javascript:ExecStringCommand('GetMcuSerailNo')" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 蜂鸣: </td> <td> <INPUT id = "Beep"type=button value="Beep" onclick="javascript:ExecStringCommand('Beep,10');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 获取M1卡号: </td> <td> <INPUT id = "GetCardNo"type=button value="GetCardNo" onclick="javascript:ExecStringCommand('GetCardNo,38');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 装载密码: </td> <td> <INPUT id = "LoadKey"type=button value="LoadKey" onclick="javascript:ExecStringCommand('LoadKey,96,0,FFFFFFFFFFFF');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 验证密码: </td> <td> <INPUT id = "Authentication"type=button value="Authentication" onclick="javascript:ExecStringCommand('Authentication,96,0');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 读数据扇区0块1: </td> <td> <INPUT id = "M1Read"type=button value="M1Read" onclick="javascript:ExecStringCommand('Read,1');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 写数据扇区0块1: </td> <td> <INPUT id = "M1Write"type=button value="M1Write" onclick="javascript:ExecStringCommand('Write,1,0123456789abcdef0123456789abcdef');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 中止M1卡片: </td> <td> <INPUT id = "M1Halt"type=button value="M1Halt" onclick="javascript:ExecStringCommand('Halt');" style="width:150px; height:30px;"/> </td> </tr> <tr style="width:100px; height:40px;"> <td> 清除日志: </td> <td> <INPUT id = "ClearLog"type=button value="ClearLog" onclick="javascript:document.getElementById('log').innerHTML = '';" style="width:150px; height:30px;"/> </td> </tr> <tr> <td colspan="2"> <h3>日志</h3> </td> </tr> <tr> <td colspan="2"> <ul id="log" style="overflow: auto; list-style: none; padding:0; background:#ffffff; font-size:small; border-style:solid; border-color:#c0c0c0"></ul> </td> </tr> </table> </body> </html>