第一步:首先需要一个蓝牙打印工具类
import android.bluetooth.BluetoothSocket;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;

import com.github.promeg.pinyinhelper.Pinyin;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Calendar;

/**

  • 蓝牙打印工具类
    */
    public class PrintUtil {

    private OutputStreamWriter mWriter = null;
    private OutputStream mOutputStream = null;

    public final static int WIDTH_PIXEL = 384;
    public final static int IMAGE_SIZE = 320;
    private static String myTime;

    /**

    • 初始化Pos实例
    • @param encoding 编码
    • @throws IOException
      */
      public PrintUtil(OutputStream outputStream, String encoding) throws IOException {
      mWriter = new OutputStreamWriter(outputStream, encoding);
      mOutputStream = outputStream;
      initPrinter();
      }

    public void print(byte[] bs) throws IOException {
    mOutputStream.write(bs);
    }

    public void printRawBytes(byte[] bytes) throws IOException {
    mOutputStream.write(bytes);
    mOutputStream.flush();
    }

    /**

    • 初始化打印机
    • @throws IOException
      */
      public void initPrinter() throws IOException {
      mWriter.write(0x1B);
      mWriter.write(0x40);
      mWriter.flush();
      //获取当前时间
      getTime();
      }

    /**

    • 打印换行
    • @return length 需要打印的空行数
    • @throws IOException
      */
      public void printLine(int lineNum) throws IOException {
      for (int i = 0; i < lineNum; i++) {
      mWriter.write("\n");
      }
      mWriter.flush();
      }

    /**

    • 打印换行(只换一行)
    • @throws IOException
      */
      public void printLine() throws IOException {
      printLine(1);
      }

    /**

    • 打印空白(一个Tab的位置,约4个汉字)
    • @param length 需要打印空白的长度,
    • @throws IOException
      */
      public void printTabSpace(int length) throws IOException {
      for (int i = 0; i < length; i++) {
      mWriter.write("\t");
      }
      mWriter.flush();
      }

    /**

    • 绝对打印位置
    • @return
    • @throws IOException
      */
      public byte[] setLocation(int offset) throws IOException {
      byte[] bs = new byte[4];
      bs[0] = 0x1B;
      bs[1] = 0x24;
      bs[2] = (byte) (offset % 256);
      bs[3] = (byte) (offset / 256);
      return bs;
      }

    public byte[] getGbk(String stText) throws IOException {
    byte[] returnText = stText.getBytes(“GBK”); // 必须放在try内才可以
    return returnText;
    }

    private int getStringPixLength(String str) {
    int pixLength = 0;
    char c;
    for (int i = 0; i < str.length(); i++) {
    c = str.charAt(i);
    if (Pinyin.isChinese©) {
    pixLength += 24;
    } else {
    pixLength += 12;
    }
    }
    return pixLength;
    }

    public int getOffset(String str) {
    return WIDTH_PIXEL - getStringPixLength(str);
    }

    /**

    • 打印文字
    • @param text
    • @throws IOException
      */
      public void printText(String text) throws IOException {
      mWriter.write(text);
      mWriter.flush();
      }

    /**

    • 对齐0:左对齐,1:居中,2:右对齐
      */
      public void printAlignment(int alignment) throws IOException {
      mWriter.write(0x1b);
      mWriter.write(0x61);
      mWriter.write(alignment);
      }

    public void printLargeText(String text) throws IOException {

     mWriter.write(0x1b); mWriter.write(0x21); mWriter.write(48); mWriter.write(text); mWriter.write(0x1b); mWriter.write(0x21); mWriter.write(0); mWriter.flush();

    }

    public void printTwoColumn(String title, String content) throws IOException {
    int iNum = 0;
    byte[] byteBuffer = new byte[100];
    byte[] tmp;

     tmp = getGbk(title); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; tmp = setLocation(getOffset(content)); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; tmp = getGbk(content); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); print(byteBuffer);

    }

    public void printThreeColumn(String left, String middle, String right) throws IOException {
    int iNum = 0;
    byte[] byteBuffer = new byte[200];
    byte[] tmp = new byte[0];

     System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; tmp = getGbk(left); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; int pixLength = getStringPixLength(left) % WIDTH_PIXEL; if (pixLength > WIDTH_PIXEL / 2 || pixLength == 0) {     middle = "\n\t\t" + middle; } tmp = setLocation(192); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; tmp = getGbk(middle); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; tmp = setLocation(getOffset(right)); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); iNum += tmp.length; tmp = getGbk(right); System.arraycopy(tmp, 0, byteBuffer, iNum, tmp.length); print(byteBuffer);

    }

    public void printDashLine() throws IOException {
    printText("--------------------------------");
    }

    public void printBitmap(Bitmap bmp) throws IOException {
    bmp = compressPic(bmp);
    byte[] bmpByteArray = draw2PxPoint(bmp);
    printRawBytes(bmpByteArray);
    }

    /*************************************************************************

    • 假设一个360*360的图片,分辨率设为24, 共分15行打印 每一行,是一个 360 * 24 的点阵,y轴有24个点,存储在3个byte里面。

    • 即每个byte存储8个像素点信息。因为只有黑白两色,所以对应为1的位是黑色,对应为0的位是白色
      **************************************************************************/
      private byte[] draw2PxPoint(Bitmap bmp) {
      //先设置一个足够大的size,最后在用数组拷贝复制到一个精确大小的byte数组中
      int size = bmp.getWidth() * bmp.getHeight() / 8 + 1000;
      byte[] tmp = new byte[size];
      int k = 0;
      // 设置行距为0
      tmp[k++] = 0x1B;
      tmp[k++] = 0x33;
      tmp[k++] = 0x00;
      // 居中打印
      tmp[k++] = 0x1B;
      tmp[k++] = 0x61;
      tmp[k++] = 1;
      for (int j = 0; j < bmp.getHeight() / 24f; j++) {
      tmp[k++] = 0x1B;
      tmp[k++] = 0x2A;// 0x1B 2A 表示图片打印指令
      tmp[k++] = 33; // m=33时,选择24点密度打印
      tmp[k++] = (byte) (bmp.getWidth() % 256); // nL
      tmp[k++] = (byte) (bmp.getWidth() / 256); // nH
      for (int i = 0; i < bmp.getWidth(); i++) {
      for (int m = 0; m < 3; m++) {
      for (int n = 0; n < 8; n++) {
      byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);
      tmp[k] += tmp[k] + b;
      }
      k++;
      }
      }
      tmp[k++] = 10;// 换行
      }
      // 恢复默认行距
      tmp[k++] = 0x1B;
      tmp[k++] = 0x32;

      byte[] result = new byte[k];
      System.arraycopy(tmp, 0, result, 0, k);
      return result;
      }

    /**

    • 图片二值化,黑色是1,白色是0
    • @param x 横坐标
    • @param y 纵坐标
    • @param bit 位图
    • @return
      */
      private byte px2Byte(int x, int y, Bitmap bit) {
      if (x < bit.getWidth() && y < bit.getHeight()) {
      byte b;
      int pixel = bit.getPixel(x, y);
      int red = (pixel & 0x00ff0000) >> 16; // 取高两位
      int green = (pixel & 0x0000ff00) >> 8; // 取中两位
      int blue = pixel & 0x000000ff; // 取低两位
      int gray = RGB2Gray(red, green, blue);
      if (gray < 128) {
      b = 1;
      } else {
      b = 0;
      }
      return b;
      }
      return 0;
      }

    /**

    • 图片灰度的转化
      */
      private int RGB2Gray(int r, int g, int b) {
      int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); // 灰度转化公式
      return gray;
      }

    /**

    • 对图片进行压缩(去除透明度)
    • @param bitmapOrg
      */
      private Bitmap compressPic(Bitmap bitmapOrg) {
      // 获取这个图片的宽和高
      int width = bitmapOrg.getWidth();
      int height = bitmapOrg.getHeight();
      // 定义预转换成的图片的宽度和高度
      int newWidth = IMAGE_SIZE;
      int newHeight = IMAGE_SIZE;
      Bitmap targetBmp = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
      Canvas targetCanvas = new Canvas(targetBmp);
      targetCanvas.drawColor(0xffffffff);
      targetCanvas.drawBitmap(bitmapOrg, new Rect(0, 0, width, height), new Rect(0, 0, newWidth, newHeight), null);
      return targetBmp;
      }

    public static void printTest(BluetoothSocket bluetoothSocket, Bitmap bitmap) {

     try {     PrintUtil pUtil = new PrintUtil(bluetoothSocket.getOutputStream(), "GBK");     // 店铺名 居中 放大     pUtil.printAlignment(1);     pUtil.printLargeText("广州德胜");     pUtil.printLine();     pUtil.printAlignment(0);     pUtil.printLine();     pUtil.printTwoColumn("时间:", myTime);     pUtil.printLine();     pUtil.printTwoColumn("订单号:", System.currentTimeMillis() + "");     pUtil.printLine();     pUtil.printTwoColumn("付款人:", "VitaminChen");     pUtil.printLine();     // 分隔线     pUtil.printDashLine();     pUtil.printLine();     //打印商品列表     pUtil.printText("商品");     pUtil.printTabSpace(2);     pUtil.printText("数量");     pUtil.printTabSpace(1);     pUtil.printText("    单价");     pUtil.printLine();     pUtil.printThreeColumn("iphone6", "1", "4999.00");     pUtil.printThreeColumn("测试测试", "1", "4999.00");     pUtil.printDashLine();     pUtil.printLine();     pUtil.printTwoColumn("订单金额:", "9998.00");     pUtil.printLine();     pUtil.printTwoColumn("实收金额:", "10000.00");     pUtil.printLine();     pUtil.printTwoColumn("找零:", "2.00");     pUtil.printLine();     pUtil.printDashLine();     //打印图片    // pUtil.printBitmap(bitmap);     pUtil.printLine(4); } catch (IOException e) { }

    }

    private void getTime() {
    final Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH) + 1;
    int day = c.get(Calendar.DATE);
    int hour = c.get(Calendar.HOUR);
    int minute = c.get(Calendar.MINUTE);
    if (month > 9) {
    myTime = year + “-” + month + “-” + day;
    } else {
    if (day > 9) {
    myTime = year + “-” + “0” + month + “-” + day;
    } else {
    myTime = year + “-” + “0” + month + “-” + “0” + day;
    }

     }

    }
    }

