Bluetooth Printer之文本打印

一、前言

       最近做一个项目,里面要求用到Bluetooth Printer (蓝牙打印机)对账单信息进行打印,做项目的过程跳了很多的坑,本文在此做个小结,以起到抛砖引玉的作用。

Bluetooth Printer 和手机连接用到了蓝牙,其中主要用到下面几个类:BluetoothDevice BluetoothAdapter、Bluetooth Socket

1.BluetoothDevice

    这是远程蓝牙设备的bean类,继承了Parcelable接口,远程蓝牙设备的属性都在这个类中,包括名称、地址、类和连接状态等信息;最主要的方法有

(1)public String getAddress () 返回该蓝牙设备的硬件地址;

(2)public String getName () 获取远程设备的蓝牙昵称

(3)public int getBondState ()获取远程设备的连接状态;

 详情查看:BluetoothDevice

2.BluetoothAdapter

      这个是一个非常重要的类,可以让用户操作蓝牙的基本任务,例如蓝牙的搜索、蓝牙设备的匹配、蓝牙设备的连接(要通过它创建一个BluetoothSocket实现蓝牙的连接),该对象是通过调用getDefaultAdapter()这一静态方法获取的,它有几个常用的常量:

(1)String      ACTION_DISCOVERY_FINISHED 广播事件:本地蓝牙适配器已经完成设备的搜寻过程。

(2) String      ACTION_DISCOVERY_STARTED 广播事件:本地蓝牙适配器已经开始对远程设备的搜寻过程

(3)String      ACTION_LOCAL_NAME_CHANGED   广播活动:本地蓝牙适配器已经更改了它的蓝牙名称

(4)String      ACTION_REQUEST_DISCOVERABLE  

Activity活动:显示一个请求被搜寻模式的系统活动。如果蓝牙模块当前未打开,该活动也将请求用户打开蓝牙模块;

(5)String      ACTION_REQUEST_ENABLE  Activity活动:显示一个允许用户打开蓝牙模块的系统活动

常见的方法:

(1)public boolean isEnabled ()

如果蓝牙正处于打开状态并可用,则返回真值

(2)public boolean startDiscovery () 

     开始对远程设备进行查找的进程它通常牵涉到一个大概需时12秒的查询扫描过程,紧跟着是一个对每个获取到自身蓝牙名称的新设备的页面扫描这是一个异步调用方法:该方法将马上获得返回值,

这是一个异步调用方法:该方法将马上获得返回值,这是一个异步调用方法:该方法将马上获得返回值,这是一个异步调用方法:该方法将马上获得返回值,注册ACTION_DISCOVERY_STARTED and ACTION_DISCOVERY_FINISHED意图准确地确定该探索是处于开始阶段或者完成阶段。注册ACTION_FOUND以活动远程蓝牙设备 已找到的通知。


(3)public String getName ()  获取远程设备的蓝牙昵称

(4)public String getAddress () 返回本地蓝牙适配器的硬件地址

(5) public boolean cancelDiscovery ()  取消当前的设备发现查找进程取消当前的设备发现查找进程

取消当前的设备发现查找进程

(6)public Set<BluetoothDevice> getBondedDevices ()

返回已经匹配到本地适配器的BluetoothDevice类的对象集合

(7) public BluetoothDevice getRemoteDevice (String address) 为给予的蓝牙硬件地址获取一个BluetoothDevice 对象

更多信息参见:BluetoothAdapter

