您的位置:首页 > 移动开发 > Android开发

androidUSB通信——打印机

2016-03-11 11:33 691 查看

  • 三使用jar包打印
  • 3 MainActivityjava
  • 四打印的图片
  • 五项目下载地址
  • 六其他参考项目

    androidUSB通信——打印机

    本文主要解决一下几个问题:
    - usb的基本通信
    - usb的基本通信打印文字
    - 使用jar包打印一个订单信息

    一、usb基础

    Android 支持各种 USB 外围设备,通过两种模式来支持 Android USB 外设 (实现了 Android 外设协议的硬件): USB 外设模式和 USB 主机模式。在 USB 外设模式下,外部 USB 硬件(装有 Android 的设备要连接的外部设备)充当 USB 主机。
    关于usb的介绍可以查看:
    https://www.geek-share.com/detail/2531288721.html
    我们这里面使用的是 usb host方式,关于usb host的介绍可以查看官网文档,也可以查看:
    https://www.geek-share.com/detail/2609246602.html

    二、创建基本usb通信

    主要涉及到以下的文件:
    - AndroidManifest.xml 清单文件
    - UsbDemoActivity.java
    - qwm_usb_xml.xml 这个文件放在 res/xml的下面,用来过滤设备

    2.1qwm_usb_xml.xml说明

    这个文件放在 res/xml的下面,用来过滤设备,满足的设备将会被过滤出来。

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <usb-device vendor-id="1234" product-id="5678"/>
    <usb-device vendor-id="1155" product-id="22304" />
    </resources>
    
    <!--
    参数说明:
    vendor-id  (VID):产商id
    product-id (PID):产品id
    class             :类
    subclass          :子类
    protocol          :协议
    -->

    2.2AndroidManifest.xml清单文件配置

    这里主要用来申明usb的相关信息

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qwm.qwmprinterdemo">
    
    <!--声明使用usb-->
    <uses-feature android:name="android.hardware.usb.host"></uses-feature>
    
    <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
    </activity>
    <activity
    android:name=".UsbDemoActivity"
    android:label="@string/title_activity_usb_demo"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
    <!--usb设备的动作-->
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <!-- android设备的信息过滤-->
    <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
    android:resource="@xml/qwm_usb_xml" ></meta-data>
    </activity>
    </application>
    </manifest>

    2.3UsbDemoActivity.java usb的操作类

    这个类用来操作usb,我们主要按一下几个步骤来操作:
    - 1.创建UsbManager
    - 2.获取满足的设备
    - 3.获取满足设备中的“接口”
    - 4.获取接口的端点(获取设备endpoint)
    - 5.连接设备
    - 6.发送数据

    package com.qwm.qwmprinterdemo;
    
    import android.content.Context;
    import android.hardware.usb.UsbConstants;
    import android.hardware.usb.UsbDevice;
    import android.hardware.usb.UsbDeviceConnection;
    import android.hardware.usb.UsbEndpoint;
    import android.hardware.usb.UsbInterface;
    import android.hardware.usb.UsbManager;
    import android.os.Bundle;
    import android.support.design.widget.FloatingActionButton;
    import android.support.design.widget.Snackbar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.util.Log;
    import android.view.View;
    import android.widget.Switch;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import java.util.HashMap;
    import java.util.Iterator;
    
    /**
    * @author qiwenming
    * @date 2016/2/25 0025 上午 10:37
    * @ClassName: UsbDemoActivity
    * @PackageName: com.qwm.qwmprinterdemo
    * @Description: usb练习
    */
    public class UsbDemoActivity extends AppCompatActivity {
    
    private String TAG = UsbDemoActivity.class.getName();
    private UsbManager usbManager;
    private TextView usbDevicesTv;
    /**
    * 满足的设备
    */
    private UsbDevice myUsbDevice;
    /**
    * usb接口
    */
    private UsbInterface usbInterface;
    /**
    * 块输出端点
    */
    private UsbEndpoint epBulkOut;
    private UsbEndpoint epBulkIn;
    /**
    * 控制端点
    */
    private UsbEndpoint epControl;
    /**
    * 中断端点
    */
    private UsbEndpoint epIntEndpointOut;
    private UsbEndpoint epIntEndpointIn;
    /**
    * 连接
    */
    private UsbDeviceConnection myDeviceConnection;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_usb_demo);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    
    usbDevicesTv = (TextView) findViewById(R.id.tv_usb_devices);
    
    FloatingActionButton connectFab = (FloatingActionButton) findViewById(R.id.fab_connect);
    connectFab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {//连接usb
    //1)创建usbManager
    usbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
    //2)获取到所有设备 选择出满足的设备
    enumeraterDevices();
    //3)查找设备接口
    getDeviceInterface();
    //4)获取设备endpoint
    assignEndpoint();
    //5)打开conn连接通道
    openDevice();
    }
    });
    FloatingActionButton sendFab = (FloatingActionButton) findViewById(R.id.fab_send);
    sendFab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {//6.发送数据 String xx = "0D";
    new Thread(new Runnable() {
    @Override
    public void run() {
    try{
    sendMessageToPoint("杞文明\nqiwenming\nqiwenmingshiwo".getBytes("gbk"));
    }catch (Exception e){
    }
    }
    }).start();
    }
    });
    }
    
    /**
    * 枚举设备
    */
    public void enumeraterDevices(){
    HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
    Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
    StringBuilder sb = new StringBuilder();
    while(deviceIterator.hasNext()){
    UsbDevice device = deviceIterator.next();
    sb.append(devicesString(device));
    //                    sb.append(device.toString());
    //                    sb.append("\n\n");
    if (device.getVendorId() == 1155 && device.getProductId() == 22304) {
    myUsbDevice = device; // 获取USBDevice
    }
    }
    usbDevicesTv.setText(sb.toString());
    }
    
    /**
    * usb设备的信息
    * @param device
    * @return
    */
    public String devicesString(UsbDevice device){
    StringBuilder builder = new StringBuilder("UsbDevice\nName=" + device.getDeviceName() +
    "\nVendorId=" + device.getVendorId() + "\nProductId=" + device.getProductId() +
    "\nmClass=" + device.getClass() + "\nmSubclass=" + device.getDeviceSubclass() +
    "\nmProtocol=" + device.getDeviceProtocol() + "\nmManufacturerName=" +"\nmSerialNumber=" +
    "\n\n");
    return builder.toString();
    }
    
    /**
    * 获取设备的接口
    */
    private void getDeviceInterface() {
    if(myUsbDevice!=null){
    Log.i(TAG,"interfaceCounts : "+myUsbDevice.getInterfaceCount());
    usbInterface = myUsbDevice.getInterface(0);
    System.out.println("成功获得设备接口:" + usbInterface.getId());
    }
    }
    
    /**
    * 分配端点,IN | OUT,即输入输出;可以通过判断
    */
    private void assignEndpoint() {
    if(usbInterface!=null){
    for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
    UsbEndpoint ep = usbInterface.getEndpoint(i);
    switch (ep.getType()){
    case UsbConstants.USB_ENDPOINT_XFER_BULK://块
    if(UsbConstants.USB_DIR_OUT==ep.getDirection()){//输出
    epBulkOut = ep;
    System.out.println("Find the BulkEndpointOut," + "index:" + i + "," + "使用端点号:"+ epBulkOut.getEndpointNumber());
    }else{
    epBulkIn = ep;
    System.out .println("Find the BulkEndpointIn:" + "index:" + i+ "," + "使用端点号:"+ epBulkIn.getEndpointNumber());
    }
    break;
    case UsbConstants.USB_ENDPOINT_XFER_CONTROL://控制
    epControl = ep;
    System.out.println("find the ControlEndPoint:" + "index:" + i+ "," + epControl.getEndpointNumber());
    break;
    case UsbConstants.USB_ENDPOINT_XFER_INT://中断
    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {//输出
    epIntEndpointOut = ep;
    System.out.println("find the InterruptEndpointOut:" + "index:" + i + ","  + epIntEndpointOut.getEndpointNumber());
    }
    if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
    epIntEndpointIn = ep;
    System.out.println("find the InterruptEndpointIn:" + "index:" + i + ","+ epIntEndpointIn.getEndpointNumber());
    }
    break;
    default:
    break;
    }
    }
    }
    }
    
    /**
    * 连接设备
    */
    public void openDevice() {
    if(usbInterface!=null){//接口是否为null
    // 在open前判断是否有连接权限;对于连接权限可以静态分配,也可以动态分配权限
    UsbDeviceConnection conn = null;
    if(usbManager.hasPermission(myUsbDevice)){
    //有权限,那么打开
    conn = usbManager.openDevice(myUsbDevice);
    }
    if(null==conn){
    Toast.makeText(this,"不能连接到设备",Toast.LENGTH_SHORT).show();
    return;
    }
    //打开设备
    if(conn.claimInterface(usbInterface,true)){
    myDeviceConnection = conn;
    if (myDeviceConnection != null)// 到此你的android设备已经连上zigbee设备
    System.out.println("open设备成功!");
    final String mySerial = myDeviceConnection.getSerial();
    System.out.println("设备serial number:" + mySerial);
    } else {
    System.out.println("无法打开连接通道。");
    Toast.makeText(this,"无法打开连接通道。",Toast.LENGTH_SHORT).show();
    conn.close();
    }
    }
    }
    
    /**
    * 发送数据
    * @param buffer
    */
    public void sendMessageToPoint(byte[] buffer) {
    if(myDeviceConnection.bulkTransfer(epBulkOut,buffer,buffer.length,0) >= 0){
    //0 或者正数表示成功
    Toast.makeText(this,"发送成功",Toast.LENGTH_SHORT).show();
    }else{
    Toast.makeText(this,"发送失败的",Toast.LENGTH_SHORT).show();
    }
    }
    }

    三、使用jar包打印

    jar就是把上面打印的指令进行了封装。但是我们使用的是usb通信,所以上面的usb配置步骤还是需要的。
    主要涉及以下几个文件:
    - AndroidManifest.xml 清单文件配置
    - MainActivity.java 打印操作界面
    - PrintTerUtils.java 打印工具类
    - regoPrintLibV3.0.05.jar 打印的jar包

    3.1 regoPrintLibV3.0.05.jar包中 regoPrinter 类的主要方法说明

    regoPrinter打印机操作类主要方法如下:

    方法 说明
    CON_PageStart 开启页模式
    ASCII_PrintString 打印字符
    ASCII_CtrlPrintCRLF 换行
    DRAW_SetFillMode 画图填充方式
    DRAW_SetLineWidth 画图线的宽度
    DRAW_PrintRectangle 画矩形
    ASCII_CtrlReset 重置
    ASCII_CtrlCutPaper 切纸
    CON_PageEnd 结束页模式

    切纸的方法调用:

    //切纸功能
    printer.CON_PageStart(myState, false, 0, 0);
    printer.ASCII_CtrlCutPaper(myState, 30, 0);

    3.1AndroidManifest.xml配置说明

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qwm.qwmprinterdemo">
    
    <!--声明使用usb-->
    <uses-feature android:name="android.hardware.usb.host"></uses-feature>
    
    <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
    <!--usb设备的动作-->
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <!-- android设备的信息过滤-->
    <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
    android:resource="@xml/qwm_usb_xml" ></meta-data>
    </activity>
    <activity
    android:name=".UsbDemoActivity"
    android:label="@string/title_activity_usb_demo"
    android:theme="@style/AppTheme.NoActionBar">
    </activity>
    </application>
    </manifest>

    3.2 PrintTerUtils.java 打印工具类

    package com.qwm.qwmprinterdemo.utils;
    
    import android.widget.Toast;
    
    import com.qwm.qwmprinterdemo.MainActivity;
    
    import rego.printlib.export.regoPrinter;
    
    /**
    * @author qiwenming
    * @date 2016/2/29 0029 下午 4:20
    * @ClassName: PrintTerUtils
    * @PackageName: com.qwm.qwmprinterdemo.utils
    * @Description:  打印类
    */
    public class PrintTerUtils {
    public regoPrinter printer;
    private static PrintTerUtils printTerUtils;
    public int myState = 0;
    private String printName="RG-MTP58B";
    private MainActivity mainActivity;
    public boolean mBconnect = false;
    private final int wordSize = 20;
    /**
    * 打印的行数
    */
    private int pintCol = 0;
    /**
    * 小票的高度
    */
    private int pintHeight = 540;
    
    private PrintTerUtils(MainActivity mainActivity){
    this.mainActivity = mainActivity;
    connectDevices(mainActivity);
    }
    
    public static PrintTerUtils getPrintTerUtils(MainActivity mainActivity){
    if (printTerUtils==null){
    printTerUtils = new PrintTerUtils(mainActivity);
    }
    return printTerUtils;
    }
    
    /**
    * 连接设备
    */
    private void connectDevices(MainActivity mainActivity){
    this.mainActivity = mainActivity;
    if(printer==null){
    printer = new regoPrinter(mainActivity);//创建设备
    }
    //1.判读设备是否连着
    if(!mBconnect){//没有连接,那么我们连接 (连接设备)
    myState = printer.CON_ConnectDevices(printName, "usb", 200);//连接
    if (myState > 0) {
    Toast.makeText(mainActivity, "打印机连接成功",
    Toast.LENGTH_SHORT).show();
    mBconnect = true;
    }else{
    mBconnect = false;
    return;
    }
    }
    }
    
    /**
    * 打印购物网当
    */
    public void toPrintOrder() {
    //TODO 设置我们的 订单
    printer.CON_PageStart(myState,false,0,0);
    printer.ASCII_CtrlAlignType(myState, preDefiniation.AlignType.AT_CENTER.getValue());
    printer.ASCII_PrintString(myState, 0, 1, 0, 0, 0, "欢迎光临  ", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "店铺名称  ", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_CtrlAlignType(myState, preDefiniation.AlignType.AT_LEFT.getValue());
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "收银员:收银员名称", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "时间:2015-01-01", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "----------------------------", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 1, 0, 0, "商品名称        单价      数量      金额", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "花生           2.00      1      2.00", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "----------------------------", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "合计:¥100元", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "优惠金额:¥90元", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "电话:00000000", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "地址:汉武大帝大厦", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_PrintString(myState, 0, 0, 0, 0, 0, "谢谢惠顾,欢迎下次光临!", "gb2312");
    printer.ASCII_CtrlPrintCRLF(myState, 1);
    printer.ASCII_CtrlReset(myState);
    printer.ASCII_CtrlCutPaper(myState, 66, 0);//切纸
    printer.CON_PageEnd(myState,0);
    }
    
    /**
    * 回收单子2
    */
    public void toPrint3(){
    printer.CON_PageStart(myState, true, 540, 540);
    printer.DRAW_SetFillMode(false);
    printer.DRAW_SetLineWidth(4);
    //矩形
    printer.DRAW_PrintRectangle(myState, 18, 10, 540, 540);
    printer.DRAW_PrintText(myState, 108, 32, "手机回收凭证", 40);
    printer.DRAW_PrintText(myState, 108, 82, "服务门店:小明大厦店", 20);
    printer.DRAW_SetLineWidth(2);
    printer.DRAW_PrintLine(myState, 38, 107, 500, 107);//线条
    printer.DRAW_PrintText(myState, 38, 127, "订单号:123456789", 25);
    printer.DRAW_PrintText(myState, 38, 167, "时间:2016-01-26 14:50", 25);
    printer.DRAW_PrintText(myState, 38, 207, "姓名:杞文明     联系电话:13000000", 25);
    printer.DRAW_PrintLine(myState, 38, 237, 500, 237);//线条
    printer.DRAW_PrintText(myState, 38, 257, "机型:iPhone 6s", 25);
    printer.DRAW_PrintText(myState, 38, 297, "IMEI:123456789987654123", 25);
    printer.DRAW_PrintText(myState, 38, 337, "设备情况:", 25);
    //下面的高度需要更具字符的个数计算
    printer.DRAW_PrintText(myState, 38, 377, "大陆国行/三网通/过保/xxxxx/小米/嘻嘻嘻一/附件是弟弟福建省的/十分激动手机覅及地上/啦啦啦", 25);
    printer.DRAW_PrintLine(myState, 38, 462, 500, 462);//线条
    printer.DRAW_PrintText(myState, 38, 482, "回收价:1000元RMB", 25);
    printer.CON_PageEnd(myState, 0);
    //切纸功能
    printer.CON_PageStart(myState, false, 0, 0);
    printer.ASCII_CtrlCutPaper(myState, 30, 0);
    printer.CON_PageEnd(myState,0);
    }
    
    }

    3.3 MainActivity.java

    package com.qwm.qwmprinterdemo;
    
    import android.os.Bundle;
    import android.support.design.widget.FloatingActionButton;
    import android.support.design.widget.Snackbar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.View;
    import android.view.Menu;
    import android.view.MenuItem;
    
    import com.qwm.qwmprinterdemo.utils.PrintTerUtils;
    
    /**
    * @author qiwenming
    * @date 2016/2/29 0029 下午 4:32
    * @ClassName: MainActivity
    * @PackageName: com.qwm.qwmprinterdemo
    * @Description: 打印
    */
    public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    }
    
    /**
    * 打印订单
    * @param view
    */
    public void printOrder1(View view){
    PrintTerUtils.getPrintTerUtils(this).toPrintOrder();
    }
    
    /**
    * 打印回收单
    * @param view
    */
    public void printOrder2(View view){
    PrintTerUtils.getPrintTerUtils(this).toPrint2();
    }
    
    /**
    * 打印回收单
    * @param view
    */
    public void printOrder3(View view){
    PrintTerUtils.getPrintTerUtils(this).toPrint3();
    }
    }

    四、打印的图片


    五、项目下载地址

    https://github.com/qiwenming/QwmPrinterDemo

    六、其他参考项目

    6.1 串口通信打印

    80mm https://github.com/antwari/print

    58mm https://github.com/antwari/printDemo

    6.2 usb等打印

    https://github.com/CelloscopeRnD/PrintingDemo

    <script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script> 阅读更多
  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: