欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android手机通过蓝牙连接佳博打印机的实例代码

程序员文章站 2024-03-01 20:17:10
所使用的打印机为佳博打印机,支持蓝牙、wifi、usb我所使用的是通过蓝牙来连接。 在网上找到一个佳博官方针对安卓开发的app源码,但是各种的跳转,没有看太懂,所以又...

所使用的打印机为佳博打印机,支持蓝牙、wifi、usb我所使用的是通过蓝牙来连接。

在网上找到一个佳博官方针对安卓开发的app源码,但是各种的跳转,没有看太懂,所以又去问度娘,找到了一个不错的文章

android对于蓝牙开发从2.0版本的sdk才开始支持,而且模拟器不支持,测试至少需要两部手机,所以制约了很多技术人员的开发。

1. 首先,要操作蓝牙,先要在androidmanifest.xml里加入权限

// 管理蓝牙设备的权限 
<uses-permissionandroid:name="android.permission.bluetooth_admin" />
// 使用蓝牙设备的权限 
<uses-permissionandroid:name="android.permission.bluetooth" />

2.打开蓝牙

获得蓝牙适配器(android.bluetooth.bluetoothadapter),检查该设备是否支持蓝牙,如果支持,就打开蓝牙。

// 检查设备是否支持蓝牙 
adapter = bluetoothadapter.getdefaultadapter(); 
if (adapter == null) 
{ 
// 设备不支持蓝牙 
} 
// 打开蓝牙 
if (!adapter.isenabled()) 
{ 
intent intent = new intent(bluetoothadapter.action_request_enable); 
// 设置蓝牙可见性,最多300秒 
intent.putextra(bluetoothadapter.extra_discoverable_duration,300);
context.startactivity(intent); 
}

3.获取已配对的蓝牙设备(android.bluetooth.bluetoothdevice)

首次连接某蓝牙设备需要先配对,一旦配对成功,该设备的信息会被保存,以后连接时无需再配对,所以已配对的设备不一定是能连接的。

bluetoothadapter adapter = bluetoothadapter.getdefaultadapter(); 
set<bluetoothdevice> devices = adapter.getbondeddevices(); 
for(int i=0; i<devices.size(); i++) 
{ 
bluetoothdevice device =
bluetoothdevice)devices.iterator().next(); 
system.out.println(device.getname()); 
} 

4.搜索周围的蓝牙设备

适配器搜索蓝牙设备后将结果以广播形式传出去,所以需要自定义一个继承广播的类,在onreceive方法中获得并处理蓝牙设备的搜索结果。

// 设置广播信息过滤 
intentfilter intentfilter = new intentfilter(); 
intentfilter.addaction(bluetoothdevice.action_found); 
intentfilter.addaction(bluetoothdevice.action_bond_state_changed); 
intentfilter.addaction(bluetoothadapter.action_scan_mode_changed); 
intentfilter.addaction(bluetoothadapter.action_state_changed); 
// 注册广播接收器,接收并处理搜索结果 
context.registerreceiver(receiver, intentfilter); 
// 寻找蓝牙设备,android会将查找到的设备以广播形式发出去 
adapter.startdiscovery(); 
自定义广播类
private broadcastreceiver receiver = new broadcastreceiver() { 
@override 
public void onreceive(context context, intent intent) { 
string action = intent.getaction(); 
if (bluetoothdevice.action_found.equals(action)) { 
bluetoothdevice device = intent.getparcelableextra(bluetoothdevice.extra_device); 
system.out.println(device.getname()); 
} 
} 
}

5.蓝牙设备的配对和状态监视

