【问题标题】:Use a handheld bluetooth printer with android使用带有 android 的手持式蓝牙打印机
【发布时间】:2011-12-25 08:57:21
【问题描述】:

我有一台蓝牙手持打印机,我可以使用 Mac 上的 SPP 连接(使用 Coolterm)与之通信。 当我尝试在 Android 上做同样的事情(使用平台 7)时,我遇到了多个问题:

  • 打印机似乎不支持/不需要 PIN 验证。从 OSX 连接时,我只是选择了“不使用 pin”选项,然后它就配对了。在 Android 中,当我使用 device.createRfcommSocketToServiceRecord() 时,它总是最终要求我提供 PIN/Key(我没有/不需要)。 我使用反射技巧解决了这个问题:

    Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
    BluetoothSocket connection = (BluetoothSocket) m.invoke(device, 1);
    

    我不确定这是否真的有效,但打印机上闪烁的 LED 停止闪烁,这让我相信它确实有效。

  • 一旦有了套接字,我就尝试使用以下方法将字节数据写入流:

    byte[] buffer = new byte[3];
    buffer[0] = (byte) 0x8A;
    buffer[1] = (byte) 0xC1;
    buffer[2] = (byte) 0x04;
    outStream.write(buffer);
    int response = inStream.read();
    mySocket.close();
    

    在 OSX 上从 Coolterm 发送相同的三字节序列会从打印机打印测试页。但是,这似乎使线程在 Android 上挂起(读取)。

这里有什么我遗漏的吗?

编辑:这似乎只在我将频道设置为 1 时才有效。所以这意味着我在这里做一些事情。

