##蓝牙问题总结
####本文档会随时更新。如有转载还请注意保留原链接。
> 开发公司票务验票APP要求连接蓝牙打印小票。但是HTML5+并没有现成的API只能自己动手了。
本人不是native开发者,所以问题描述和解决方案可能并不是最优或准确的。如果问题描述有误或您有更好的解决方法。欢迎指正,共同学习!由于本人对ios不懂。且ios蓝牙资料缺少。所以APP蓝牙打印仅安卓版本的支持。iOS支持请等待后续更新
联系本人:wzhec@foxmail.com
关于service端的APP设计请参考我的另外一本笔记:[联合票务系统对接文档说明](http://www.kancloud.cn/iwzh/lianhepiaowu/168108)
重点来了,蓝牙问题说明:
涉及到,蓝牙搜索,蓝牙配对,蓝牙自动开启。蓝牙传输打印功能。
github项目地址:[https://github.com/iwzh/lianhepiaowuVerifyCode/blob/master/js/pr.js](https://github.com/iwzh/lianhepiaowuVerifyCode/blob/master/js/pr.js)
代码已基本解决上述问题。
贴代码:(代码可能已更新,但大改动应该没有)
~~~
(function($, BT) {
/**
* 获取应用本地配置
**/
function getSettings() {
var settingsText = localStorage.getItem('$settings') || "{}";
return JSON.parse(settingsText);
}
var device = null,
BluetoothAdapter = null,
BAdapter = null,
UUID = null,
uuid = null,
main = null,
bluetoothSocket = null,
BluetoothDevice = null,
IntentFilter=null;
var agintry=0;
var defaultpage="tab-webview-subpage-bluetooth.html";
//定义 Bluetooth 类
var Bluetooth = $.Bluetooth = $.Class.extend({
/**
* 构造函数
* */
init: function(options) {
var self = this;
options = options || {};
self.options = options;
self.device = self.options.device || device;
if(self.device==null){
main = self.options.main = self.options.main || plus.android.runtimeMainActivity();
BluetoothAdapter = self.options.BluetoothAdapter = self.options.BluetoothAdapter || BluetoothAdapter || plus.android.importClass("android.bluetooth.BluetoothAdapter");
BAdapter=self.options.BAdapter = self.options.BAdapter || BAdapter || BluetoothAdapter.getDefaultAdapter();
//self.device = self.options.device || device || self.BAdapter.getRemoteDevice(self.mac_address);
//plus.android.importClass(self.device);
}
if(self.openBluetooth(self.BAdapter)){
/* //搜索蓝牙时候用到
if(self.IntentFilter==null){
self.IntentFilter = self.options.BluetoothAdapter || plus.android.importClass('android.content.IntentFilter') || self.IntentFilter;
}*/
}else{
$.toast('开启蓝牙失败,无法使用蓝牙打印机;请手动设置权限后,重新打开');
}
},
/**
* 获取本地存储的蓝牙列表
**/
getBlueList : function() {
var stateText = localStorage.getItem('$bluetoothlist') || "{}";
return JSON.parse(stateText);
},
/**
* 设置本地存储的蓝牙列表
**/
setBlueList:function(state) {
state = state || {};
localStorage.setItem('$bluetoothlist', JSON.stringify(state));
},
/*
* 清除本地存储的蓝牙列表
*/
clearBlueList:function(){
this.setBlueList({});
},
/**
* 获取本地存储的搜索蓝牙列表
**/
setBTSearchList:function(state) {
var stateText = localStorage.getItem('$btseachlist') || '{"on":"[]","un":"[]"}';
return JSON.parse(stateText);
},
/**
* 设置本地存储的搜索蓝牙列表
**/
setBTSearchList:function(state) {
state = state || '{"on":"[]","un":"[]"}';
localStorage.setItem('$btseachlist', JSON.stringify(state));
},
/*
* 获取保存的蓝牙连接地址
*/
getMacAddress:function(){
var settings=getSettings();
settings.bluestate=1;
if(settings.bluestate){
var address = localStorage.getItem('$bluetoothMacAddress') || "";
return address;
}else{
console.log('未开启蓝牙打印设置');
return false;
}
},
/*
* 设置保存蓝牙连接的地址
*/
setMacAddress:function(address){
address=address||'';
localStorage.setItem('$bluetoothMacAddress', address);
},
/*
* 测试打印
*/
testprint:function(mac_address,teststr,device,bluetoothSocket){
teststr=teststr||"这是测试打印的。内容可以忽略 ";
this.print(mac_address,teststr,device,bluetoothSocket);
},
/**
* 打印
*/
print: function(mac_address, printstring, device, bluetoothSocket) {
var self = this;
if(!mac_address) {
var mac_address=self.getMacAddress();
if(!mac_address){
$.toast('请选择蓝牙打印机');
return;
}
}
self.initParam({"mac_address":mac_address},1);
bluetoothSocket=self.options.bluetoothSocket;
self.connectedBT(bluetoothSocket,mac_address);//检测蓝牙是否连接;
if(bluetoothSocket.isConnected()) {
var outputStream = bluetoothSocket.getOutputStream();
plus.android.importClass(outputStream);
var bytes = plus.android.invoke(printstring, 'getBytes', 'gbk');
var clearFormat = [0x1b, 0x40]; //复位打印机
outputStream.write(clearFormat);
/*start *** 文字加粗*/
/*
outputStream.write([0x1b,0x45,1]);
var title=plus.android.invoke("【联合票务】", 'getBytes', 'gbk');
outputStream.write(title);
outputStream.write([0x1b,0x45,0]);
*/
/*end *** 文字加粗*/
outputStream.write(bytes);
outputStream.write([0x1b,0x64,4]);//多走纸n行
/*outputStream.write([0x1b,0x2a,1,6,0,10,0,122,222,22,54]);//位图模式*/
outputStream.flush();
/*//device = null //清空连接设备 如果持续验票的情况下,不能每次都初始化设备。只需要关闭蓝牙与手机APP的socket即可。无需情况设备*/
/*bluetoothSocket.close(); //必须关闭蓝牙连接否则意外断开的话打印错误*/
}else{
$.toast("蓝牙未连接,无法打印");
}
},
/*
* 成功的提示
*/
confirm:function(mac_address){
var self=this;
var confirm_title='测试打印';
var confirm_tips='蓝牙已连接成功,是否测试打印?';
if($.os.plus) {
mac_address=mac_address||self.options.mac_address||self.getMacAddress();
var btnArray = ['是', '否'];
$.confirm(confirm_tips, confirm_title, btnArray, function(e) {
if(e.index == 0) {
self.print(mac_address)
}else{
console.log('取消');
}
});
} else {
alert("成功");
}
},
/*
* 开启蓝牙
*/
openBluetooth:function(BAdapter){
var self=this;
BAdapter=self.options.BAdapter || BAdapter;
if(!BAdapter.isEnabled()) {
console.log('检测到未打开蓝牙,尝试打开中....');
$.toast('检测到未打开蓝牙,尝试打开中....');
var status = BAdapter.enable();
if(status){
console.log('已为您开启蓝牙...');
$.toast('已成功为您开启蓝牙');
}else{
console.log('开启蓝牙失败,请手动开启蓝牙');
$.toast('开启蓝牙失败,请手动开启蓝牙');
return false;
}
}
return true;
},
initParam:function(options,checkSocket,checkDevice){
var self = this;
checkSocket=checkSocket||0;
checkDevice=checkDevice||0;
device = self.options.device = options.device||self.options.device ||device ;
if(self.device==null){
main = self.options.main = options.main||self.options.main||main||plus.android.runtimeMainActivity();
BluetoothAdapter =self.options.BluetoothAdapter =options.BluetoothAdapter||self.options.BluetoothAdapter ||BluetoothAdapter||plus.android.importClass("android.bluetooth.BluetoothAdapter");
BAdapter=self.options.BAdapter=options.BAdapter||self.options.BAdapter || BAdapter || BluetoothAdapter.getDefaultAdapter();
}
if(options.mac_address){
device =self.options.device= BAdapter.getRemoteDevice(options.mac_address);
plus.android.importClass(device);
}
if(checkDevice){
//蓝牙信息
BluetoothDevice=self.options.BluetoothDevice =options.BluetoothDevice||self.options.BluetoothDevice||plus.android.importClass("android.bluetooth.BluetoothDevice");
}
//蓝牙连接或者uuid为空时,需要重新导入蓝牙socket
if(checkSocket){
/*检查Socket时,要么导入Socket要么给Socket初始值*/
UUID=self.options.UUID =options.UUID||self.options.UUID||plus.android.importClass("java.util.UUID");
uuid=self.options.uuid =options.uuid||self.options.uuid||UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
bluetoothSocket=self.options.bluetoothSocket = options.bluetoothSocket||device.createInsecureRfcommSocketToServiceRecord(uuid);
plus.android.importClass(bluetoothSocket);
}
return self;
},
/*
* 连接蓝牙
*/
connectedBT: function(bluetoothSocket,mac_address) {
var self = this;
if(!bluetoothSocket.isConnected()) {
if(agintry>1){
console.log('重试两次了,不再尝试');
bluetoothSocket=self.options.bluetoothSocket=null;
UUID=self.options.UUID=null;
uuid=self.options.uuid=null;
return false;
}
try {
bluetoothSocket.connect();
} catch(e) {
console.log('Bluetooth Connect Error!'+e);
bluetoothSocket.close();
self.initParam({"mac_address":mac_address},1,1);
bluetoothSocket =self.options.bluetoothSocket;
console.log('设备连接出错了,重新连接');
agintry++;
bluetoothSocket.connect();
}
if(!bluetoothSocket.isConnected()) {
$.toast('设备未连接,重新连接失败,请确保设备开启。');
return false;
} else {
console.log('设备已连接。');
}
console.log('设备已连接 bluetoothSocket.isConnected()=' + bluetoothSocket.isConnected());
}
agintry=0;
return true;
},
contactBT:function(mac_address){
var self=this;
self.initParam({"mac_address":mac_address},1,1);
var bdevice = new BluetoothDevice();
if(device.getBondState()==bdevice.BOND_NONE){
//地址一样,执行配对
if(mac_address == device.getAddress()){
console.log('正在执行配对');
if(device.createBond()) {
console.log("配对成功");
//第一次配对成功将配对成功的数据放入已配对蓝牙列表
var _bluelist=self.getBlueList();
var item={"id":d.getAddress(),"name":d.getName()};
_bluelist.push(item);
self.setBlueList(_bluelist);
}
}
}
self.connectedBT(self.options.bluetoothSocket,mac_address);
},
/**
* 扫描已配对蓝牙
*/
scan: function() {
var self = this;
BAdapter=self.options.BAdapter || self.BAdapter || BAdapter;
var lists = BAdapter.getBondedDevices(); //获取配对的设备列表
plus.android.importClass(lists);
var iterator = lists.iterator();
plus.android.importClass(iterator);
var bluetoothList=new Array();
while(iterator.hasNext()) {
var d = iterator.next();
plus.android.importClass(d);
var item={"id":d.getAddress(),"name":d.getName()};
bluetoothList.push(item);
}
self.setBlueList(bluetoothList);
return bluetoothList;
},
/*
* 取消蓝牙配对
*/
removeBlueDevices:function(mac_address,mac_name){
var self=this;
if(!mac_address) {
$.toast('请选择成功配对的蓝牙设备');
return;
}
self.initParam({"mac_address":mac_address},1,1);
device=self.options.device;
BluetoothDevice=self.options.BluetoothDevice;
var bdevice = new BluetoothDevice();
if(device.getBondState()==bdevice.BOND_BONDED){
//地址一样,执行删除配对
if(mac_address == device.getAddress()){
var btnArray = ['是', '否'];
$.confirm('是否删除已配对的设备:' + mac_name + '?', '删除设备', btnArray, function(e) {
if(e.index == 0) {
if(device.removeBond()) {
var _bluelist=self.getBlueList();
var item={"id":mac_address,"name":mac_name};
var rebluelist=_bluelist.map(function(listiteam){
if(JSON.stringify(item)!=JSON.stringify(listiteam)){
return listiteam;
}
});
self.setBlueList(rebluelist);
console.log("删除配对蓝牙设备:\n" + mac_name + " 成功");
return true;
}
} else {
console.log('取消删除设备操作');
return false;
}
});
}
}else{
console.log("未配对设备,不能删除");
return false;
}
},
/*
* 搜索蓝牙设备,并创建处理HTML蓝牙列表
*/
seachBT:function(address){
var self=this;
if(address){
self.initParam({"mac_address":address},0,1);
}else{
self.initParam({},0,1);
}
//检查蓝牙是否开启
self.openBluetooth(BAdapter);
IntentFilter=self.options.IntentFilter=self.options.IntentFilter||IntentFilter || plus.android.importClass('android.content.IntentFilter');
BluetoothDevice=self.options.BluetoothDevice=self.options.BluetoothDevice||BluetoothDevice || plus.android.importClass("android.bluetooth.BluetoothDevice");
var filter = new IntentFilter();
var bdevice = new BluetoothDevice();
var on = new Array(),un = new Array(),onstr=null,unstr=null;
var BTSeatchList=new Object();
BAdapter.startDiscovery(); //开启搜索
var receiver;
receiver = plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {
onReceive: function(context, intent) {
//实现onReceiver回调函数
plus.android.importClass(intent);
//通过intent实例引入intent类,方便以后的‘.’操作
//获取action
console.log(intent.getAction());
if(intent.getAction() == "android.bluetooth.adapter.action.DISCOVERY_FINISHED") {
console.log("搜索结束,本地保存未配对设备和已配对设备");
BTSeatchList.on=on;
BTSeatchList.un=un;
main.unregisterReceiver(receiver); //取消监听
//事件数据
var eventData = {
sender: self,
btsearchlist: BTSeatchList
};
//触发声明的DOM的自定义事件(暂定 done 为事件名,可以考虑更有针对的事件名 )
var firepage = plus.webview.getWebviewById(defaultpage);
$.fire(firepage,'done', eventData);
} else {
BleDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//判断是否配对
if(BleDevice.getBondState() == bdevice.BOND_NONE) {
//判断防止重复添加
if(BleDevice.getName()!=unstr){
unstr=BleDevice.getName();
console.log("未配对蓝牙设备:" + unstr + ' ' + BleDevice.getAddress());
var unitem={"id":BleDevice.getAddress(),"name":unstr};
un.push(unitem);
}
} else {
//判断防止重复添加
if(onstr!=BleDevice.getName()){
onstr=BleDevice.getName();
console.log("已配对蓝牙设备:" + onstr + ' ' + BleDevice.getAddress());
var onitem={"id":BleDevice.getAddress(),"name":onstr};
on.push(onitem);
}
}
}
}
});
filter.addAction(bdevice.ACTION_FOUND);//搜索设备
filter.addAction(BAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BAdapter.ACTION_STATE_CHANGED);
filter.addAction(BAdapter.ACTION_STATE_CHANGED); //监听蓝牙开关
main.registerReceiver(receiver, filter); //注册监听
},
/*
* 数组去重
*/
arrayUnique:function(a) {
var seen = {};
return a.filter(function(item) {
item=JSON.stringify(item);
return seen.hasOwnProperty(item) ? false : (seen[item] = true);
});
}
});
//添加 Bluetooth 插件
$.fn.bluetooth = function(options) {
var self = this[0];
var bluetooth = null;
bluetooth = new Bluetooth(options);
return bluetooth;
}
})(mui, window);
~~~
- 说明
- PHP
- 数组操作
- file操作的常用方法
- PHP字符串输出之Heredoc说明
- require(_once)和include(_once)的理解
- file_get_contents和curl
- PHP的json问题
- PHP提高效率的几点
- PHP/异步任务队列处理
- HTTP_AUTHORIZATION
- php中 intval和string的一些转换问题
- 变量在 PHP7 内部的实现
- 关于exit和die
- php获取微秒
- php高性能日志扩展seaslog的使用
- Curl使用说明
- echo的数据自动增加换行或其他
- php-memcache
- 根据18位数校验前17位身份证号是否正确
- 将一个老项目升级到php7
- ord获取ASCII码
- 框架
- thinkphp5
- THINKPHP5常见问题
- Laravel5学习笔记
- homestead总结
- easywechat学习笔记
- wechat公众号
- 获取用户信息的实现方式
- 前端
- HTML
- CSS
- 伪类和伪元素的区别
- Bootstrap使用
- Javascript
- Javascript梳理总结
- 巧用history.pushState无刷新改变页面url
- jquery日期时间选择器组件datepicker的使用说明
- 基本操作
- 比较
- 后端/Nodejs
- 多nodejs版本管理
- 小功能
- URLAPI
- 二维码转换
- 地图URL直接实现导航
- 字体生成
- 网址长短互转
- 百度短网址
- Fiddle模拟测试百度短网址api
- Composer备忘录
- composer安装配置
- Composer 错误集锦
- Composer使用自己的库
- GIT简单操作命令
- Git记住密码
- git 显示错误详情和请求信息
- 工具软件
- PHPStorm
- VI简单操作命令
- ATOM
- browser提示shockwave false加载失败
- Cmder使用说明
- Windows软件总结
- 浏览器插件
- 支付
- 微信支付
- 支付宝
- 银联支付
- Ping++
- Beecloud支付
- Map
- 百度地图BaiduMap
- RESTfulAPI设计实践
- HTTP
- GET/POST 的请求大小
- 常见状态码说明
- Ubuntu
- 命令行中的>>和>的区别
- 笔记
- 正则
- Hybrid的使用记录
- H5+和mui
- HTML5+和mui使用
- APP开发过程中蓝牙问题总结
- Cordova的使用
- 服务器
- URL重写
- 目录限制访问
- 软链接和硬链接
- 票务系统对接资料和总结
- qunar去哪儿门票对接
- qunar对接case介绍及错误代码
- tuniu门票对接总结
- 途牛小结
- 联合票务对接途牛文档说明
- 途牛签名流程
- meituan美团
- 大众点评
- 联合票务
- 安卓使用技巧
- 安卓清理电池信息
- 安卓6.0使用时发现的问题
- 数据库
- 数据库mysql
- 分页数据优化
- 手机号用不到索引的问题分析
- mysql配置的localhost和127.0.0.1的区别
- mysql5.5升级mysql5.7
- 数据库MongoDB
- Redis使用说明
- phpredis使用说明
- 环境变量
- Twig使用
- 经典的文章
- 用超人的故事讲解 IoC(控制反转) 和 DI(依赖注入)