private broadcastreceiver receiver = new broadcastreceiver() { 
@override 
public void onreceive(context context, intent intent) { 
string action = intent.getaction(); 
if (bluetoothdevice.action_found.equals(action)) { 
// 获取查找到的蓝牙设备 
bluetoothdevice device = intent.getparcelableextra(bluetoothdevice.extra_device); 
system.out.println(device.getname()); 
// 如果查找到的设备符合要连接的设备,处理 
if (device.getname().equalsignorecase(name)) { 
// 搜索蓝牙设备的过程占用资源比较多,一旦找到需要连接的设备后需要及时关闭搜索 
adapter.canceldiscovery(); 
// 获取蓝牙设备的连接状态 
connectstate = device.getbondstate(); 
switch (connectstate) { 
// 未配对 
case bluetoothdevice.bond_none: 
// 配对 
try { 
method createbondmethod = bluetoothdevice.class.getmethod("createbond"); 
createbondmethod.invoke(device); 
} catch (exception e) { 
e.printstacktrace(); 
} 
break; 
// 已配对 
case bluetoothdevice.bond_bonded: 
try { 
// 连接 
connect(device); 
} catch (ioexception e) { 
e.printstacktrace(); 
} 
break; 
} 
} 
} else if(bluetoothdevice.action_bond_state_changed.equals(action)) { 
// 状态改变的广播 
bluetoothdevice device = intent.getparcelableextra(bluetoothdevice.extra_device); 
if (device.getname().equalsignorecase(name)) { 
connectstate = device.getbondstate(); 
switch (connectstate) { 
case bluetoothdevice.bond_none: 
break; 
case bluetoothdevice.bond_bonding: 
break; 
case bluetoothdevice.bond_bonded: 
try { 
// 连接 
connect(device); 
} catch (ioexception e) { 
e.printstacktrace(); 
} 
break; 
} 
} 
} 
} 
}

6.蓝牙设备的连接

private void connect(bluetoothdevice device) throws ioexception { 
// 固定的uuid 
final string spp_uuid = "00001101-0000-1000-8000-00805f9b34fb"; 
uuid uuid = uuid.fromstring(spp_uuid); 
bluetoothsocket socket = device.createrfcommsockettoservicerecord(uuid); 
socket.connect(); 
} 
private void connect(bluetoothdevice device) throws ioexception { 
// 固定的uuid 
final string spp_uuid = "00001101-0000-1000-8000-00805f9b34fb"; 
uuid uuid = uuid.fromstring(spp_uuid); 
bluetoothsocket socket = device.createrfcommsockettoservicerecord(uuid); 
socket.connect(); 
}

1.bluetoothadapter 顾名思义,蓝牙适配器,直到我们建立bluetoothsocket连接之前,都要不断操作它

bluetoothadapter里的方法很多,常用的有以下几个:

canceldiscovery() 根据字面意思,是取消发现,也就是说当我们正在搜索设备的时候调用这个方法将不再继续搜索

disable()关闭蓝牙

enable()打开蓝牙,这个方法打开蓝牙不会弹出提示,更多的时候我们需要问下用户是否打开,一下这两行代码同样是打开蓝牙,不过会提示用户:

intemtenabler=new intent(bluetoothadapter.action_request_enable);

startactivityforresult(enabler,recode);//同startactivity(enabler);

getaddress()获取本地蓝牙地址

getdefaultadapter()获取默认bluetoothadapter,实际上,也只有这一种方法获取bluetoothadapter

getname()获取本地蓝牙名称

getremotedevice(string address)根据蓝牙地址获取远程蓝牙设备

getstate()获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)

isdiscovering()判断当前是否正在查找设备,是返回true

isenabled()判断蓝牙是否打开,已打开返回true,否则,返回false

listenusingrfcommwithservicerecord(string name,uuid uuid)根据名称,uuid创建并返回bluetoothserversocket,这是创建bluetoothsocket服务器端的第一步

startdiscovery()开始搜索,这是搜索的第一步

2.bluetoothdevice看名字就知道,这个类描述了一个蓝牙设备

createrfcommsockettoservicerecord(uuiduuid)根据uuid创建并返回一个bluetoothsocket

这个方法也是我们获取bluetoothdevice的目的——创建bluetoothsocket

这个类其他的方法,如getaddress(),getname(),同bluetoothadapter

