前言
这几天,我一直在构思怎么写这篇文章,很多时候写一篇博客往往要想很久,代码也许一会就写完了。在之前写过一篇Android操作蓝牙打印机(上),当时也是因为自己在工作中确实走了许多弯路,所以当时计划着用两篇文章详细阐述蓝牙打印的整个流程,也是对工作的一种总结,其次也可以给蓝牙打印方面感觉困惑的同学做一些参考,后来由于接近年底,任务比较多,所以就暂且搁置了。后来在阅读之前的代码时发现是相当繁琐(甚至感觉有些地方考虑的很复杂),最明显的复杂就是通过广播去监听蓝牙的状态,操作起来相当繁琐,久而久之,随着业务场景的增多,就出了bug,最头疼的就是与业务代码参杂在一起,不够解耦,也包括后来测试也给我提了bug,导致在bug系统挂了很久,前几天的一天早上项目经理也问我什么时候把这个bug处理一下,其实早在五一之前我就对此次重构做了一个大概了,只是一些周边细节未完善,这几天也是抽了许多时间优化,测试,把项目相关模块重构,将蓝牙部分抽取出来以依赖的方式集成在项目中。
git地址
传送门(https://github.com/zhuhuitao/printer)
在你的app build.gradle 中添加如下代码:
dependencies {
...
implementation "com.github.zhuhuitao:printer:1.0.9"
}
在上一篇文章之后,有好几个小伙伴私信我,能不能把源码放到git,参考一下,这里我统一回复,当时由于整个蓝牙部分与业务参杂在一起,并没有一个完整的demo,后来也没有上传,所以给之前带来不便的小伙伴,说一声抱歉。
功能介绍
在之前的文章中从头到尾是阐述了如何扫描,连接蓝牙,大都与蓝牙相关,此次与之前大为不同,这里我们只需要将相关依赖导入项目中,我们可以将所有精力放到我们业务代码中,不需要在关心蓝牙部分,依赖已将所有蓝牙部分做了封装,我们只管调用接口完成打印就好。并且这次重构简化了许多代码,结构清晰,也去掉了广播监听,等等许多繁琐的地方。
在阐述使用之前我还是将整个依赖的大体功能做一些介绍:
1,核心接口Imybinder类,这个类主要是与我们业务打交道的接口,包括我们连接蓝牙,往蓝牙打印机写入数据,断开蓝牙等相关功能,代码如下:
/**
*author : huitao
*e-mail : pig.huitao@gmail.com
*date : 2021/4/13 10:42
*desc :
*version :
*/
interface Imybinder {
fun connectBtPort(var1: String, var2: TaskCallback)
fun disconnectCurrentPort(var1: TaskCallback)
fun clearBuffer()
fun checkLinkedState(var1: TaskCallback)
fun ondiscovery(
var1: Context,
portType: PrinterDev.PortType,
callback: DeviceFoundCallback
): MutableList<String>?
fun getBtAvailableDevice(): MutableList<String>
fun write(var1: ByteArray?, var2: TaskCallback)
fun writeSendData(var1: TaskCallback, var2: ProcessData)
fun acceptDataFromPrinter(var1: TaskCallback?, var2: Int)
fun readBuffer(): RoundQueue<ByteArray?>?
fun read(var1: TaskCallback)
}
2,核心服务PrinterService类,在这个类中,实现了上述提到的Imybinder接口,主要是对上一步Imybinder接口做了进一步描述,代码如下:
class PrinterService : Service() {
private val mmybinder = mybinder()
private lateinit var mPrinterDev: PrinterDev
private lateinit var mReturnMsg: ReturnMessage
private var mIsConnected = false
private var mQueue: RoundQueue<ByteArray>? = null
private var mDeviceFoundCallback: DeviceFoundCallback? = null
private fun getInstanceRoundQueue(): RoundQueue<ByteArray> {
if (this.mQueue == null) {
mQueue = RoundQueue(500)
}
return this.mQueue!!
}
override fun onCreate() {
super.onCreate()
this.mQueue = this.getInstanceRoundQueue()
}
private val mviewmodelScope = Coroutinescope(dispatchers.IO)
override fun onBind(p0: Intent?): IBinder {
return this.mmybinder
}
inner class mybinder : Binder(), Imybinder {
private var mBluetoothAdapter: BluetoothAdapter? = null
private var mFond: MutableList<String>? = null
private var mBond: MutableList<String>? = null
private var mPortType: PrinterDev.PortType? = null
private val mReceiver = object : broadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
if (p1?.action == "android.bluetooth.device.action.FOUND") {
val device =
p1.getParcelableExtra<BluetoothDevice>("android.bluetooth.device.extra.DEVICE")
?: return
if (!device.name.isNullOrEmpty()) {
mFond?.forEach {
if (it.split("\n").last() == device.address) {
return
}
}
mFond?.add("${device.name}\n${device.address}")
mDeviceFoundCallback?.deviceFoundCallback("${device.name} \n ${device.address}")
}
}
}
}
override fun connectBtPort(var1: String, var2: TaskCallback) {
mviewmodelScope.launch {
mPrinterDev = PrinterDev(PrinterDev.PortType.Bluetooth, var1)
mReturnMsg = this@PrinterService.mPrinterDev.open()
mPortType = PrinterDev.PortType.Bluetooth
mviewmodelScope.launch(dispatchers.Main) {
when (mReturnMsg.getErrorCode()) {
PrinterDev.ErrorCode.OpenPortSucceed -> {
mIsConnected = true
var2.onSucceed()
}
else -> {
var2.onFailed()
}
}
}
}
}
override fun disconnectCurrentPort(var1: TaskCallback) {
mviewmodelScope.launch {
mReturnMsg = mPrinterDev.close()
mviewmodelScope.launch(dispatchers.Main) {
when (mReturnMsg.getErrorCode()) {
PrinterDev.ErrorCode.ClosePortSucceed -> {
mIsConnected = false
if (mQueue != null) {
mQueue?.clear()
}
var1.onSucceed()
}
else -> {
var1.onFailed()
}
}
}
}.start()
}
override fun clearBuffer() {
mQueue?.clear()
}
override fun checkLinkedState(var1: TaskCallback) {
mviewmodelScope.launch {
if (mPrinterDev.getPortInfo().isOpened) var1.onSucceed() else var1.onFailed()
}.start()
}
override fun ondiscovery(
var1: Context,
portType: PrinterDev.PortType,
callback: DeviceFoundCallback
): MutableList<String>? {
this.mFond = mutablelistof()
this.mBond = mutablelistof()
mDeviceFoundCallback = callback
if (portType == PrinterDev.PortType.Bluetooth) {
this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
if (mBluetoothAdapter == null) {
Toast.makeText(
this@PrinterService,
"Device didn't support bluetooth !\n",
Toast.LENGTH_SHORT
).show()
return null
}
if (mBluetoothAdapter!!.isEnabled) {
if (mBluetoothAdapter!!.enable()) {
if (!mBluetoothAdapter!!.isdiscovering) {
mBluetoothAdapter!!.startdiscovery()
}
val filter = IntentFilter("android.bluetooth.device.action.FOUND")
registerReceiver(mReceiver, filter)
val pairedDevice = mBluetoothAdapter!!.bondedDevices
if (!pairedDevice.isNullOrEmpty()) {
val it = pairedDevice.iterator()
while (it.hasNext()) {
val device = it.next()
mBond?.add("${device.name}\n${device.address}")
}
} else {
Looper.prepare()
Toast.makeText(
this@PrinterService,
"no paired device",
Toast.LENGTH_SHORT
).show()
Looper.loop()
}
} else {
Toast.makeText(
this@PrinterService,
"Bluetooth is not enable !\n",
Toast.LENGTH_SHORT
).show()
}
} else {
Toast.makeText(
this@PrinterService,
"Bluetooth adapter is not enabled !\n",
Toast.LENGTH_SHORT
).show()
}
}
return this.mBond
}
override fun getBtAvailableDevice(): MutableList<String> {
this.mBluetoothAdapter?.canceldiscovery()
return this.mFond!!
}
override fun write(var1: ByteArray?, var2: TaskCallback) {
if (var1 != null) {
mviewmodelScope.launch {
mReturnMsg = mPrinterDev.write(var1)
mviewmodelScope.launch(dispatchers.Main) {
when (mReturnMsg.getErrorCode()) {
PrinterDev.ErrorCode.WriteDataSucceed -> {
mIsConnected = true
var2.onSucceed()
}
else -> {
mIsConnected = false
var2.onFailed()
}
}
}
}
}
}
override fun writeSendData(var1: TaskCallback, var2: ProcessData) {
val list = var2.processDataBeforeSend()
if (list == null) {
var1.onFailed()
} else {
mviewmodelScope.launch {
list.forEach {
mReturnMsg = mPrinterDev.write(it)
}
when (mReturnMsg.getErrorCode()) {
PrinterDev.ErrorCode.WriteDataSucceed -> {
mIsConnected = true
var1.onSucceed()
}
else -> {
mIsConnected = false
var1.onFailed()
}
}
}.start()
}
}
override fun acceptDataFromPrinter(var1: TaskCallback?, var2: Int) {
val buffer = ByteArray(var2)
mviewmodelScope.launch {
kotlin.runcatching {
mQueue = getInstanceRoundQueue()
mQueue?.clear()
mQueue?.addLast(buffer)
Log.i("frank", "acceptDataFromPrinter: " + Arrays.toString(mQueue!!.last))
}.onSuccess {
}.onFailure {
}
}
}
override fun readBuffer(): RoundQueue<ByteArray?>? {
return null
}
override fun read(var1: TaskCallback) {
mviewmodelScope.launch {
val msg = mPrinterDev.read()
Log.d("frank", "read: $msg")
}
}
}
}
在我们使用的时候仅和这两个类做了相关调用,由于我主要想讲述如何使用此依赖,所以暂且介绍了这两个类,如果感兴趣可以直接阅读源码,这样更快捷。
使用
一般我们都是将蓝牙部分运用在项目中,并不像我们写个demo学习那样简单,我也思考着怎么把demo写的更贴实际,但是终究demo功能还是很单一,没有实际业务那么复杂,所以建议只是做参考。
1,创建服务MyService类继承android 中的Service,其实为了简单,也可以不创建服务,为了更贴实际项目,所以创建了MyService,这个服务主要是用来启动我们蓝牙模块中的PrinterService,以及启动另外一个辅助服务AncillaryService,辅助服务接下来我再另外介绍,最后也就是与我们业务做交互,比如与Activity做交互发送接收数据。MyService主要是我们业务的Activity与PrintService中间的桥梁,详细代码如下:
/**
*author : huitao
*e-mail : pig.huitao@gmail.com
*date : 2021/5/17 18:07
*desc :
*version :
*/
class MyService : Service() {
private var mImybinder: Imybinder? = null
private val mServiceConnect = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mImybinder = service as Imybinder
val mac = ""
connectByMac(mac, object : TaskCallback {
override fun onSucceed() {
}
override fun onFailed() {
}
})
}
override fun onServicedisconnected(name: ComponentName?) {
}
}
fun getBondDeviceList(): MutableList<String>? {
return mImybinder?.ondiscovery(
this,
PrinterDev.PortType.Bluetooth,
object : DeviceFoundCallback {
override fun deviceFoundCallback(device: String) {
//这里接收扫描的周围蓝牙设备
}
})
}
fun writeData(bean: OrderBean, task: TaskCallback) {
printOrderDetail(mmybinder = mImybinder!!, order = bean, taskCallback = task)
}
fun connectByMac(mac: String, task: TaskCallback) {
if (mac.isNotEmpty()) {
mImybinder?.connectBtPort(mac, task)
}
}
fun disconnect(task: TaskCallback) {
mImybinder?.disconnectCurrentPort(task)
}
override fun onCreate() {
super.onCreate()
val intent = Intent(this, AncillaryService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AncillaryService.startForeground(this)
startForegroundService(intent)
} else {
startService(intent)
}
val service = Intent(this, PrinterService::class.java)
bindService(service, mServiceConnect, BIND_AUTO_CREATE)
}
override fun onBind(p0: Intent?): IBinder {
return mybinder()
}
inner class mybinder : Binder() {
fun getService(): MyService {
return this@MyService
}
}
}
2,关于辅助服务AncillaryService,也是继承android Service,这个类主要是用来在手机通知栏弹出一个应用正在运行的功能,因为实际项目中可以尽可能的减少被系统杀死的概率,由于我们主要任务不在此处,包括8.0之前与之后系通知栏的变化,如果你感兴趣,还是建议收集资料详细的了解,比如实际代码中,我在onCreate直接停止了服务 stopSelf(),这个主要是在7.0之前有效,就是可以做一个假象,通知栏不会存在通知。详细代码如下:
/**
*author : huitao
*e-mail : pig.huitao@gmail.com
*date : 2021/5/17 18:39
*desc :
*version :
*/
class AncillaryService:Service() {
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(this)
}
stopSelf()
}
override fun onDestroy() {
super.onDestroy()
stopForeground(true)
}
companion object{
fun startForeground(ctx: Service) {
try {
val CHANNEL_ONE_ID = "CHANNEL_ONE_ID"
val CHANNEL_ONE_NAME = "CHANNEL_ONE_ID"
val SERVICE_ID = 802
val notificationChannel: NotificationChannel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationChannel = NotificationChannel(
CHANNEL_ONE_ID, CHANNEL_ONE_NAME, notificationmanager.IMPORTANCE_HIGH
)
notificationChannel.enableLights(true)
notificationChannel.lightColor = R.color.app_them
notificationChannel.setShowBadge(true)
notificationChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
val nm = ctx.getSystemService(NOTIFICATION_SERVICE) as notificationmanager
nm.createNotificationChannel(notificationChannel)
}
val intent = Intent()
val className = Class.forName("com.huitao.printerdemo.printer.Printeractivity")
intent.setClassName(ctx, className.name)
val pendingIntent = PendingIntent.getActivity(ctx, 0, intent, 0)
val builder = NotificationCompat.Builder(ctx, CHANNEL_ONE_ID)
builder.setContentTitle(ctx.getString(R.string.pending_title))
.setContentText(ctx.getString(R.string.pending_content))
.setWhen(System.currentTimeMillis())
.setPriority(Notification.PRIORITY_MIN)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
val notification = builder.build()
ctx.startForeground(SERVICE_ID, notification)
} catch (e: ClassNotFoundException) {
e.printstacktrace()
}
}
}
}
3,业务层的Printeractivity,这个类中的主要功能就是绑定我们前面提到的MyService,布局中写了两个textView和一个RecyclerView,用来获取绑定设备,测试打印,以及展示已绑定的设备列表。绑定服务以及列表展示就不做相关详细介绍,重点介绍一下连接,断开,获取设备列表功能。
a,获取已绑定的设备:
mBinder?.getService()?.getBondDeviceList()
这行代码就会帮我们返回手机已绑定的蓝牙设备,具体获取是在PrinterService中实现的,前面有相关代码,看到这里我想你大概会存在疑问,如何获取周围的蓝牙设备,这可不必大有担心,也有实现,在PrinterService中,有以下代码:
fun getBondDeviceList(): MutableList<String>? {
return mImybinder?.ondiscovery(
this,
PrinterDev.PortType.Bluetooth,
object : DeviceFoundCallback {
override fun deviceFoundCallback(device: String) {
//这里接收扫描的周围蓝牙设备
}
})
}
我们可以在此处理扫描的周围蓝牙设备,也可以直接将集合回调到Activity层。
b,连接蓝牙,实际是一个耗时操作,底层已使用协程做了耗时处理,所以此处我们不必关心耗时相关代码,只关心回调给我们的连接状态,处理业务就好,详细代码如下:
mBinder?.getService()?.connectByMac(mList[obj].name.split("\n").last().trim(),
object : TaskCallback {
override fun onSucceed() {
Toast.makeText(
this@Printeractivity,
getString(R.string.connect_success),
Toast.LENGTH_SHORT
).show()
mIsConnect = true
mList[obj].isConnected = true
mAdapter.notifyItemChanged(obj)
}
override fun onFailed() {
Toast.makeText(
this@Printeractivity,
getString(R.string.connect_failure),
Toast.LENGTH_SHORT
).show()
}
})
c,断开连接,实际调用接口和连接一样,详细代码如下,不做过多介绍:
mBinder?.getService()?.disconnect(object : TaskCallback {
override fun onSucceed() {
Toast.makeText(
this@Printeractivity,
getString(R.string.disconnect_success),
Toast.LENGTH_SHORT
).show()
mList[obj].isConnected = false
mAdapter.notifyItemChanged(obj)
mIsConnect = false
}
override fun onFailed() {
Toast.makeText(
this@Printeractivity,
getString(R.string.disconnect_failure),
Toast.LENGTH_SHORT
).show()
}
})
d,最后介绍以下启动app后自动连接的功能,此方法在MyService中有实现,由于demo中没有使用数据库或者sp等存储功能,所以只写了一个样板,我们可以将上一次连接蓝牙mac,缓存在本地或者数据库中,下次在启动服务时,直接调用连接蓝牙功能连接蓝牙,代码如下:
private val mServiceConnect = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mImybinder = service as Imybinder
val mac = ""
connectByMac(mac, object : TaskCallback {
override fun onSucceed() {
}
override fun onFailed() {
}
})
}
override fun onServicedisconnected(name: ComponentName?) {
}
}
e,最后就是向蓝牙打印机写入数据,写入数据也是耗时操作,不过我们完全不用关心此问题,我们直接调用writeSendData就可以发送数据,完成打印功能,这里做了一个巧妙的设计,将我们的所有要打印的byte字节装入一个list集合,传给下层服务,可以直接完成打印,并且下层还将打印结果成功或者失败状态返回来,demo中的相关代码如下:
fun printOrderDetail(mmybinder: Imybinder, order: OrderBean, taskCallback: TaskCallback) {
mmybinder.writeSendData(taskCallback, object : ProcessData {
override fun processDataBeforeSend(): MutableList<ByteArray> {
val list = ArrayList<ByteArray>()
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.selectAliment(0x01))
list.add(DataForSendToPrinter.selectFontSize(0x11))
list.add(strToBytes("#${order.pickUpCode} 测试外卖")!!)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.selectAliment(0x01))
list.add(DataForSendToPrinter.selectFontSize(0x01))
list.add(strToBytes("*${order.shopName}*")!!)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.selectFontSize(0x11))
list.add(DataForSendToPrinter.selectAliment(0x01))
list.add(strToBytes("--已在线支付--")!!)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.printBothColumns("配送方式:", order.deliveryTypestr))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.printBothColumns("下单时间:", order.createTime))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
val onTime = order.receiveTime
if (onTime != null) {
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.printBothColumns("预计送达时间:", onTime))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.selectOrCancelBoldModel(0x01))
list.add(strToBytes("客户留言:")!!)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
if (order.remarks == null) {
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
} else {
list.add(strToBytes(order.remarks)!!)
}
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.initializePrinter())
if (order.receiver != null && order.receiver.isNotEmpty()) {
list.add(
DataForSendToPrinter.printBothColumns(
"收货人:",
"${order.receiver.substring(0, 1)}**"
)
)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
if (order.receiverMobile != null) {
list.add(DataForSendToPrinter.printBothColumns("电话:", order.receiverMobile))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
if (order.riderName != null) {
list.add(DataForSendToPrinter.printBothColumns("骑手:", order.riderName))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
if (order.riderMobile != null) {
list.add(DataForSendToPrinter.printBothColumns("电话:", order.riderMobile))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
if (order.address != null) {
list.add(strToBytes("收货地址:${order.address}")!!)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
list.add(DataForSendToPrinter.printThreeColumns("名称", "数量", "售价"))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
order.orderDetailList.forEach {
val price = when (it.isdiscount) {
1 -> numberFormat(it.amount)
else -> numberFormat(it.shopPrice)
}
list.add(DataForSendToPrinter.initializePrinter())
list.add(DataForSendToPrinter.selectOrCancelBoldModel(0x01))
list.add(strToBytes(it.goodsName)!!)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printThreeColumns("", "${it.buyCount}", "¥$price"))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
list.add(DataForSendToPrinter.initializePrinter())
list.add(
DataForSendToPrinter.printBothColumns(
"订单原价:",
"¥${numberFormat(order.money)}"
)
)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(
DataForSendToPrinter.printBothColumns(
"配送费:",
"¥${numberFormat(order.freight)}"
)
)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(
DataForSendToPrinter.printBothColumns(
"实付金额:",
"¥${numberFormat(order.payMoney)}"
)
)
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printBothColumns("订单类型:", order.orderTypestr))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
if (order.orderTypestr.contains("预约")) {
list.add(DataForSendToPrinter.printBothColumns("预约时间:", order.appointmentTime))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
}
list.add(DataForSendToPrinter.printBothColumns("订单号:", order.orderCode))
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
list.add(DataForSendToPrinter.printAndFeedLine())
return list
}
})
}
至此,介绍了整个依赖的详细使用,由于篇幅原因,不能贴入全部代码,如果感兴趣,还是建议直接查看源码。
总结
以上仅是对工作的一种总结,我也将一直持续维护此项目,由于个人经验能力不足,可能还存在些许问题,如果你觉得不合理,欢迎留言讨论,或者直接提出你的建议,我直接将你的想法写进项目中。