Android下的POS打印机调用的简单实现

本文基于GP58系列,它可以兼容ESC/POS指令集,对EPSON的打印机通用.

Android下的设备调试,如果设备提供了驱动,按照厂家的驱动调试即可;设备未提供驱动,只能按照通用的方法进行调试。这里采用的是调用USB接口来控制打印机输出。

1.首先获取USB管理器

public UsbAdmin(Context context) {
    mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
    mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    context.registerReceiver(mUsbReceiver, filter);
  }

使用一个延迟意图来接收usb接入时的广播,当广播接收到时,说明有新的设备接入。

添加一个boardcast action

代码如下:

private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      if (ACTION_USB_PERMISSION.equals(action)) {
        synchronized (this) {
          UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
          if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
            if (device != null) {
              setDevice(device);
            } else {
              Closeusb();
             // mDevice = device;
            }
          } else {
            Log.d(TAG, "permission denied for device " + device);
          } 

        } 

      }
    }
  };

取到usb设备的引用,android系统会询问你是否允许设备访问,默认为false;当允许了访问之后,会判断USB的引用是否为null,如果不为空则会调用setDevice来创建一个Connection,否则会关闭本次连接。

在setDevice中,我们可以获取设备的功能集(UsbInterface),也可以获取通信通道(UsbEndpoint),同时也创建了host与device的连接用来传输数据。

private void setDevice(UsbDevice device) {
    if (device != null) {
      UsbInterface intf = null;
      UsbEndpoint ep = null; 

      int InterfaceCount = device.getInterfaceCount();
      int j; 

      mDevice = device;
      for (j = 0; j < InterfaceCount; j++) {
        int i; 

        intf = device.getInterface(j);
        Log.i(TAG, "接口是:" + j + "类是:" + intf.getInterfaceClass());
        if (intf.getInterfaceClass() == 7) {
          int UsbEndpointCount = intf.getEndpointCount();
          for (i = 0; i < UsbEndpointCount; i++) {
            ep = intf.getEndpoint(i);
            Log.i(TAG, "端点是:" + i + "方向是:" + ep.getDirection() + "类型是:" + ep.getType());
            if (ep.getDirection() == 0 && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
              Log.i(TAG, "接口是:" + j + "端点是:" + i);
              break;
            }
          }
          if (i != UsbEndpointCount) {
            break;
          }
        }
      }
      if (j == InterfaceCount) {
        Log.i(TAG, "没有打印机接口");
        return;
      } 

      mEndpointIntr = ep; 

        UsbDeviceConnection connection = mUsbManager.openDevice(device); 

        if (connection != null && connection.claimInterface(intf, true)) {
          Log.i(TAG, "打开成功! ");
          mConnection = connection; 

        } else {
          Log.i(TAG, "打开失败! ");
          mConnection = null;
        }
      } 

  }

2.在相关的类中新建一个UsbAdmin,调用openUsb,这里首先是走了上面的setDevice()方法,获取到了设备的引用,当连接通道建立时列出所有USB设备,当设备的引用不存在时同样列出所有的USB设备,并且都请求获取USB权限。

public void openUsb() {
    if (mDevice != null) {
      setDevice(mDevice);
      if (mConnection == null) {
        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); 

        while (deviceIterator.hasNext()) {
          UsbDevice device = deviceIterator.next();
          mUsbManager.requestPermission(device, mPermissionIntent);
        }
      }
    } else {
      HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
      Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); 

      while (deviceIterator.hasNext()) {
        UsbDevice device = deviceIterator.next();
        mUsbManager.requestPermission(device, mPermissionIntent);
      }
    }
  }

3.当上面两部都走完了之后,我们就可以发送指令来控制已经建立连接的打印机了,这里我们使用的是标准的ESC/POS指令集,为硬件默认,贴出代码,这里的指令集采用的是十进制表示形式,也可以替换成十六进制。

public class printerCmdUtils { 

  /**
   * 这些数据源自爱普生指令集,为POS机硬件默认
   */ 

  public static final byte ESC = 27;//换码
  public static final byte FS = 28;//文本分隔符
  public static final byte GS = 29;//组分隔符
  public static final byte DLE = 16;//数据连接换码
  public static final byte EOT = 4;//传输结束
  public static final byte ENQ = 5;//询问字符
  public static final byte SP = 32;//空格
  public static final byte HT = 9;//横向列表
  public static final byte LF = 10;//打印并换行(水平定位)
  public static final byte CR = 13;//归位键
  public static final byte FF = 12;//走纸控制(打印并回到标准模式(在页模式下) )
  public static final byte CAN = 24;//作废(页模式下取消打印数据 ) 

//------------------------打印机初始化----------------------------- 