3.bluetoothserversocket如果去除了bluetooth相信大家一定再熟悉不过了,既然是socket,方法就应该都差不多,

这个类一种只有三个方法

两个重载的accept(),accept(inttimeout)两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,直到接收到了客户端的请求(或是过期之后),都会阻塞线程,应该放在新线程里运行!

还有一点需要注意的是,这两个方法都返回一个bluetoothsocket,最后的连接也是服务器端与客户端的两个bluetoothsocket的连接

close()这个就不用说了吧,翻译一下——关闭!

4.bluetoothsocket,跟bluetoothserversocket相对,是客户端

一共5个方法,不出意外,都会用到

close(),关闭

connect()连接

getinptustream()获取输入流

getoutputstream()获取输出流

getremotedevice()获取远程设备,这里指的是获取bluetoothsocket指定连接的那个远程蓝牙设备

根据这篇文章只是更改了最后的蓝牙连接部分(因为佳博打印机有自己的sdk,sdk中有自己的连接方法)将下载的demo中的gprintersdkv22.jar和xutils-2.6.14.jar两个包导入,之后的连接方法如下:

/**
*连接
*/
private voidconnect() {
intrel =0;
try{//使用端口1,4代表模式为蓝牙模式,蓝牙地址,最后默认为0
rel = mgpservice.openport(1,4,adressdata.get(loction),0);
}catch(remoteexception e) {
e.printstacktrace();
}
gpcom.error_code r = gpcom.error_code.values()[rel];
if(r != gpcom.error_code.success) {
if(r == gpcom.error_code.device_already_open) {
//开启成功
}else{
uiutils.showmessage(gpcom.geterrortext(r));
}
}else{
progressdialogutil.dismiss(buletoothactivity.this);
uiutils.showmessage("失败");
}
}

不要忘记的就是mgpservice是佳博sdk的一个自己的服务,要先获取,并与activity进行绑定;

protected voidoncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.activity_buletooth);
connection();
}
private voidconnection() {
conn=newprinterserviceconnection();
intent intent =newintent(this, gpprintservice.class);
this.bindservice(intent,conn, context.bind_auto_create);// bindservice
}
classprinterserviceconnectionimplementsserviceconnection {
@override
public void onservicedisconnected(componentname name) {
mgpservice=null;
}
@override
public void onserviceconnected(componentname name, ibinder service) {
mgpservice= gpservice.stub.asinterface(service);
}
}

还要在清单文件中去配置服务

<service
android:name="com.gprinter.service.gpprintservice"
android:enabled="true"
android:exported="true"
android:label="gpprintservice">
<intent-filter>
<actionandroid:name="com.gprinter.aidl.gpprintservice"/>
</intent-filter>
</service>
<serviceandroid:name="com.gprinter.service.allservice">
</service>

做完这些之后就大功告成,可以连接到打印机了,不过还是不能打印,还要进行一些打印的配置,由于我的项目的原因,连接和打印并没有在同一个界面,所以继续去研究佳博源码,发现如果前面链接已经成功的话,在另一个界面只需就行一个配置就可一直接打印打印也代码如下:

