项目需求,最近在玩蓝牙连接打印机,并实现打印功能的Demo,现在Demo已经完成,打印已做好排版,打印的效果还是不错的,就是.....字体有点大
下面就是用蓝牙连接打印接并且实现打印的流程
1.获取BluetoothAdapter
bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
有了这个,我们才可以进行下面的操作。
if(!bluetoothAdapter.isEnabled()){ Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent,REQUEST_ENABLE); } Bt_ReadyForScan(); //判断是否正在搜索 if(bluetoothAdapter.isDiscovering()){ //结束搜索 bluetoothAdapter.cancelDiscovery(); } //开始搜索 bluetoothAdapter.startDiscovery();
首先我们判断蓝牙是否已经打开,没有的打开蓝牙那就要打开蓝牙了
isEnabled() 就是判断是否打开蓝牙的方法
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(intent,REQUEST_ENABLE); 这两步会弹出一个对话框,来提示用户时候打开蓝牙
2.搜索附近的蓝牙设备
isDiscovering() 判断是否在搜索bluetoothAdapter.cancelDiscovery() 结束搜索bluetoothAdapter.startDiscovery(); 开始搜索,这时候没搜索到一个蓝牙设备,系统就会发出一个BluetoothDevice.ACTION_FOUND 广播,所以我们还要注册个自定义的广播来接收并且展示到UI上
BlueBroadcast的代码如下
public void onReceive(Context context, Intent intent) { String action=intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)){//每发现个蓝牙设备就会发送这个广播 BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//获得搜索到的蓝牙设备 String name=device.getName();//设备的名字 蓝牙设备的绑定状态,若已经配对就不要了,bluetoothAdapter有方法获得已经配对的蓝牙设备 if(device!=null&&device.getBondState()!=BluetoothDevice.BOND_BONDED&&name!=null&&name.contains("Jolimark")){ if(reshList==null)return; reshList.refreshList("name:"+device.getName()+"\nMac:"+device.getAddress()); } }else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){//搜索结束后发送的广播 if(reshList==null) return; reshList.searchFinished(); }else if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)){//蓝牙与设备断开连接时发送的广播 BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); Toast.makeText(context,device.getName()+"已断开连接",Toast.LENGTH_SHORT).show(); PrintHelper.getInstance().setConnection(false); PrintHelper.getInstance().close(); }
好了,自定义的广播大概就是监听这几种广播,若有其他需求自己在添加
private void Bt_ReadyForScan(){ //获取已经匹配的蓝牙列表 BlueListAdapter adapter = (BlueListAdapter) device_pair.getAdapter(); adapter.removeAll(); Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices(); if(bondedDevices.size()>0){ for (BluetoothDevice device:bondedDevices) { if(device.getName().contains("Jolimark")){//我这是过滤掉其他的设备,只要Jolimark打印机设备 adapter.add("name:"+device.getName()+"\nMac:"+device.getAddress()); } } } }
3.连接设备
前面做的事都是为了得到设备的Mac地址,得到Mac地址之后我们就可以去连接设备了
remoteDevice=bluetoothAdapter.getRemoteDevice(deviceAddress);//根据Mac地址来得创建个RemoteDeviceUUID是固定的bluetoothSocket = remoteDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid)); bluetoothSocket.connect(); outputStream = bluetoothSocket.getOutputStream(); inputStream = bluetoothSocket.getInputStream();
String uuid="00001101-0000-1000-8000-00805F9B34FB"
是不是很熟悉,蓝牙连接用的也是Socket,blue Socket得到IO流之后,我们就可以来给连接的打印设备去发送打印指令了
4.发送打印指令
这个就得看打印机的文档了,虽然说ESC指令大多数都是通用的,但还是有个是不同的
对于封装指令来格式话打印,例如字体大小啊,粗体 请可参考 http://blog.csdn.net/a214024475/article/details/52996047
还有去看看ESC命令文档,她的打印格式化还是不错的,但是我公司打印的发票在打印多列的情况,最后一列并不是在打印发票的最末尾
我推荐还是使用自定义水平制表,来改变打印的位置
public ThermalPaper setTable(int[] table) { byte[] cmd = new byte[table.length + 3]; cmd[0] = 0x1B; cmd[1] = 0x44; for (int i = 0; i < table.length; i++) { cmd[i + 2] = (byte)(table[i] & 0xFF); } cmd[cmd.length - 1] = 0; datas=twoToOne(datas,cmd); return this; } public ThermalPaper nextTab() { byte[] cmd = {0x09}; datas=twoToOne(datas,cmd); return this; }我的理解就是,int数组里的每个数都代表的是一个水平制表的位置,这个位置是从0开始计算的,int数组的值就代表的多少个字节,我的打印机打印的汉子是1个汉字两个字节
所以一个汉字的宽度就是两个字节,一个字母和数字的宽度就是一个字节。int数组的长度就是水平制表的个数。
注意,int数组中不能出现0,还有后面的数一定不能小于前面的数。
对于定位,打印机是有黑标功能的,打印纸上面的右边侧是有个黑色的标记,都是用来定位,来找到打印开始的位置和打印结束后撕纸的位置
怎么定位?
{(byte)0x1D,(byte) 0x0c}封装好定位黑标的指令用outputStream发送过去就可以定位到黑标了,打印开始的位置和打印结束后撕纸的位置就看自己去调整了,利用走纸和进纸去调就是。
打印开始时我碰到个坑,打印汉字时是乱码 想都不想是编码的问题了,把汉字转化为GB2312格式的编码就行了,这个格式可以看打印机的说明文档,一般是这个格式
text.getBytes("GB2312");
还有就是我把文字转化的字节数组发送过去后打印不出来,打印机没反应,这是因为我没有在文字后面加\r\n来实现换行,或者我们在后面发送个 打印并换行的指令