3.BluetoothSocket

      蓝牙监听接口(BluetoothSocket和BluetoothServerSocket和TCP端监听接口类似(Socket和ServerSocket)类似,服务端使用BluetoothServerSocket类创建一个服务端监听接口,当BluetoothServerSocket接受一个连接时,它创建一个BluetoothSocket对象,对这个连接进行监听;客户端单独使用BluetoothSocket进行连接监听。

     通过BluetoothDevice.createRfcommSocketToServiceRecord()方法获取该类实例,通过调用connect()方法连接远程设备,通过调用public OutputStream getOutputStream ()获取输出流,往服务里面写数据。

更多信息参见:BluetoothSocket

三、主要代码

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
    android:layout_width="match_parent" android:layout_height="match_parent"
    tools:context="com.eric.textbtp.MainActivity">

    <TextView
        android:id="@+id/txt_print"
        android:layout_centerHorizontal="true"
        android:textSize="@dimen/font_big_30"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始打印" />
</RelativeLayout>
device_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/bg_activity"
    android:orientation="vertical">

    <com.eric.textbtp.TitleVIew
        android:id="@+id/title_bluetoothList"
        android:layout_width="match_parent"
        android:layout_height="@dimen/title_bar_height"
        app:titleText = "@string/title_bluetooth_list"/>

    <ListView
        android:id="@+id/paired_devices"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"/>


    <Button
        android:id="@+id/button_scan"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:textSize="@dimen/font_def"
        android:textColor="@color/white_FE"
        android:background="@drawable/bg_ro_btn_shape"
        android:text="@string/button_scan" />

    <Button
        android:id="@+id/button_bace"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="@drawable/bg_ro_btn_shape"
        android:layout_marginBottom="@dimen/spacing_big"
        android:text="@string/button_back" />

</LinearLayout>
蓝牙设备列表:

package com.eric.textbtp;

import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 蓝牙列表
 */
public class BluetoothDeviceList extends Activity {
   private static final String TAG = "DeviceListActivity";
   public static String EXTRA_DEVICE_ADDRESS = "device_address";
   public static String EXTRA_RE_PAIR = "re_pair";
   public static String EXTRA_DEVICE_NAME="device_name";
   /** BluetoothDevice 对象 */
   public static String EXTRA_DEVICE_OBEJECT="device_object";

   // Member fields
   /** 蓝牙适配器*/
   private BluetoothAdapter mBtAdapter;
   /** 蓝牙设备地址名称集合*/
   private ArrayAdapter<String> mPairedDevicesArrayAdapter;
   private ListView pairedListView;
   private Button scanButton;
   private Button backButton;
   /** 标题*/
   private TitleVIew titleVIew;
   /** 搜索进度对话框*/
   private ProgressDialog searchProgressDialog ;
   /** 蓝牙设备集合*/
   private Map<String,BluetoothDevice> bluetoothDevices  = new HashMap<>();
   private Handler  handler = new Handler(){

      @Override
      public void handleMessage(Message msg) {
         super.handleMessage(msg);
         switch (msg.what){
            case 21:
//             mPairedDevicesArrayAdapter.notify();
               break;
         }
      }
   };
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
//    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
      setContentView(R.layout.device_list);
//    setTitle(R.string.select_device);
      setResult(Activity.RESULT_CANCELED);
      initView();
      setWidgetListener();
      initData();
   }

   /**
    * 初始化view
    */
   private void initView() {
      titleVIew = (TitleVIew) findViewById(R.id.title_bluetoothList);
      backButton= (Button) findViewById(R.id.button_bace);
      scanButton = (Button) findViewById(R.id.button_scan);
      pairedListView = (ListView) findViewById(R.id.paired_devices);
      searchProgressDialog = new ProgressDialog(this);

   }

   /**
    * 初始化数据
    * (此处输入方法执行任务.)
    * <h3>Version</h3> 1.0
    * <h3>CreateTime</h3> 2017/6/2/002,16:46
    * <h3>UpdateTime</h3> 2017/6/2/002,16:46
    * <h3>CreateAuthor</h3> Eric
    * <h3>UpdateAuthor</h3>
    * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
    */
   private void initData() {
      mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_item);
      mBtAdapter = BluetoothAdapter.getDefaultAdapter();
      //获取已经匹配的蓝牙设备
      Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
      if (pairedDevices.size() > 0) {
         for (BluetoothDevice device : pairedDevices) {
            mPairedDevicesArrayAdapter.add(device.getName() + " ( "
                  + getResources().getText(R.string.has_paired) + " )"
                  + "\n" + device.getAddress());
            bluetoothDevices.put(device.getAddress(),device);
         }
      }

      searchProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
      searchProgressDialog.setTitle(getString(R.string.dialog_seaching));
      searchProgressDialog.setMessage(getString(R.string.dialog_wait));
      searchProgressDialog.setIndeterminate(true);
      searchProgressDialog.setCancelable(true);
      pairedListView.setAdapter(mPairedDevicesArrayAdapter);

   }

   /**
    * 设置监听
    * (此处输入方法执行任务.)
    * <h3>Version</h3> 1.0
    * <h3>CreateTime</h3> 2017/6/2/002,16:47
    * <h3>UpdateTime</h3> 2017/6/2/002,16:47
    * <h3>CreateAuthor</h3> Eric
    * <h3>UpdateAuthor</h3>
    * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
    */
   private void setWidgetListener() {
      titleVIew.getImg_back().setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View v) {
            finish();
         }
      });
      scanButton.setOnClickListener(new OnClickListener() {
         public void onClick(View v) {
            doDiscovery();
            v.setEnabled(false);
         }
      });

      backButton.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View v) {
            finish();
         }

      });
      pairedListView.setOnItemClickListener(mDeviceClickListener);
      pairedListView.setOnItemLongClickListener(mDeviceLongClickListener);
      pairedListView.setOnCreateContextMenuListener(mCreateContextMenuListener);


      searchProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
         @Override
         public void onDismiss(DialogInterface dialog) {
            if (mBtAdapter != null && mBtAdapter.isDiscovering()) {
               mBtAdapter.cancelDiscovery();
            }
            if (searchProgressDialog != null && searchProgressDialog.isShowing()){
               searchProgressDialog.dismiss();
            }
         }
      });
   }

   @Override
   protected void onStop() {
      if (mBtAdapter != null && mBtAdapter.isDiscovering()) {
         mBtAdapter.cancelDiscovery();
      }
      if (searchProgressDialog != null && searchProgressDialog.isShowing()){
         searchProgressDialog.dismiss();
      }

      this.unregisterReceiver(mReceiver);
      super.onStop();
   }

   @Override
   protected void onResume() {
      IntentFilter filter = new IntentFilter();
      filter.addAction(BluetoothDevice.ACTION_FOUND);
      filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
//    filter.addAction();
      registerReceiver(mReceiver, filter);
      super.onResume();
   }

   /**
    * Start device discover with the BluetoothAdapter
    */
   private void doDiscovery() {
//    Log.d(TAG, "doDiscovery()");
      searchProgressDialog.show();
      // Indicate scanning in the title
//    setProgressBarIndeterminateVisibility(true);
//    setTitle(R.string.scanning);

      // If we're already discovering, stop it
      if (mBtAdapter.isDiscovering()) {
         mBtAdapter.cancelDiscovery();
      }

      mPairedDevicesArrayAdapter.clear();
      bluetoothDevices.clear();
      // Request discover from BluetoothAdapter
      mBtAdapter.startDiscovery();
   }

   /**
    * 返回结果
    * @param address
    * @param re_pair
    * @param name
    */
   private void returnToPreviousActivity(String address, boolean re_pair,String name,BluetoothDevice device) {
      if (mBtAdapter.isDiscovering()) {
         mBtAdapter.cancelDiscovery();
      }
      if (searchProgressDialog != null && searchProgressDialog.isShowing()){
         searchProgressDialog.dismiss();
      }

      Intent intent = new Intent();
      intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
      intent.putExtra(EXTRA_RE_PAIR, re_pair);
      intent.putExtra(EXTRA_DEVICE_NAME, name);

      intent.putExtra(EXTRA_DEVICE_OBEJECT,device);

      setResult(Activity.RESULT_OK, intent);
      finish();
   }

   private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {

         String info = ((TextView) v).getText().toString();
//       System.out.println("message:"+info);
         String address = info.substring(info.length() - 17);
         String name=info.substring(0,info.length() - 17);
//       System.out.println("name:"+name);
         returnToPreviousActivity(address, false,name,bluetoothDevices.get(address));
      }
   };

   private OnItemLongClickListener mDeviceLongClickListener = new OnItemLongClickListener() {
      @Override
      public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
                              int arg2, long arg3) {
         // if return true, don't call method onCreateContextMenu
         return false;
      }
   };

   private OnCreateContextMenuListener mCreateContextMenuListener = new OnCreateContextMenuListener() {
      @Override
      public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo arg2) {
         menu.setHeaderTitle(R.string.select_options);
         String info = ((TextView) (((AdapterContextMenuInfo) arg2).targetView)).getText().toString();
//       System.out.println("message1:"+info);
         // if(((AdapterContextMenuInfo)arg2).position < pairedDeviceNum)
         if (info.contains(" ( " + getResources().getText(R.string.has_paired) + " )")) {
            menu.add(0, 0, 0, R.string.rePaire_connect).setOnMenuItemClickListener(mOnMenuItemClickListener);
            menu.add(0, 1, 1, R.string.connect_paired).setOnMenuItemClickListener(mOnMenuItemClickListener);
         } else {
            menu.add(0, 2, 2, R.string.paire_connect).setOnMenuItemClickListener(mOnMenuItemClickListener);
         }
      }
   };

   private final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener() {
      public boolean onMenuItemClick(MenuItem item) {
         //获取ListView item的内容
         String info = ((TextView) ((AdapterContextMenuInfo) item.getMenuInfo()).targetView).getText().toString();
         String address = info.substring(info.length() - 17);//蓝牙设备地址
         String name=info.substring(0,5);//蓝牙设备名称
         switch (item.getItemId()) {
            case 0:// repair and connect
               returnToPreviousActivity(address, true,name,bluetoothDevices.get(address));
               break;
            case 1:// connect
            case 2:// pair and connect
               returnToPreviousActivity(address, false,name,bluetoothDevices.get(address));
               break;
         }
         return false;
      }
   };

   private final BroadcastReceiver mReceiver = 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);
            String itemName = device.getName() + " ( "
                  + getResources().getText(device.getBondState() == BluetoothDevice.BOND_BONDED ? R.string.has_paired
                  : R.string.not_paired) + " )"
                  + "\n" + device.getAddress();
            mPairedDevicesArrayAdapter.remove(itemName);
            mPairedDevicesArrayAdapter.add(itemName);
            pairedListView.setEnabled(true);
            if (!bluetoothDevices.containsKey(device.getAddress())){
               bluetoothDevices.put(device.getAddress(),device);
            }