  /**
   * 打印机初始化
   * @return
   */
  public static byte[] init_printer()
  {
    byte[] result = new byte[2];
    result[0] = ESC;
    result[1] = 64;
    return result;
  } 

//------------------------换行----------------------------- 

  /**
   * 换行
   * @param lineNum要换几行
   * @return
   */
  public static byte[] nextLine(int lineNum)
  {
      byte[] result = new byte[lineNum];
      for(int i=0;i<lineNum;i++)
      {
        result[i] = LF;
      } 

      return result;
  } 

//------------------------下划线-----------------------------   

  /**
   * 绘制下划线(1点宽)
   * @return
   */
  public static byte[] underlineWithOneDotWidthOn()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 45;
    result[2] = 1;
    return result;
  } 

  /**
   * 绘制下划线(2点宽)
   * @return
   */
  public static byte[] underlineWithTwoDotWidthOn()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 45;
    result[2] = 2;
    return result;
  }
  /**
   * 取消绘制下划线
   * @return
   */
  public static byte[] underlineOff()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 45;
    result[2] = 0;
    return result;
  } 

//------------------------加粗----------------------------- 

  /**
   * 选择加粗模式
   * @return
   */
  public static byte[] boldOn()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 69;
    result[2] = 0xF;
    return result;
  } 

  /**
   * 取消加粗模式
   * @return
   */
  public static byte[] boldOff()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 69;
    result[2] = 0;
    return result;
  } 

//------------------------对齐----------------------------- 

  /**
   * 左对齐
   * @return
   */
  public static byte[] alignLeft()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 97;
    result[2] = 0;
    return result;
  } 

  /**
   * 居中对齐
   * @return
   */
  public static byte[] alignCenter()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 97;
    result[2] = 1;
    return result;
  } 

  /**
   * 右对齐
   * @return
   */
  public static byte[] alignRight()
  {
      byte[] result = new byte[3];
    result[0] = ESC;
    result[1] = 97;
    result[2] = 2;
    return result;
  } 

  /**
   * 水平方向向右移动col列
   * @param col
   * @return
   */
  public static byte[] set_HT_position( byte col )
  {
    byte[] result = new byte[4];
    result[0] = ESC;
    result[1] = 68;
    result[2] = col;
    result[3] = 0;
    return result;
  }
//------------------------字体变大----------------------------- 

  /**
   * 字体变大为标准的n倍
   * @param num
   * @return
   */
  public static byte[] fontSizeSetBig(int num)
  {
      byte realSize = 0;
      switch (num)
      {
      case 1:
        realSize = 0;break;
      case 2:
        realSize = 17;break;
      case 3:
        realSize = 34;break;
      case 4:
        realSize = 51;break;
      case 5:
        realSize = 68;break;
      case 6:
        realSize = 85;break;
      case 7:
        realSize = 102;break;
      case 8:
        realSize = 119;break;
      }
      byte[] result = new byte[3];
      result[0] = 29;
      result[1] = 33;
      result[2] = realSize;
      return result;
  } 

//------------------------字体变小----------------------------- 

  /**
   * 字体取消倍宽倍高
   * @param num
   * @return
   */
  public static byte[] fontSizeSetSmall(int num)
  {
      byte[] result = new byte[3];
      result[0] = ESC;
      result[1] = 33; 

    return result;
  } 

//------------------------切纸-----------------------------   

  /**
   * 进纸并全部切割
   * @return
   */
  public static byte[] feedPaperCutAll()
  {
      byte[] result = new byte[4];
     result[0] = GS;
     result[1] = 86;
     result[2] = 65;
     result[3] = 0;
     return result;
  } 

  /**
   * 进纸并切割(左边留一点不切)
   * @return
   */
  public static byte[] feedPaperCutPartial()
  {
      byte[] result = new byte[4];
     result[0] = GS;
     result[1] = 86;
     result[2] = 66;
     result[3] = 0;
     return result;
  } 