public classprintactivityextendsbaseactivityimplementsview.onclicklistener{
@bind(r.id.print_print)
buttonprint;
privategpservicemgpservice=null;
privateprinterserviceconnectionconn=null;
private static final int main_query_printer_status=0xfe;
private static final int request_print_label=0xfd;
private static final int request_print_receipt=0xfc;
private int mtotalcopies=0;
@override
protected void inithandler() {
handler=newhandler() {
@override
public void handlemessage(message msg) {
super.handlemessage(msg);
}
};
}
privatebroadcastreceivermbroadcastreceiver=newbroadcastreceiver() {
@override
public void onreceive(context context, intent intent) {
string action = intent.getaction();
log.d("tag", action);
// gpcom.action_device_real_status 为广播的intentfilter
if(action.equals(gpcom.action_device_real_status)) {
//业务逻辑的请求码,对应哪里查询做什么操作
intrequestcode = intent.getintextra(gpcom.extra_printer_request_code, -1);
//判断请求码,是则进行业务操作
if(requestcode ==main_query_printer_status) {
intstatus = intent.getintextra(gpcom.extra_printer_real_status,16);
string str;
if(status == gpcom.state_no_err) {
str ="打印机正常";
}else{
str ="打印机 ";
if((byte) (status & gpcom.state_offline) > 0) {
str +="脱机";
}
if((byte) (status & gpcom.state_paper_err) > 0) {
str +="缺纸";
}
if((byte) (status & gpcom.state_cover_open) > 0) {
str +="打印机开盖";
}
if((byte) (status & gpcom.state_err_occurs) > 0) {
str +="打印机出错";
}
if((byte) (status & gpcom.state_times_out) > 0) {
str +="查询超时";
}
}
toast.maketext(getapplicationcontext(),"打印机:"+1+"状态:"+ str, toast.length_short)
.show();
}else if(requestcode ==request_print_receipt) {
intstatus = intent.getintextra(gpcom.extra_printer_real_status,16);
if(status == gpcom.state_no_err) {
sendreceipt();
}else{
toast.maketext(printactivity.this,"query printer status error", toast.length_short).show();
}
}
}
}
};
@override
protected void inittitle() {
mtitletextmiddle.settext("打印");
}
private void connection() {
conn=newprinterserviceconnection();
intent intent =newintent(this, gpprintservice.class);
this.bindservice(intent,conn, context.bind_auto_create);// bindservice
}
classprinterserviceconnectionimplementsserviceconnection {
@override
public void onservicedisconnected(componentname name) {
log.i("serviceconnection","onservicedisconnected() called");
mgpservice=null;
}
@override
public void onserviceconnected(componentname name, ibinder service) {
mgpservice= gpservice.stub.asinterface(service);
}
}
@override
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.activity_print);
connection();
//注册实时状态查询广播
registerreceiver(mbroadcastreceiver,newintentfilter(gpcom.action_device_real_status));
/**
*票据模式下,可注册该广播,在需要打印内容的最后加入addqueryprinterstatus(),在打印完成后会接收到
* action为gpcom.action_device_status的广播,特别用于连续打印,
*可参照该sample中的sendreceiptwithresponse方法与广播中的处理
**/
registerreceiver(mbroadcastreceiver,newintentfilter(gpcom.action_receipt_response));
/**
*标签模式下,可注册该广播,在需要打印内容的最后加入addqueryprinterstatus(response_mode mode)
*,在打印完成后会接收到,action为gpcom.action_label_response的广播,特别用于连续打印,
*可参照该sample中的sendlabelwithresponse方法与广播中的处理
**/
registerreceiver(mbroadcastreceiver,newintentfilter(gpcom.action_label_response));
}
@override
protected void initview() {
print.setonclicklistener(this);
}
@override
public void onclick(view v) {
switch(v.getid()) {
caser.id.print_print:
if(mgpservice==null) {
uiutils.showmessage("服务正在开启");
}else{
try{
inttype =mgpservice.getprintercommandtype(1);
if(type == gpcom.esc_command) {
mgpservice.queryprinterstatus(1,1000,request_print_receipt);
}else{
toast.maketext(this,"printer is not receipt mode", toast.length_short).show();
}
}catch(remoteexception e1) {
e1.printstacktrace();
}
}
break;
}
}
private void sendreceipt() {
esccommand esc =newesccommand();
esc.addinitializeprinter();
esc.addprintandfeedlines((byte)3);
esc.addselectjustification(esccommand.justification.center);//设置打印居中
esc.addselectprintmodes(esccommand.font.fonta, esccommand.enable.off, esccommand.enable.on, esccommand.enable.on, esccommand.enable.off);//设置为倍高倍宽
esc.addtext("asdfkldsjgfsdl\n");//打印文字
esc.addprintandlinefeed();
/*打印文字 */
esc.addselectprintmodes(esccommand.font.fonta, esccommand.enable.off, esccommand.enable.off, esccommand.enable.off, esccommand.enable.off);//取消倍高倍宽
esc.addselectjustification(esccommand.justification.left);//设置打印左对齐
esc.addtext("dfkdsgklfds\n");//打印文字
// esc.addtext("welcome to use smarnet printer!\n"); //打印文字
// /*打印繁体中文需要打印机支持繁体字库 */
// string message = "佳博智匯票據打印機\n";
// // esc.addtext(message,"big5");
// esc.addtext(message, "gb2312");
esc.addprintandlinefeed();
/*绝对位置具体详细信息请查看gp58编程手册 */
esc.addtext("商品名称");
esc.addsethorandvermotionunits((byte)7, (byte)0);
esc.addsetabsoluteprintposition((short)6);
esc.addtext("订单号");
esc.addsetabsoluteprintposition((short)10);
esc.addtext("状态");
esc.addprintandlinefeed();
esc.addtext("苹果");
esc.addsethorandvermotionunits((byte)7, (byte)0);
esc.addsetabsoluteprintposition((short)6);
esc.addtext("12345");
esc.addsetabsoluteprintposition((short)10);
esc.addtext("正常");
esc.addprintandlinefeed();
esc.addtext("果粒橙300ml");
esc.addsethorandvermotionunits((byte)7, (byte)0);
esc.addsetabsoluteprintposition((short)6);
esc.addtext("3545456");
esc.addsetabsoluteprintposition((short)10);
esc.addtext("正常");
esc.addprintandlinefeed();
// /*打印图片 */
// esc.addtext("print bitmap!\n"); //打印文字
// bitmap b = bitmapfactory.decoderesource(getresources(), r.drawable.gprinter);
// esc.addrastbitimage(b, 384, 0); //打印图片
// /*打印一维条码 */
// esc.addtext("print code128\n"); //打印文字
// esc.addselectprintingpositionforhricharacters(esccommand.hri_position.below);//
// //设置条码可识别字符位置在条码下方
// esc.addsetbarcodeheight((byte) 60); //设置条码高度为60点
// esc.addsetbarcodewidth((byte) 1); //设置条码单元宽度为1
// esc.addcode128(esc.gencodeb("smarnet")); //打印code128码
// esc.addprintandlinefeed();
/*
* qrcode命令打印此命令只在支持qrcode命令打印的机型才能使用。在不支持二维码指令打印的机型上,则需要发送二维条码图片
*/
esc.addtext("商家二维码\n");//打印文字
esc.addselecterrorcorrectionlevelforqrcode((byte)0x31);//设置纠错等级
esc.addselectsizeofmoduleforqrcode((byte)6);//设置qrcode模块大小
esc.addstoreqrcodedata("dfgdgs");//设置qrcode内容
esc.addprintqrcode();//打印qrcode
esc.addprintandlinefeed();
/*打印文字 */esc.addselectjustification(esccommand.justification.center);//设置打印左对齐
esc.addtext("completed!\r\n");//打印结束
//开钱箱
esc.addgenerateplus(labelcommand.foot.f5, (byte)255, (byte)255);
esc.addprintandfeedlines((byte)8);
vector<byte> datas = esc.getcommand();//发送数据
byte[] bytes = gputils.byteto_byte(datas);
string sss = base64.encodetostring(bytes, base64.default);
intrs;
try{
rs =mgpservice.sendesccommand(1, sss);
gpcom.error_code r = gpcom.error_code.values()[rs];
if(r != gpcom.error_code.success) {
toast.maketext(getapplicationcontext(), gpcom.geterrortext(r), toast.length_short).show();
}
}catch(remoteexception e) {
//todo auto-generated catch block
e.printstacktrace();
}
}
}

至此大功告成,打印出东西之后感觉好爽

以上所述是小编给大家介绍的android手机通过蓝牙连接佳博打印机的实例代码,希望对大家有所帮助