关闭

MUI蓝牙打印(Android)

标签: 5+H5+MUIJSNativeJS
1914人阅读 评论(3) 收藏 举报
分类:

MUI蓝牙打印(Android)


使用MUI开发手机APP时使用蓝牙打印功能可能较少使用,MUI官方并为集成蓝牙打印功能,而且似乎对iPhone蓝牙打印的类库支持也不够完善。忙完一阶段后回顾下之前的工作,想想蓝牙打印功能折腾了够长时间了,写这篇文章既是自己做个总结,也希望能给遇到同样为蓝牙打印功能挣扎的人带来一点帮助。

感谢以下几篇文章给予的帮助。


页面HTML

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">

        <!--标准mui.css-->
        <link rel="stylesheet" href="../../css/mui.min.css">
        <link rel="stylesheet" href="../../css/wg-common.css">
        <link rel="stylesheet" href="../../css/iconfont.css">
        <!--App自定义的css-->
        <link rel="stylesheet" type="text/css" href="../../css/app.css" />
        <title></title>
    </head>
    <style>
        .wg-info-title {
            background-color: white;
            color: #007AFF;
        }

        .mui-btn {
            font-size: 16px;
            padding: 8px;
            margin: 3px;
        }
    </style>

    <body>
        <header class="mui-bar mui-bar-nav" style="padding-top: 2px;">
            <div style="float: left;padding-right: 8px;">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
            </div>
            <h1 id="title" class="mui-title">打印</h1>
            <div style="float: right;padding-right: 8px;">
                <a class="mui-icon mui-icon-refreshempty" id="btnRefresh"></a>
            </div>
        </header>
        <div class="mui-content mui-content-padded">
            <h5 class="mui-content-padded">点击设备开始连接</h5>
            <ul id="list1" class="mui-table-view mui-table-view-chevron">
            </ul>
            <br />
            <h5 class="mui-content-padded">点击设备开始打印</h5>
            <ul id="list2" class="mui-table-view mui-table-view-chevron">
            </ul>
        </div>
    </body>
</html>

页面JS代码