//          HandlerUtil.sendMessage(handler,21);
         } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//          setProgressBarIndeterminateVisibility(false);
//          setTitle(R.string.select_device);
            if (searchProgressDialog != null && searchProgressDialog.isShowing()){
               searchProgressDialog.dismiss();
            }
            if (mPairedDevicesArrayAdapter.getCount() == 0) {
               String noDevices = getResources().getText(R.string.none_found).toString();
               mPairedDevicesArrayAdapter.add(noDevices);
               pairedListView.setEnabled(false);
            }
            scanButton.setEnabled(true);
         }
      }
   };

}
工具类:

package com.eric.textbtp;

import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;


import com.eric.textbtp.grant.PermissionsManager;
import com.eric.textbtp.grant.PermissionsResultAction;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;

/**
 * <h3>Description</h3> 蓝牙操作工具类
 * TODO
 * <h3>Author</h3> Eric
 */
public class BluetoothOperationUtil {

    private static BluetoothOperationUtil bluetoothOperationUtil = null;
    /** UUID厂商识别码*/
    private static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//    private boolean isConnection = false;
    /** 蓝牙端口*/
    private static BluetoothSocket bluetoothSocket = null;
    private static OutputStream outputStream = null;
    /**蓝牙适配器 */
    private BluetoothAdapter bluetoothAdapter = null;
    /** 搜索进度对话框*/
    private ProgressDialog searchProgressDialog ;
    /** 连接成功 */
    public static final int SUCCESS = 101;
    /** 连接失败 */
    public static final int FAILED = 102;
    /** 连接关闭 */
    public static final int CLOSED = 103;
    /** 无设备*/
    public static final int NODEVICE = 104;
    /** handler 消息机制 用来处理连接结果*/
    private Handler mHandler;