//------------------------切纸-----------------------------
  public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){
    byte[] byte_3 = new byte[byte_1.length+byte_2.length];
    System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
    System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
    return byte_3;
  }  

  public static byte[] byteMerger(byte[][] byteList){  

      int length = 0;
    for(int i=0;i<byteList.length;i++)
    {
        length += byteList[i].length;
    }
    byte[] result = new byte[length]; 

    int index = 0;
    for(int i=0;i<byteList.length;i++)
    {
        byte[] nowByte = byteList[i];
        for(int k=0;k<byteList[i].length;k++)
        {
          result[index] = nowByte[k];
          index++;
        }
    }
    return result;
  }  

}

4.在以上都完成之后,就可以把你需要的字符串转换成byte数组并调用sendCommand方法来进行打印了

@SuppressLint("NewApi")
  public boolean sendCommand(byte[] Content) {
    boolean Result;
    synchronized (this) {
      int len = -1;
      if (mConnection != null) {
        len = mConnection.bulkTransfer(mEndpointIntr, Content, Content.length, 10000);
      } 

      if (len < 0) {
        Result = false;
        Log.i(TAG, "发送失败! " + len);
      } else {
        Result = true;
        Log.i(TAG, "发送" + len + "字节数据");
      }
    }
    return Result;

代码如下:

len = mConnection.bulkTransfer(mEndpointIntr, Content, Content.length, 10000);

这一步仅仅加了同步锁,并未开启一个新的线程去处理,在本机上没有问题,但上面的USB通信机制的文章有提到要放到异步线程,这里需要注意。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 蓝牙连接 ESC/POS 热敏打印机打印实例(ESC/POS指令篇)

    上一篇 主要介绍了如何通过蓝牙连接到打印机.这一篇,我们就介绍如何向打印机发送打印指令,来打印字符和图片. 1. 构造输出流 首先要明确一点,就是蓝牙连接打印机这种场景下,手机是 Client 端,打印机是 Server 端. 在上一篇的最后,我们从 BluetoothSocket 得到了一个OutputStream.这里我们做一层包装,得到一个OutputStreamWriter 对象: OutputStreamWriter writer = new OutputStreamWriter(ou

  • Android 蓝牙连接 ESC/POS 热敏打印机打印实例(蓝牙连接篇)

    公司的一个手机端的 CRM 项目最近要增加小票打印的功能,就是我们点外卖的时候经常会见到的那种小票.这里主要涉及到两大块的知识: 蓝牙连接及数据传输 ESC/POS 打印指令 蓝牙连接不用说了,太常见了,这篇主要介绍这部分的内容.但ESC/POS 打印指令是个什么鬼?简单说,我们常见的热敏小票打印机都支持这样一种指令,只要按照指令的格式向打印机发送指令,哪怕是不同型号品牌的打印机也会执行相同的动作.比如打印一行文本,换行,加粗等都有对应的指令,这部分内容放在下一篇介绍. 本篇主要基于官方文档,相

  • Android进阶——安卓调用ESC/POS打印机打印实例

    前言 前一段时间由于工作需要,要研究一下安卓程序调用打印机打印小票,并且要求不能使用蓝牙调用,研究了一下,可以利用socket连接,来实现打印功能.写了个Demo,分享一下. 工具:一台打印机(芯烨XP-80XX),一台安卓测试机 开发环境:Android Studio 1.5 需求:点击按钮,实现打印小票功能,小票上除必要文字外,还要有二维码. 封装了一个Pos打印工具类: package com.example.haoguibao.myapplication; import java.io.

  • Android下的POS打印机调用的简单实现

    本文基于GP58系列,它可以兼容ESC/POS指令集,对EPSON的打印机通用. Android下的设备调试,如果设备提供了驱动,按照厂家的驱动调试即可:设备未提供驱动,只能按照通用的方法进行调试.这里采用的是调用USB接口来控制打印机输出. 1.首先获取USB管理器 public UsbAdmin(Context context) { mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); mPermi

  • Android下2d物理引擎Box2d用法简单实例

    本文实例讲述了Android下2d物理引擎Box2d用法.分享给大家供大家参考.具体如下: 程序运行的时候需要加载Jbox2d的库,可到以下地址下载(使用的是不带渲染部分的库jbox2d-2.0.1-library-only.jar): http://sourceforge.net/projects/jbox2d/ package com.test; import org.jbox2d.collision.AABB; import org.jbox2d.collision.CircleDef;

  • Android下拉阻尼效果实现原理及简单实例

    前言 本文将通过代码讲解下拉阻尼效果的实现原理. 实现灵感来源于这篇博客,但是这篇博客的代码并不能让我满意,或者说是糟糕的,不过还是非常感谢作者带给我的启发. 现在大部分资讯类安卓APP都有一个下拉刷新的功能,又如微信联系人列表顶部的小程序入口,也使用了这种下拉阻尼的效果. 我的代码主要是解释其实现原理,为方便读者理解,所以代码逻辑非常简单,但如果想要实现例如下拉刷新转动的进度圈,还需要修改代码中的MoveHeaderTask类中的onProgressUpdate方法:如果要实现滑动列表顶部加入

  • Android下拉刷新PtrFrameLayout的使用实例代码

    1.介绍: 可以包含所有的控件 :ListView, GridView, ScrollView, FrameLayout, 甚至 TextView. 可以自定义刷新头(这点非常实用) 使用简单方便 不足就是不支持上拉加载. 2.使用 首先添加依赖到项目 compile 'in.srain.cube:ultra-ptr:1.0.11' 在Xml中使用 <in.srain.cube.views.ptr.PtrFrameLayout xmlns:android="http://schemas.a

  • Android下拉刷新上拉加载控件(适用于所有View)

    前面写过一篇关于下拉刷新控件的文章下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能.不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~ 我做了一个大集合的demo,实现了ListView.GridView.ExpandableListView.ScrollView.WebView.ImageView.TextView的下拉刷新和上拉加载.后面会提供demo的

  • Android下如何使用百度地图sdk

    可以使用该套 SDK开发适用于Android系统移动设备的地图应用,通过调用地图SDK接口,您可以轻松访问百度地图服务和数据,构建功能丰富.交互性强的LBS(地图类)应用程序. 百度地图Android SDK提供的所有服务是免费的,接口使用无次数限制.您需申请密钥(key)后,才可使用百度地图Android SDK.任何非营利性产品请直接使用.这弦外之音就是盈利的产品必须帮百度给钱. 一.百度地图api平台. 百度地图API网址:http://developer.baidu.com/map/sd

  • 使用Promise解决多层异步调用的简单学习心得

    前言 第一次接触到Promise这个东西,是2012年微软发布Windows8操作系统后抱着作死好奇的心态研究用html5写Metro应用的时候.当时配合html5提供的WinJS库里面的异步接口全都是Promise形式,这对那时候刚刚毕业一点javascript基础都没有的我而言简直就是天书.我当时想的是,微软又在脑洞大开的瞎捣鼓了. 结果没想到,到了2015年,Promise居然写进ES6标准里面了.而且一项调查显示,js程序员们用这玩意用的还挺high. 讽刺的是,作为早在2012年就在M

  • linux 下实现sleep详解及简单实例

    linux 下实现sleep详解及简单实例 sleep: 普通版本 1.基本设计思路: 1>注册SIGALRM信号的处理函数:    2>调用alarm(nsecs)设定闹钟: 3>调⽤pause等待,内核切换到别的进程运行: 4>nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程 ; 5>从内核态返回这个进程的⽤户态之前处理未决信号,发现有SIGALRM信号,其处理函数是sig_alrm; 6> 切换到用户态执行sig_alrm函数,进⼊sig_alrm函数时

  • Android下拉刷新框架实现代码实例

    前段时间项目中用到了下拉刷新功能,之前在网上也找到过类似的demo,但这些demo的质量参差不齐,用户体验也不好,接口设计也不行.最张没办法,终于忍不了了,自己就写了一个下拉刷新的框架,这个框架是一个通用的框架,效果和设计感觉都还不错,现在分享给各位看官. 一. 关于下拉刷新 下拉刷新这种用户交互最早由twitter创始人洛伦•布里切特(Loren Brichter)发明,有理论认为,下拉刷新是一种适用于按照从新到旧的时间顺序排列feeds的应用,在这种应用场景中看完旧的内容时,用户会很自然地下

  • Android数据加密之Base64编码算法的简单实现

    前面学习总结了平时开发中遇见的各种数据加密方式,最终都会对加密后的二进制数据进行Base64编码,起到一种二次加密的效果,其实呢Base64从严格意义上来说的话不是一种加密算法,而是一种编码算法,为何要使用Base64编码呢?它解决了什么问题?这也是本文探讨的东西? 什么Base64算法? Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64并不是安全领域的加密算法,其实Base64只能算是一个编码算法,对数据内容进行编码来适合传输.标准Base64编码解码无需额外信

随机推荐