// 导入的java包
        var Context, BluetoothAdapter, BluetoothDevice;
        // 蓝牙服务与适配
        var BManager, BAdapter, BluetoothSocket, mDevice, receiver;
        var mMain, mUUID;

        var vlist1 = document.getElementById('list1'); //注册容器用来显示未配对设备
        var vlist2 = document.getElementById('list2'); //注册容器用来显示未配对设备
        var buttonRefresh = document.getElementById('btnRefresh');

        document.addEventListener('plusready', function(event) {
            var self = plus.webview.currentWebview();
            // 打开蓝牙设备并扫描
            if (mui.os.android) {
                // 打开蓝牙
                openAndroidBluetooth();

                // 设置延时,防止蓝牙未完全开启时调用
                CommonUtil.WaitFor(
                    function() {
                        return BAdapter.isEnabled();
                    },
                    function() {
                        // 获取已连接设备列表
                        getConnectedDevices();
                    },
                    3000);
            }
        });
        // 刷新(重新扫描)
        buttonRefresh.addEventListener('tap', function(event) {
            buttonRefresh.disabled = true;
            if (mui.os.android) {
                // 扫描
                searchDevices();
            }
            buttonRefresh.disabled = false;
        });
        // list1/list2的监听事件只能用on绑定,如果使用
        //              li2.addEventListener('tap', function(event) {
        //                  print(li2.getAttribute('id'));
        //              });
        // 会导致打印时socket超时,具体原因不明
        mui('#list1').on('tap', 'li', function() {
            connect(this.id);
        })
        mui('#list2').on('tap', 'li', function() {
            print(this.id);
        })

        /**
         *打开蓝牙(Android) 
         */
        function openAndroidBluetooth() {
            mMain = plus.android.runtimeMainActivity();
            Context = plus.android.importClass("android.content.Context");
            BManager = mMain.getSystemService(Context.BLUETOOTH_SERVICE);
            plus.android.importClass(BManager); //引入相关的method函数
            BAdapter = BManager.getAdapter();
            plus.android.importClass(BAdapter); //引入相关的method函数,这样之后才会有isEnabled函数支持
            if (!BAdapter.isEnabled()) {
                BAdapter.enable();
            }
        }

        /**
         * 获取已配对的蓝牙设备列表
         */
        function getConnectedDevices() {
            //          var main = plus.android.runtimeMainActivity();
            //          var BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
            //          var BAdapter = BluetoothAdapter.getDefaultAdapter(); //获得本机蓝牙适配器
            if (!BAdapter.isEnabled()) {
                plus.nativeUI.toast('请先打开蓝牙');
                return;
            }
            var lists = BAdapter.getBondedDevices(); //获取配对的设备列表
            plus.android.importClass(lists);
            var iterator = lists.iterator();
            plus.android.importClass(iterator);
            var vlist2 = document.getElementById('list2'); //注册容器用来显示未配对设备
            while (iterator.hasNext()) {
                var d = iterator.next();
                plus.android.importClass(d);
                var li2 = genLi(d);
                vlist2.appendChild(li2);
            }
        }

        /**
         *扫描蓝牙设备 
         */
        function searchDevices() {
            //console.log("开始搜索设备");

            if (!BAdapter.isEnabled()) {
                plus.nativeUI.toast('请先打开蓝牙');
                return;
            }

            plus.nativeUI.showWaiting('正在搜索设备,请稍后...', {
                back: 'none' // 可取值"none"表示截获处理返回键,但不做任何响应;"close"表示截获处理返回键并关闭等待框;"transmit"表示不截获返回键,向后传递给Webview窗口继续处理(与未显示等待框的情况一致)。 
            });
            vlist1.innerHTML = ''; //清空容器
            vlist2.innerHTML = ''; //清空容器
            // 初始化蓝牙广播接收器 
            initReceiver();
            // 开启搜索
            BAdapter.startDiscovery();
            // 初始化广播信息过滤
            initIntentFilter();
        }

        function initReceiver() {
            BluetoothDevice = plus.android.importClass("android.bluetooth.BluetoothDevice");
            var bdevice = new BluetoothDevice();
            receiver = plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {
                onReceive: function(context, intent) { //实现onReceiver回调函数
                    plus.android.importClass(intent); //通过intent实例引入intent类,方便以后的‘.’操作
                    //console.log(intent.getAction()); //获取action

                    if (intent.getAction() == "android.bluetooth.adapter.action.DISCOVERY_FINISHED") {
                        mMain.unregisterReceiver(receiver); //取消监听
                        //console.log("搜索结束")
                        plus.nativeUI.closeWaiting();
                    } else {
                        BleDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                        //                      console.log(JSON.stringify(BluetoothDevice));
                        //                      console.log(JSON.stringify(BleDevice));
                        //判断是否配对
                        if (BleDevice.getBondState() == bdevice.BOND_NONE) {
                            //console.log("未配对蓝牙设备:" + BleDevice.getName() + '    ' + BleDevice.getAddress());
                            if (!document.getElementById(BleDevice.getAddress())) { //判断防止重复添加
                                var li1 = genLi(BleDevice);
                                vlist1.appendChild(li1);
                            }
                        } else {
                            if (!document.getElementById(BleDevice.getAddress())) { //判断防止重复添加
                                //console.log("已配对蓝牙设备:" + BleDevice.getName() + '    ' + BleDevice.getAddress());
                                var li2 = genLi(BleDevice);
                                vlist2.appendChild(li2);
                            }
                        }
                    }
                }
            });
        }

        function initIntentFilter() {
            // 设置广播信息过滤  
            var IntentFilter = plus.android.importClass('android.content.IntentFilter');
            var filter = new IntentFilter();
            filter.addAction(BluetoothDevice.ACTION_FOUND);
            filter.addAction(BAdapter.ACTION_DISCOVERY_STARTED);
            filter.addAction(BAdapter.ACTION_DISCOVERY_FINISHED);
            filter.addAction(BAdapter.ACTION_STATE_CHANGED);
            // 注册广播接收器,接收并处理搜索结果  
            mMain.registerReceiver(receiver, filter);
        }

        function connect(mac_address) {
            // 查找蓝牙设备
            var unConnected = BAdapter.getRemoteDevice(mac_address);
            if (unConnected) {
                try {
                    if (BleDevice.createBond()) { //配对命令.createBond()
                        //console.log("配对成功");
                    }
                } catch (e) {
                    //TODO handle the exception
                    mui.alert('连接到设备失败');
                }
            }
        }

        //mac_address:打印机的mac地址
        function print(mac_address, str) {
            if (!mac_address) {
                mui.toast('请选择蓝牙打印机');
                return;
            }
            if (mDevice == null) {
                //              mMain = plus.android.runtimeMainActivity();
                //              BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
                //              BAdapter = BluetoothAdapter.getDefaultAdapter();
                UUID = plus.android.importClass("java.util.UUID");
                mUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
                mDevice = BAdapter.getRemoteDevice(mac_address);
                plus.android.importClass(mDevice);
                BluetoothSocket = mDevice.createInsecureRfcommSocketToServiceRecord(mUUID);
            }
            plus.android.importClass(BluetoothSocket);
            if (!BluetoothSocket.isConnected()) {
                //console.log('检测到设备未连接,尝试连接....');
                try {
                    BluetoothSocket.connect();
                } catch (e) {
                    //TODO handle the exception
                    mui.alert('连接超时');
                    return;
                }
            }

            // 防止蓝牙未完成连接时调用打印
            CommonUtil.WaitFor(
                function() { // 等待条件
                    return BluetoothSocket.isConnected();
                },
                function() { // 回调方法
                    if (!BluetoothSocket.isConnected()) {
                        plus.nativeUI.toast('请连接打印机');
                        return;
                    }
                    printTest();
                    //printPictureTest();
                }, 3000);
        }

        function printTest() {
            // 初始化PintUtil
            PrintUtil.init(BluetoothSocket);
            // 以下测试打印
            var printStr = '测试打印\r\n';
            // 设置字体大小
            PrintUtil.SetFontSize(30);
            // 打印字符串
            PrintUtil.PrintString(printStr);
            // 设置字体大小
            PrintUtil.SetFontSize(20);
            // 打印字符串
            PrintUtil.PrintString(printStr);
            // 重置打印机
            PrintUtil.Reset();
            // 打印字符串
            PrintUtil.PrintString(printStr);
            // 切纸
            PrintUtil.CutPage();
            // 结束打印
            PrintUtil.End();
        }

        function genLi(bleDevice) {
            var li = document.createElement('li');
            li.setAttribute('id', bleDevice.getAddress());
            li.className = 'mui-table-view-cell';
            var a = document.createElement('a');
            a.setAttribute('class', 'mui-navigate-right')
            a.innerText = bleDevice.getName();
            li.appendChild(a);

            return li;
        }