    final String[] items = { "复位打印机", "标准ASCII字体", "压缩ASCII字体", "字体不放大",
            "宽高加倍", "取消加粗模式", "选择加粗模式", "取消倒置打印", "选择倒置打印", "取消黑白反显", "选择黑白反显",
            "取消顺时针旋转90°", "选择顺时针旋转90°" };
    final byte[][] byteCommands =
            { { 0x1b, 0x40 },// 复位打印机
                    { 0x1b, 0x4d, 0x00 },// 标准ASCII字体
                    { 0x1b, 0x4d, 0x01 },// 压缩ASCII字体
                    { 0x1d, 0x21, 0x00 },// 字体不放大
                    { 0x1d, 0x21, 0x11 },// 宽高加倍
                    { 0x1b, 0x45, 0x00 },// 取消加粗模式
                    { 0x1b, 0x45, 0x01 },// 选择加粗模式
                    { 0x1b, 0x7b, 0x00 },// 取消倒置打印
                    { 0x1b, 0x7b, 0x01 },// 选择倒置打印
                    { 0x1d, 0x42, 0x00 },// 取消黑白反显
                    { 0x1d, 0x42, 0x01 },// 选择黑白反显
                    { 0x1b, 0x56, 0x00 },// 取消顺时针旋转90°
                    { 0x1b, 0x56, 0x01 },// 选择顺时针旋转90°
            };


    /**
     * 构造方法私有化
     */
    private BluetoothOperationUtil() {
    }


    /**
     * 单例模式
     * @return 返回该类实例
     */
    public static synchronized BluetoothOperationUtil getInstance() {
        if (bluetoothOperationUtil == null){
//            synchronized (bluetoothOperationUtil){
//                if (bluetoothOperationUtil == null){
//                }
//            }
            bluetoothOperationUtil = new BluetoothOperationUtil();

        }
        return bluetoothOperationUtil;
    }

    /**
     * 获取蓝牙适配器
     * @return 蓝牙适配器
     */
    public BluetoothAdapter getBluetoothAdapter() {
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        return bluetoothAdapter;
    }

    /**
     * 获取已经配对的蓝牙设备
     */
    public Set<BluetoothDevice> getBondedDevices(){
        if (bluetoothAdapter == null){
            LogUtil.logErrorMessage("BluetoothOperationUtil----------> bluetoothAdapter can not be null and please invoke getBluetoothAdapter() " +
                    "method init bluetoothAdapter object !");
            return null;
        }
        Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
        return pairedDevices;
    }