第二步 :还有一个检测蓝牙是否连接的工具类

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

public class BluetoothUtil {

/** * 蓝牙是否打开 */public static boolean isBluetoothOn() {BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (mBluetoothAdapter != null)// 蓝牙已打开if (mBluetoothAdapter.isEnabled())return true;return false;}/** * 获取所有已配对的设备 */public static List getPairedDevices() {List deviceList = new ArrayList<>();Set pairedDevices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();if (pairedDevices.size() > 0) {for (BluetoothDevice device : pairedDevices) {deviceList.add(device);}}return deviceList;}/** * 获取所有已配对的打印类设备 */public static List getPairedPrinterDevices() {return getSpecificDevice(BluetoothClass.Device.Major.IMAGING);}/** * 从已配对设配中,删选出某一特定类型的设备展示 * @param deviceClass * @return */public static List getSpecificDevice(int deviceClass){List devices = BluetoothUtil.getPairedDevices();List printerDevices = new ArrayList<>();for (BluetoothDevice device : devices) {BluetoothClass klass = device.getBluetoothClass();// 关于蓝牙设备分类参考 http://stackoverflow.com/q/23273355/4242112if (klass.getMajorDeviceClass() == deviceClass)printerDevices.add(device);}return printerDevices;}/** * 弹出系统对话框,请求打开蓝牙 */public static void openBluetooth(Activity activity) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);activity.startActivityForResult(enableBtIntent, 666);}public static BluetoothSocket connectDevice(BluetoothDevice device) {BluetoothSocket socket = null;try {socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));socket.connect();} catch (IOException e) {try {socket.close();} catch (IOException closeException) {return null;}return null;}return socket;}

}

第三步:创建一个基类
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.will.bluetoothprinterdemo.utils.BluetoothUtil;

import java.io.IOException;

public abstract class BasePrintActivity extends AppCompatActivity {

String tag = getClass().getSimpleName();private BluetoothSocket mSocket;private BluetoothStateReceiver mBluetoothStateReceiver;private AsyncTask mConnectTask;private ProgressDialog mProgressDialog;/** * 蓝牙连接成功后回调,该方法在子线程执行,可执行耗时操作 */public abstract void onConnected(BluetoothSocket socket, int taskType);/** * 蓝牙状态发生变化时回调 */public void onBluetoothStateChanged(Intent intent) {}@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    initReceiver();}@Overrideprotected void onStop() {    cancelConnectTask();    closeSocket();    super.onStop();}protected void closeSocket() {    if (mSocket != null) {        try {            mSocket.close();        } catch (IOException e) {            mSocket = null;            e.printStackTrace();        }    }}protected void cancelConnectTask() {    if (mConnectTask != null) {        mConnectTask.cancel(true);        mConnectTask = null;    }}@Overrideprotected void onDestroy() {    unregisterReceiver(mBluetoothStateReceiver);    super.onDestroy();}private void initReceiver() {    mBluetoothStateReceiver = new BluetoothStateReceiver();    IntentFilter filter = new IntentFilter();    filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);    registerReceiver(mBluetoothStateReceiver, filter);}/** * 检查蓝牙状态,如果已打开,则查找已绑定设备 * * @return */public boolean checkBluetoothState() {    if (BluetoothUtil.isBluetoothOn()) {        return true;    } else {        BluetoothUtil.openBluetooth(this);        return false;    }}public void connectDevice(BluetoothDevice device, int taskType) {    if (checkBluetoothState() && device != null) {        mConnectTask = new ConnectBluetoothTask(taskType).execute(device);    }}class ConnectBluetoothTask extends AsyncTask {    int mTaskType;    public ConnectBluetoothTask(int taskType) {        this.mTaskType = taskType;    }    @Override    protected void onPreExecute() {        showProgressDialog("请稍候...");        super.onPreExecute();    }    @Override    protected BluetoothSocket doInBackground(BluetoothDevice... params) {        if(mSocket != null){            try {                mSocket.close();            } catch (IOException e) {                e.printStackTrace();            }        }        mSocket = BluetoothUtil.connectDevice(params[0]);;        onConnected(mSocket, mTaskType);        return mSocket;    }    @Override    protected void onPostExecute(BluetoothSocket socket) {        mProgressDialog.dismiss();        if (socket == null || !socket.isConnected()) {            toast("连接打印机失败");        } else {            toast("成功!");        }        super.onPostExecute(socket);    }}protected void showProgressDialog(String message) {    if (mProgressDialog == null) {        mProgressDialog = new ProgressDialog(this);        mProgressDialog.setCanceledOnTouchOutside(false);        mProgressDialog.setCancelable(false);    }    mProgressDialog.setMessage(message);    if (!mProgressDialog.isShowing()) {        mProgressDialog.show();    }}protected void toast(String message) {    Toast.makeText(this, message, Toast.LENGTH_SHORT).show();}/** * 监听蓝牙状态变化的系统广播 */class BluetoothStateReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);        switch (state) {            case BluetoothAdapter.STATE_TURNING_ON:                toast("蓝牙已开启");                break;            case BluetoothAdapter.STATE_TURNING_OFF:                toast("蓝牙已关闭");                break;        }        onBluetoothStateChanged(intent);    }}

}