辅助方法

页面上用到的几个方法也贴出来吧。

    CommonUtil.WaitFor = function(condition, callback, timeout, unitTime) {
        // 设置默认等待时间(循环间隔)
        if(!unitTime || isNaN(unitTime)) {
            unitTime = 100;
        }
        // 设置超时(到达超时则返回)
        if(!timeout || isNaN(timeout)) {
            timeout = 100;
        }
        if(condition && condition()) { // 等待条件成立,则执行回调
            callback();
        } else if(timeout - unitTime <= 0) { // 等待超时,则执行回调
            callback();
        } else { // 设置延时等待操作
            setTimeout(function() {
                owner.WaitFor(condition, callback, timeout - unitTime, unitTime);
            }, unitTime);
        }
    };

PrintUtil打印公共方法

这里使用了一些打印机指令,具体的指令可以自己根据使用的打印机去找。

(function($, owner) {
    owner.OutputStream = null;

    owner.init = function(BluetoothSocket) {
        owner.OutputStream = BluetoothSocket.getOutputStream();
        plus.android.importClass(owner.OutputStream);
    }

    // 设置字体大小
    owner.SetFontSize = function(n) {
        var font = [0x1D, 0X21, n]
        owner.OutputStream.write(font);
    };

    // 打印字符串
    owner.PrintString = function(string) {
        var bytes = plus.android.invoke(string, 'getBytes', 'gbk');
        owner.OutputStream.write(bytes);
    };

    // 重置打印机
    owner.Reset = function() {
        var reset = [0x1B, 0X40];
        owner.OutputStream.write(reset);
    };

    // 打印下划线
    owner.Underline = function() {
        // 下划线指令
        var underline = [0x1b, 0x2d, 0x01];
        owner.OutputStream.write(underline);
    };

    // 结束打印
    owner.End = function() {
        owner.OutputStream.flush();
        var end = [0x1d, 0x4c, 0x1f, 0x00];
        owner.OutputStream.write(end);
    };

    // 打印图片(暂不可用)
    owner.Picture = function() {
        var picture = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x40, 0x1B, 0x33, 0x00];
        // var picture = [0x1B, 0x2A];
        owner.OutputStream.write(picture);
    };

    // 切纸(暂不可用)
    owner.CutPage = function() {
        // 发送切纸指令  
        var end = [0x1B, 0x69];
        owner.OutputStream.write(end);
    };

    // 条形码打印(暂不可用)
    owner.PrintBarcode = function(n) {
        var barcode = [0x1D, 0x6B, 65, 5, 11, 12, 3, 6, 23];
        owner.OutputStream.write(barcode);
    };
}(mui, window.PrintUtil = {}))

    好了,基本上代码都贴出来了,作为一个代码狗,很多时候我都相信:Talk is cheap, show me the code。
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:28336次
    • 积分:471
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:6篇
    • 译文:0篇
    • 评论:6条
    文章分类
    最新评论