    /**
     * 开始扫描
     * @param context
     */
    public void startDiscovery (Context context){
        if (bluetoothAdapter == null){
            LogUtil.logErrorMessage("BluetoothOperationUtil----------> bluetoothAdapter can not be null and please invoke getBluetoothAdapter() " +
                    "method init bluetoothAdapter object !");
            return ;
        }
        searchProgressDialog = new ProgressDialog(context);
        searchProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        searchProgressDialog.setTitle("正在搜索");
        searchProgressDialog.setMessage("请稍等...");
        searchProgressDialog.setIndeterminate(true);
        searchProgressDialog.setCancelable(true);
        searchProgressDialog.show();
        if (bluetoothAdapter.isDiscovering()){
            bluetoothAdapter.cancelDiscovery();
        }
        bluetoothAdapter.startDiscovery();
        searchProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
                    bluetoothAdapter.cancelDiscovery();
                }
                if (searchProgressDialog != null && searchProgressDialog.isShowing()){
                    searchProgressDialog.dismiss();
                }
            }
        });

    }

    /**
     * 结束扫描
     */
    public void cancelDiscovery(){
        if (searchProgressDialog != null && searchProgressDialog.isShowing()){
            searchProgressDialog.dismiss();
        }
        if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
        }
    }

    /**
     * 蓝牙连接
     * @param device
     * @return
     * @throws IOException
     */
    public BluetoothSocket connect(BluetoothDevice device) throws IOException {
        bluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
        bluetoothSocket.connect();
        outputStream = bluetoothSocket.getOutputStream();
        return bluetoothSocket;
    }

    /**
     * 蓝牙连接
     * @param device 蓝牙设备
     * @param handler 消息机制 用来处理连接结果
     * @return
     * @throws IOException
     */
    public BluetoothSocket connect(final BluetoothDevice device, final Context context ,Handler handler) {
        mHandler = handler;
        try {
            bluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
            bluetoothSocket.connect();
            outputStream = bluetoothSocket.getOutputStream();
            Message m = handler.obtainMessage();
            m.what = SUCCESS;
            handler.sendMessage(m);
        } catch (IOException e) {
            Message m = handler.obtainMessage();
            m.what = FAILED;
            handler.sendMessage(m);
            LogUtil.logErrorMessage("BluetoothOperationUtil--------Connect()---->" + e.getMessage());
        }

        if (getCurrentVersionCode(context) >= Build.VERSION_CODES.N){
            PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult((Activity) context
                    , new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE}
                    , new PermissionsResultAction() {
                @Override
                public void onGranted() {
                    saveBtConnInfo(context,device.getAddress());
                }

                @Override
                public void onDenied(String permission) {
                    Toast.makeText(context,"请开启权限!",Toast.LENGTH_SHORT).show();
                }
            });
        }else {
            saveBtConnInfo(context,device.getAddress());
        }
        return bluetoothSocket;
    }


    /**
     * 蓝牙重连接
     * @return
     * @throws IOException
     */
    public BluetoothSocket reConnect(final Context context, final BluetoothAdapter adapter, final Handler handler){
        mHandler = handler;
        if (getCurrentVersionCode(context) >= Build.VERSION_CODES.N){
            PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult((Activity) context
                    , new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE}
                    , new PermissionsResultAction() {
                        @Override
                        public void onGranted() {
                            Properties properties =  getBtConnInfo(context);
                            String mDeviceAddress = properties.getProperty("mac");
                            BluetoothDevice device;
                            if (adapter == null){
//                                LogUtil.logErrorMessage("BluetoothOperationUtil------------> adapter can not null !");
//                                return;
                                device = getBluetoothAdapter().getRemoteDevice(mDeviceAddress);
                            }else {
                                device = adapter.getRemoteDevice(mDeviceAddress);
                            }

                            try {
                                bluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
                                bluetoothSocket.connect();
                                outputStream = bluetoothSocket.getOutputStream();
                                Message m = handler.obtainMessage();
                                m.what = SUCCESS;
                                handler.sendMessage(m);
                            } catch (IOException e) {
                                Message m = handler.obtainMessage();
                                m.what = FAILED;
                                handler.sendMessage(m);
//                                e.printStackTrace();
                                LogUtil.logErrorMessage("BluetoothOperationUtil--------reConnect---->" + e.getMessage());
                            }

                        }

                        @Override
                        public void onDenied(String permission) {
                            Toast.makeText(context,"请开启权限!",Toast.LENGTH_SHORT).show();
                        }
                    });
        }else {

            Properties properties =  getBtConnInfo(context);
            String mDeviceAddress = properties.getProperty("mac");
            BluetoothDevice device;

            if (adapter == null){
//                LogUtil.logErrorMessage("BluetoothOperationUtil------------> adapter can not null !");
                device  = getBluetoothAdapter().getRemoteDevice(mDeviceAddress);
            }else {
                device  = adapter.getRemoteDevice(mDeviceAddress);
            }
            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
                bluetoothSocket.connect();
                outputStream = bluetoothSocket.getOutputStream();
                Message m = handler.obtainMessage();
                m.what = SUCCESS;
                handler.sendMessage(m);
            } catch (IOException e) {
                Message m = handler.obtainMessage();
                m.what = FAILED;
                handler.sendMessage(m);
                LogUtil.logErrorMessage("BluetoothOperationUtil--------reConnect---->" + e.getMessage());
            }

        }
        return bluetoothSocket;
    }


    /**
     * (此处输入方法执行任务.)
     * @param context 上下文
     * @param id  byteCommands 对应的下标
     * @return true 设置成功 否则设置失败
     */
    public boolean selectCommand(Context context ,int id){
        if (outputStream == null){
            LogUtil.logErrorMessage("BluetoothOperationUtil--------->outputStream can not be null !");
            return false;
        }else {
            try {
                outputStream.write(byteCommands[id]);
                return true;
            } catch (IOException e) {
                LogUtil.logErrorMessage("BluetoothOperationUtil--------->selectCommand() " + e.getMessage());
//                Toast.makeText(context,"设置指令失败!",Toast.LENGTH_SHORT).show();
                return false;
            }
        }
    }


    /**
     * 打印文本
     * @param text 要打印的文本
     * @param brNum 文本结尾要添加换行的个数
     * @return true 数据发送成功 否则发送失败
     */
    public boolean printText(String text, int brNum){
        if (TextUtils.isEmpty(text)){
            return false;
        }
        if (outputStream == null){
            LogUtil.logErrorMessage("BluetoothOperationUtil--------->outputStream can not be null !");
            return false;
        }else {
            StringBuffer buffer = new StringBuffer(text);
            for (int i = 0; i < brNum; i++) {
                buffer.append("\n");
            }
            byte[] bytes = new byte[0];
            try {
                bytes = buffer.toString().getBytes("gbk");
                outputStream.write(bytes,0,bytes.length);
                outputStream.flush();
                return true;

            } catch (Exception e) {
                LogUtil.logErrorMessage("BluetoothOperationUtil--------->printText() " + e.getMessage());
                try {
                    outputStream.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return false;
            }
        }
    }


    /**
     * 断开连接
     */
    public void disconnect(){
        if (bluetoothSocket != null){
            try {
                bluetoothSocket.close();
                if (outputStream != null){
                    outputStream.close();
                }
                if (mHandler != null){
                    Message message = mHandler.obtainMessage();
                    message.what = CLOSED;
                    mHandler.sendMessage(message);
                }
            } catch (IOException e) {
                LogUtil.logErrorMessage("BluetoothOperationUtil--------->disconnect() " + e.getMessage());
            }
        }
    }


    /** 保存蓝牙设备的详细信息
     * @param context
     * @param mac
     * @return
     */
    public  boolean saveBtConnInfo(Context context, String mac) {
        try {
            //创建文件
            File e = new File(context.getFilesDir(), "btinfo.properties");
            FileOutputStream fos = new FileOutputStream(e);
            //Properties类继承自Hashtable类并且实现了Map接口,
            // 也是使用一种键值对的形式来保存属性集。不过Properties有特殊的地方,就是它的键和值都是字符串类型
            Properties pro = new Properties();
            /* Properties 继承了hasTable,数据结构也是key-value的形式,不过都是String类型的 ,类似map中的put方法。
             * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
             * parallelism with the <tt>getProperty</tt> method. Enforces use of
             * strings for property keys and values. The value returned is the
             * result of the <tt>Hashtable</tt> call to <code>put</code>.
             */
            pro.setProperty("mac", mac);
            /* pro集合的内容存储到 properties中。
             * Writes this property list (key and element pairs) in this
             * <code>Properties</code> table to the output stream in a format suitable
             * for loading into a <code>Properties</code> table using the
             * {@link #load(InputStream) load(InputStream)} method.
             * */
            pro.store(fos, "btinfo.properties");
            fos.close();
            Log.v("utils", "save-success!");
            return true;
        } catch (Exception var5) {
            throw new RuntimeException();
        }
    }

    /** 获取蓝牙设备的详细信息
     * @param context
     * @return
     */
    public static Properties getBtConnInfo(Context context) {
        try {
            File e = new File(context.getFilesDir(), "btinfo.properties");
            FileInputStream fis = new FileInputStream(e);
            Properties pro = new Properties();
            pro.load(fis);
            Log.v("utils", "get-success!");
            fis.close();
            return pro;
        } catch (Exception var4) {
            var4.printStackTrace();
            return null;
        }
    }



    /** 判断蓝牙缓存文件是否存在
     * @param context
     * @return
     */
    public   boolean isBTCacheFileExit(final Context context){
        final boolean[] isExit = new boolean[1];
        if (getCurrentVersionCode(context) >= Build.VERSION_CODES.N){
            PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult((Activity) context,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}
                    , new PermissionsResultAction() {
                        @Override
                        public void onGranted() {
                            File e = new File(context.getFilesDir(), "btinfo.properties");
                            if (e.exists() && e.isFile()){
                                isExit[0] =  true;
                            }else {
                                isExit[0] = false;
                            }
                        }
                        @Override
                        public void onDenied(String permission) {
//                            ToastUtils.showToast("请打开权限继续操作!");
                            Toast.makeText(context,"请开启权限!",Toast.LENGTH_SHORT).show();
                        }
                    });
        }else {
            File e = new File(context.getFilesDir(), "btinfo.properties");
            if (e.exists() && e.isFile()){
                isExit[0] =  true;
            }else {
                isExit[0] = false;
            }
        }
        return isExit[0];
    }


    /**
     * 获取当前版本号

     * @param context 上下文
     * @return 返回当前版本号
     */
    private  int getCurrentVersionCode(Context context) {
        int versionCode = 1;
        // 获取packagemanager的实例
        PackageManager packageManager = context.getPackageManager();
        // getPackageName()是你当前类的包名,0代表是获取版本信息
        PackageInfo packInfo;
        try {
            packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            versionCode = packInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
            versionCode = 1;
        }
        return versionCode;
    }
}
mainActivity:

package com.eric.textbtp;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private TextView txtPrint;
    private TitleVIew titleVIew;
    /** 蓝牙操作工具类*/
    private BluetoothOperationUtil operationUtil;
    private BluetoothAdapter adapter;
    /** true  蓝牙已经连接上 否则没有连接上 */
    private boolean isConnected ;

    /** 连接设备*/
    public static final int CONNECT_DEVICE = 1;
    /** 打开蓝牙设备*/
    public static final int ENABLE_BT = 2;
    /** 蓝牙列表*/
    public static final int BT_LIST = 3;
    /** 消息机制用来处理连接结果 */
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case BluetoothOperationUtil.CLOSED:
                    Toast.makeText(MainActivity.this,"连接关闭!",Toast.LENGTH_SHORT).show();
                    isConnected = false;
                    break;
                case BluetoothOperationUtil.FAILED:
                    isConnected = false;
                    Toast.makeText(MainActivity.this,"连接失败!",Toast.LENGTH_SHORT).show();
                    break;
                case BluetoothOperationUtil.SUCCESS:
                    isConnected = true;
                    Toast.makeText(MainActivity.this,"连接成功!",Toast.LENGTH_SHORT).show();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            PrintUtils.printText(operationUtil,MainActivity.this.getResources());
                        }
                    }).start();
                    break;
            }

            if (connectingProgressDialog != null && connectingProgressDialog.isShowing()){
                connectingProgressDialog.dismiss();
            }
        }
    };
    private BluetoothSocket bluetoothSocket;
    private ProgressDialog connectingProgressDialog;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        setListener();
        initData();
    }

    /**
     * 初始化数据
     */
    private void initData() {
        operationUtil = BluetoothOperationUtil.getInstance();
        //获取蓝牙适配器
        adapter = operationUtil.getBluetoothAdapter();
    }

    /**
     * 设置监听
     */
    private void setListener() {
        txtPrint.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!adapter.isEnabled()){//蓝牙没有打开
                    new AlertDialog.Builder(MainActivity.this).setTitle("提示")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Intent intent  = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                                    MainActivity.this.startActivityForResult(intent,ENABLE_BT);
                                    dialog.dismiss();
                                }
                            }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).setMessage("确定要打开蓝牙设备?").show();
                }else {
                    if (isConnected){
                        new AlertDialog.Builder(MainActivity.this).setTitle("提示")
                                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        new Thread(new Runnable() {
                                            @Override
                                            public void run() {
                                                PrintUtils.printText(operationUtil,MainActivity.this.getResources());
                                            }
                                        }).start();
                                    }
                                }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        }).setMessage("要打印?").show();


                    }else {
                       if (!operationUtil.isBTCacheFileExit(MainActivity.this)){//还未连接过
                           new AlertDialog.Builder(MainActivity.this).setTitle("提示")
                                   .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                       @Override
                                       public void onClick(DialogInterface dialog, int which) {
                                           Intent intent  = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                                           MainActivity.this.startActivityForResult(intent,ENABLE_BT);
                                           dialog.dismiss();
                                       }
                                   }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
                               @Override
                               public void onClick(DialogInterface dialog, int which) {
                                   dialog.dismiss();
                               }
                           }).setMessage("确定要连接蓝牙打印机?").show();
                       }else {//已经成功连接过
                           new AlertDialog.Builder(MainActivity.this).setTitle("提示")
                                   .setPositiveButton("确定连接", new DialogInterface.OnClickListener() {
                                       @Override
                                       public void onClick(DialogInterface dialog, int which) {
                                           new Thread(new Runnable() {
                                               @Override
                                               public void run() {
                                                   operationUtil.reConnect(MainActivity.this,adapter,handler);
                                               }
                                           }).start();
                                           dialog.dismiss();
                                       }
                                   }).setNegativeButton("重新扫描", new DialogInterface.OnClickListener() {
                               @Override
                               public void onClick(DialogInterface dialog, int which) {
                                   Intent intent  = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                                   MainActivity.this.startActivityForResult(intent,ENABLE_BT);
                                   dialog.dismiss();
                               }
                           }).setMessage("要连接上一次的设备?").show();
                       }
                    }
                }

            }
        });
    }

    /**
     * 初始化views
     */
    private void initView() {
        txtPrint = (TextView) findViewById(R.id.txt_print);

        connectingProgressDialog = new ProgressDialog(this);
        connectingProgressDialog.setTitle("正在连接");
        connectingProgressDialog.setMessage("请稍等...");
        connectingProgressDialog.setCanceledOnTouchOutside(false);

    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode){
            case ENABLE_BT:
                if (resultCode == RESULT_OK){
                    Intent intent = new Intent(this,BluetoothDeviceList.class);
                    startActivityForResult(intent,BT_LIST);
                }else {
                    Toast.makeText(this,"蓝牙打开失败!",Toast.LENGTH_SHORT);
                }
                break;
            case BT_LIST:
                if (resultCode == RESULT_OK && data != null){
                    final BluetoothDevice device = data.getParcelableExtra(BluetoothDeviceList.EXTRA_DEVICE_OBEJECT);
                    connectingProgressDialog.show();
                    new Thread(new Runnable() {

                        @Override
                        public void run() {
                            //连接远程设备
                            bluetoothSocket = operationUtil.connect(device,MainActivity.this,handler);
                        }
                    }).start();
                }
                break;
        }
    }


    @Override
    protected void onStop() {
        super.onStop();
        operationUtil.disconnect();
        if (connectingProgressDialog != null && connectingProgressDialog.isShowing()){
            connectingProgressDialog.dismiss();
        }
    }
}
打印工具类:

package com.eric.textbtp;

import android.content.res.Resources;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PrintUtils {
   /**
    * 打印文本
    * @param resources
    */
   public static void printText(BluetoothOperationUtil operationUtil , Resources resources) {
      operationUtil.printText("测试打印文本",1);
      long timeMillis =System.currentTimeMillis();
      SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
      operationUtil.printText(format.format(new Date(timeMillis)),3);
   }
}

项目源码稍后上传。
















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在VB中,可以使用`Printer.PaintPicture`方法来实现打印预览功能。该方法用于将图像绘制在打印机驱动程序的画布上,从而实现打印预览效果。 首先,我们需要将需要打印的图像加载到一个PictureBox控件中,可以使用`PictureBox.Load`方法来实现。然后,在打印预览按钮的点击事件中,可以使用`Printer.PaintPicture`方法将图像绘制在打印机驱动程序的画布上。 示例代码如下: ```vb Private Sub btnPrintPreview_Click(sender As Object, e As EventArgs) Handles btnPrintPreview.Click ' 加载需要打印的图像到PictureBox控件 PictureBox1.Load("C:\Path\to\image.png") ' 设置打印机驱动程序的属性 Printer.CurrentX = 100 Printer.CurrentY = 100 Printer.ScaleMode = vbTwips ' 设置绘图单位为屏幕的1/20个点 Printer.Font.Size = 12 ' 绘制图像到打印机驱动程序的画布上 Printer.PaintPicture(PictureBox1.Image, 0, 0) ' 显示打印预览对话框 Printer.EndDoc ' 结束打印任务,弹出打印预览对话框 End Sub ``` 上述代码中,我们首先使用`PictureBox.Load`方法将需要打印的图像加载到PictureBox1控件中。然后,我们设置了打印机驱动程序的属性,包括当前的位置(CurrentX和CurrentY)和绘图单位(ScaleMode),以及字体大小。接着,我们使用`Printer.PaintPicture`方法将图像绘制在打印机驱动程序的画布上。最后,使用`Printer.EndDoc`方法结束打印任务,并弹出打印预览对话框。 这样,点击打印预览按钮后,会出现打印预览对话框,其中显示了绘制在打印机驱动程序画布上的图像内容,从而实现了打印预览的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值