第四步:主界面代码

package com.will.bluetoothprinterdemo.ui;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.will.bluetoothprinterdemo.R;
import com.will.bluetoothprinterdemo.utils.BluetoothUtil;
import com.will.bluetoothprinterdemo.utils.PrintUtil;

import java.util.List;

public class PrinterSettingActivity extends BasePrintActivity implements View.OnClickListener{

ListView mLvPairedDevices;Button mBtnSetting;Button mBtnTest;Button mBtnPrint;DeviceListAdapter mAdapter;int mSelectedPosition = -1;final static int TASK_TYPE_CONNECT = 1;final static int TASK_TYPE_PRINT = 2;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_printer_setting);    initViews();}@Overrideprotected void onResume() {    super.onResume();    fillAdapter();}private void initViews() {    mLvPairedDevices = (ListView) findViewById(R.id.lv_paired_devices);    mBtnSetting = (Button) findViewById(R.id.btn_goto_setting);    mBtnTest = (Button) findViewById(R.id.btn_test_conntect);    mBtnPrint = (Button) findViewById(R.id.btn_print);    mLvPairedDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {        @Override        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {            mSelectedPosition = position;            mAdapter.notifyDataSetChanged();        }    });    mBtnSetting.setOnClickListener(this);    mBtnTest.setOnClickListener(this);    mBtnPrint.setOnClickListener(this);    mAdapter = new DeviceListAdapter(this);    mLvPairedDevices.setAdapter(mAdapter);}/** * 从所有已配对设备中找出打印设备并显示 */private void fillAdapter() {    //推荐使用 BluetoothUtil.getPairedPrinterDevices()    List printerDevices = BluetoothUtil.getPairedDevices();    mAdapter.clear();    mAdapter.addAll(printerDevices);    refreshButtonText(printerDevices);}private void refreshButtonText(List printerDevices) {    if (printerDevices.size() > 0) {        mBtnSetting.setText("配对更多设备");    } else {        mBtnSetting.setText("还未配对打印机,去设置");    }}@Overridepublic void onClick(View v) {    switch (v.getId()){        case R.id.btn_goto_setting:            startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));            break;        case R.id.btn_test_conntect:            connectDevice(TASK_TYPE_CONNECT);            break;        case R.id.btn_print:            connectDevice(TASK_TYPE_PRINT);            break;    }}private void connectDevice(int taskType){    if(mSelectedPosition >= 0){        BluetoothDevice device = mAdapter.getItem(mSelectedPosition);        if(device!= null)            super.connectDevice(device, taskType);    }else{        Toast.makeText(this, "还未选择打印设备", Toast.LENGTH_SHORT).show();    }}@Overridepublic void onConnected(BluetoothSocket socket, int taskType) {    switch (taskType){        case TASK_TYPE_PRINT:            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);            PrintUtil.printTest(socket, bitmap);            break;    }}class DeviceListAdapter extends ArrayAdapter {    public DeviceListAdapter(Context context) {        super(context, 0);    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        BluetoothDevice device = getItem(position);        if (convertView == null) {            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_bluetooth_device, parent, false);        }        TextView tvDeviceName = (TextView) convertView.findViewById(R.id.tv_device_name);        CheckBox cbDevice = (CheckBox) convertView.findViewById(R.id.cb_device);        tvDeviceName.setText(device.getName());        cbDevice.setChecked(position == mSelectedPosition);        return convertView;    }}

}

第五步:主界面布局
activity_printer_setting.xml

<?xml version="1.0" encoding="utf-8"?>

布局二:

<?xml version="1.0" encoding="utf-8"?>

更多相关文章

  1. 《 Android物联网开发从入门到实战》国内第一本开发书籍!
  2. 《 Android物联网开发从入门到实战》国内第一本开发书籍!
  3. Android(安卓)热敏打印机打印二维码
  4. Android(安卓)蓝牙开发基本流程
  5. Android(安卓)C++层打印调用栈
  6. Android(安卓)蓝牙开发浅析
  7. android 简单实用的Log打印类封装,助你快速定位问题
  8. Android(安卓)SDK自带教程之BluetoothChat
  9. Android(安卓)在屏幕上打印LOG

随机推荐

  1. mac配置android环境(android studio)
  2. Android中XML文件的序列化生成与解析
  3. Android Edittext输入框点击空白处,软键盘
  4. android 监听来电
  5. android中获取IP的方法
  6. Android应用程序 启动画面
  7. Dalvik虚拟机启动全程解析
  8. Android使用MediaStore.ACTION_IMAGE_CAP
  9. android studio集成butterknife
  10. Android(安卓)library projects cannot b