【问题讨论】:

  • 您使用的是 SPP UUID 吗? (private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");) - 我想你很可能是,如果你不接受,打印机可能不会接受连接,但我想我还是要确定一下。
  • createInsecureRfcommSocket 方法不接受 UUID 作为参数,只接受一个通道。由于我没有 PIN,因此无法创建安全通道。
  • 您是否尝试过使其与采用 UUID 的公共 API 一起工作? developer.android.com/reference/android/bluetooth/…我知道它只是在更高版本的android sdk中,但值得尝试看看它是否可以工作

标签: android printing bluetooth serial-port


【解决方案1】:

@Trevor Page 我认为是在正确的道路上。这是我用来连接基本邮票微控制器的谷歌示例。

/* * 版权所有 (C) 2009 Android 开源项目 * * 根据 Apache 许可证 2.0 版(“许可证”)获得许可; * 除非遵守许可,否则您不得使用此文件。 * 您可以在以下网址获取许可证的副本 * * http://www.apache.org/licenses/LICENSE-2.0 * * 除非适用法律要求或书面同意,否则软件 *根据许可分发是在“原样”基础上分发的, * 不提供任何明示或暗示的保证或条件。 * 请参阅许可证以了解特定语言的管理权限和 * 许可证下的限制。 */ 包 com.your_package; 导入 java.io.IOException; 导入 java.io.InputStream; 导入 java.io.OutputStream; 导入 java.util.UUID; 导入 android.bluetooth.BluetoothAdapter; 导入 android.bluetooth.BluetoothDevice; 导入 android.bluetooth.BluetoothServerSocket; 导入 android.bluetooth.BluetoothSocket; 导入android.content.Context; 导入android.os.Bundle; 导入android.os.Handler; 导入android.os.Message; 导入android.util.Log; /** * 这个类完成了设置和管理蓝牙的所有工作 *与其他设备的连接。它有一个线程来监听 * 传入连接,用于连接设备的线程,以及 * 连接时执行数据传输的线程。 */ 公共类蓝牙服务 { // 调试 私有静态最终字符串 TAG = "BluetoothService_BoeBot"; 私有静态最终布尔值 D = true; // 创建服务器套接字时 SDP 记录的名称 private static final String NAME_SECURE = "BluetoothSecure"; private static final String NAME_INSECURE = "BluetoothInsecure"; // 此应用程序的唯一 UUID 私有静态最终 UUID MY_UUID_SECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); 私有静态最终 UUID MY_UUID_INSECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // 成员字段 私有最终蓝牙适配器 mAdapter; 私有最终处理程序 mHandler; 私有AcceptThread mSecureAcceptThread; 私有AcceptThread mInsecureAcceptThread; 私有连接线程 mConnectThread; 私有连接线程 mConnectedThread; 私有int mState; // 表示当前连接状态的常量 公共静态最终 int STATE_NONE = 0; // 我们什么都不做 公共静态最终 int STATE_LISTEN = 1; // 现在监听传入的连接 公共静态最终 int STATE_CONNECTING = 2; // 现在开始一个传出连接 公共静态最终 int STATE_CONNECTED = 3; // 现在连接到远程设备 /** * 构造函数。准备一个新的 BluetoothChat 会话。 * @param context UI 活动上下文 * @param handler 将消息发送回 UI Activity 的 Handler */ 公共蓝牙服务(上下文上下文,处理程序处理程序) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = 处理程序; } /** * 设置聊天连接的当前状态 * @param state 定义当前连接状态的整数 */ 私有同步无效 setState(int state) { 如果 (D) Log.d(TAG, "setState() " + mState + " -> " + state); mState = 状态; // 将新状态赋予 Handler,以便 UI Activity 可以更新 mHandler.obtainMessage(BoeBot.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } /** * 返回当前连接状态。 */ 公共同步 int getState() { 返回 mState; } /** * 启动聊天服务。具体启动AcceptThread开始一个 * 监听(服务器)模式下的会话。活动调用 onResume() */ 公共同步无效开始() { 如果 (D) Log.d(TAG, "开始"); // 取消任何试图建立连接的线程 如果(mConnectThread!= null) { mConnectThread.cancel(); mConnectThread = null; } // 取消当前运行连接的任何线程 如果(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } setState(STATE_LISTEN); // 启动线程以侦听 BluetoothServerSocket 如果(mSecureAcceptThread == null) { mSecureAcceptThread = new AcceptThread(true); mSecureAcceptThread.start(); } 如果(mInsecureAcceptThread == null) { mInsecureAcceptThread = new AcceptThread(false); mInsecureAcceptThread.start(); } } /** * 启动 ConnectThread 以启动与远程设备的连接。 * @param device 要连接的蓝牙设备 * @param secure 套接字安全类型 - Secure (true) , Insecure (false) */ 公共同步无效连接(蓝牙设备设备,布尔安全) { 如果 (D) Log.d(TAG, "连接到:" + 设备); // 取消任何试图建立连接的线程 如果(mState == STATE_CONNECTING) { 如果(mConnectThread!= null) { mConnectThread.cancel(); mConnectThread = null; } } // 取消当前运行连接的任何线程 如果(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } 尝试 { // 启动线程以连接给定的设备 mConnectThread = new ConnectThread(设备,安全); mConnectThread.start(); setState(STATE_CONNECTING); }catch(异常 e) { } } /** * 启动 ConnectedThread 以开始管理蓝牙连接 * @param socket 建立连接的蓝牙套接字 * @param device 已连接的蓝牙设备 */ 公共同步无效连接(蓝牙套接字套接字,蓝牙设备设备,最终字符串套接字类型) { 如果 (D) Log.d(TAG, "已连接, 套接字类型:" + socketType); // 取消完成连接的线程 如果(mConnectThread!= null) { mConnectThread.cancel(); mConnectThread = null; } // 取消当前运行连接的任何线程 如果(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // 取消接受线程,因为我们只想连接一个设备 如果(mSecureAcceptThread != null) { mSecureAcceptThread.cancel(); mSecureAcceptThread = null; } 如果(mInsecureAcceptThread != null) { mInsecureAcceptThread.cancel(); mInsecureAcceptThread = null; } // 启动线程来管理连接并执行传输 mConnectedThread = new ConnectedThread(socket, socketType); mConnectedThread.start(); // 将连接设备的名称发送回 UI Activity 消息消息 = mHandler.obtainMessage(BoeBot.MESSAGE_DEVICE_NAME); 捆绑捆绑 = 新捆绑(); bundle.putString(BoeBot.DEVICE_NAME, device.getName()); msg.setData(捆绑); mHandler.sendMessage(msg); setState(STATE_CONNECTED); } /** * 停止所有线程 */ 公共同步无效停止() { 如果 (D) Log.d(TAG, "停止"); 如果(mConnectThread!= null) { mConnectThread.cancel(); mConnectThread = null; } 如果(mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } 如果(mSecureAcceptThread != null) { mSecureAcceptThread.cancel(); mSecureAcceptThread = null; } 如果(mInsecureAcceptThread != null) { mInsecureAcceptThread.cancel(); mInsecureAcceptThread = null; } setState(STATE_NONE); } /** * 以非同步方式写入ConnectedThread * @param out 要写入的字节数 * @see ConnectedThread#write(byte[]) */ 公共无效写入(字节[]输出) { // 创建临时对象 连接线程 r; //同步一个ConnectedThread的副本 同步(这个) { 如果(mState!= STATE_CONNECTED) 返回; r = mConnectedThread; } // 执行非同步写入 r.write(out); } /** * 表示连接尝试失败并通知UI Activity。 */ 私人无效连接失败() { // 向Activity发送失败消息 消息消息 = mHandler.obtainMessage(BoeBot.MESSAGE_TOAST); 捆绑捆绑 = 新捆绑(); bundle.putString(BoeBot.TOAST, "无法连接设备"); msg.setData(捆绑); mHandler.sendMessage(msg); // 重新启动服务以重新启动监听模式 BluetoothService.this.start(); } /** * 表示连接丢失并通知UI Activity。 */ 私人无效连接丢失() { // 向Activity发送失败消息 消息消息 = mHandler.obtainMessage(BoeBot.MESSAGE_TOAST); 捆绑捆绑 = 新捆绑(); bundle.putString(BoeBot.TOAST, "设备连接丢失"); msg.setData(捆绑); mHandler.sendMessage(msg); // 重新启动服务以重新启动监听模式 BluetoothService.this.start(); } /** * 此线程在侦听传入连接时运行。它的行为 * 像服务器端客户端。它一直运行直到接受连接 *(或直到取消)。 */ 私有类 AcceptThread 扩展 Thread { // 本地服务器套接字 私有最终 BluetoothServerSocket mmServerSocket; 私有字符串 mSocketType; 公共AcceptThread(布尔安全) { BluetoothServerSocket tmp = null; mSocketType = 安全? “安全”:“不安全”; // 创建一个新的监听服务器套接字 尝试 { 如果(安全) { tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, MY_UUID_SECURE); } 别的 { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord( NAME_INSECURE,MY_UUID_INSECURE); } } 捕捉(IOException e) { Log.e(TAG, "套接字类型:" + mSocketType + "listen() 失败", e); } mmServerSocket = tmp; } @Override 公共无效运行() { 如果 (D) { Log.d(TAG, "套接字类型:" + mSocketType + "BEGIN mAcceptThread" + this); } setName("AcceptThread" + mSocketType); BluetoothSocket 套接字 = null; // 如果我们没有连接,则监听服务器套接字 而(mState!= STATE_CONNECTED) { 尝试 { // 这是一个阻塞调用,只会返回一个 // 连接成功或异常 套接字 = mmServerSocket.accept(); } 捕捉(IOException e) { Log.e(TAG, "套接字类型:" + mSocketType + "accept() 失败", e); 休息; } // 如果连接被接受 如果(套接字!= null) { 同步(BluetoothService.this) { 开关(mState) { 案例STATE_LISTEN: 案例状态连接: // 情况正常。启动连接的线程。 已连接(套接字,socket.getRemoteDevice(),mSocketType); 休息; 案例状态_无: 案例STATE_CONNECTED: // 未准备好或已连接。终止新套接字。 尝试 { socket.close(); } 捕捉(IOException e) { Log.e(TAG, "无法关闭不需要的套接字", e); } 休息; } } } } 如果 (D) { Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType); } } 公共无效取消() { 如果 (D) { Log.d(TAG, "Socket Type" + mSocketType + "cancel" + this); } 尝试 { mmServerSocket.close(); } 捕捉(IOException e) { Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e); } } } /** * 该线程在尝试建立传出连接时运行 * 带设备。它直接穿过;连接要么 * 成功或失败。 */ 私有类 ConnectThread 扩展 Thread { 私有最终蓝牙套接字 mmSocket; 私有最终蓝牙设备 mmDevice; 私有字符串 mSocketType; 公共 ConnectThread(蓝牙设备设备,布尔安全) { mmDevice = 设备; 蓝牙套接字 tmp = null; mSocketType = 安全? “安全”:“不安全”; // 获取一个 BluetoothSocket 用于与 // 给定蓝牙设备 尝试 { 如果(安全) { tmp = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE); } 别的 { tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE); } } 捕捉(IOException e) { Log.e(TAG, "套接字类型:" + mSocketType + "create() failed", e); } mmSocket = tmp; } @Override 公共无效运行() { Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); setName("ConnectThread" + mSocketType); // 始终取消发现,因为它会减慢连接速度 mAdapter.cancelDiscovery(); // 与蓝牙套接字建立连接 尝试 { // 这是一个阻塞调用,只会返回一个 // 连接成功或异常 mmSocket.connect(); } 捕捉(IOException e) { // 关闭套接字 尝试 { mmSocket.close(); } 捕捉(IOException e2) { Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2); } 连接失败(); 返回; } // 重置 ConnectThread 因为我们已经完成了 同步(BluetoothService.this) { mConnectThread = null; } 尝试 { // 启动连接的线程 已连接(mmSocket,mmDevice,mSocketType); }catch(异常 e) { Log.e(TAG, "", e); } } 公共无效取消() { 尝试 { mmSocket.close(); } 捕捉(IOException e) { Log.e(TAG, "close() of connect " + mSocketType + "socket failed", e); } } } /** * 此线程在与远程设备连接期间运行。 *它处理所有传入和传出的传输。 */ 私有类 ConnectedThread 扩展 Thread { 私有最终蓝牙套接字 mmSocket; 私有最终 InputStream mmInStream; 私有最终输出流 mmOutStream; 公共连接线程(蓝牙套接字套接字,字符串套接字类型) { Log.d(TAG, "创建 ConnectedThread:" + socketType); mmSocket = 插座; 输入流 tmpIn = null; 输出流 tmpOut = null; // 获取 BluetoothSocket 输入和输出流 尝试 { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } 捕捉(IOException e) { Log.e(TAG, "临时套接字未创建", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } @Override 公共无效运行() { Log.i(TAG, "开始 mConnectedThread"); 字节[]缓冲区=新字节[1024]; 整数字节; // 连接时继续监听 InputStream 而(真) { 尝试 { // 从 InputStream 中读取 字节= mmInStream.read(缓冲区); // 将获取的字节发送到 UI Activity mHandler.obtainMessage(BoeBot.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); } 捕捉(IOException e) { Log.e(TAG, "断开连接", e); 连接丢失(); 休息; } } } /** * 写入连接的 OutStream。 * @param buffer 要写入的字节数 */ 公共无效写入(字节[]缓冲区) { 尝试 { mmOutStream.write(缓冲区); // 将发送的消息分享回 UI Activity mHandler.obtainMessage(BoeBot.MESSAGE_WRITE, -1, -1, 缓冲区).sendToTarget(); } 捕捉(IOException e) { Log.e(TAG, "写入异常", e); } } 公共无效取消() { 尝试 { mmSocket.close(); } 捕捉(IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } }

测试它是否有效。

BluetoothService mService = new BluetoothService(this, mHandler);
mService.write(Bytes);

【讨论】:

    【解决方案2】:

    【讨论】:

    • 他想通过蓝牙连接,而不是办公室或家里的电脑和打印机。
    • 它是一款基于蓝牙的热敏打印机,我在这里专门讨论。谷歌云打印可能适合通用解决方案。
    猜你喜欢
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    相关资源
    最近更新 更多