今天写了份代码,通过使用斑马手持机(TC26)蓝牙的方式连接打印(TSC-30B)出现的问题如下:
通过手持机的前段界面,点击打印,打印机正常出纸,但是纸上没有测试内容,但是控制台提示ok,以下截图


这个是厂家给的打印机指令:


以下是核心代码:
MainActivity
package com.jl.bluetoothprinter_two;
import android.Manifest;
import android.app.AlertDialog;
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.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
// 基础常量
private static final String TAG = "TSC-Printer-API28";
private static final int REQUEST_PERMISSIONS = 100;
private static final int REQUEST_ENABLE_BT = 101;
private static final UUID PRINTER_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// 打印配置(可统一修改)
private static final String LABEL_WIDTH = "60"; // 标签宽度(mm)
private static final String LABEL_HEIGHT = "40"; // 标签高度(mm)
private static final int PRINT_DENSITY = 30; // 打印浓度(0-30,默认10)
private static final Charset PRINT_CHARSET = Charset.forName("GBK"); // 打印编码
// 蓝牙核心组件
private BluetoothAdapter bluetoothAdapter;
private BluetoothSocket bluetoothSocket;
private OutputStream outputStream;
// UI组件
private TextView connectionStatus;
private ListView deviceListView;
private Button searchBtn; // 搜索按钮
private Button printBtn; // 打印按钮
private Button disconnectBtn; // 新增:断开连接按钮
// 设备列表
private ArrayList<String> deviceList = new ArrayList<>();
private ArrayList<String> deviceAddresses = new ArrayList<>();
private ArrayAdapter<String> deviceAdapter;
// 线程池(替代裸线程,更稳定)
private ExecutorService executor = Executors.newSingleThreadExecutor();
private Handler mainHandler = new Handler(Looper.getMainLooper());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "=== 应用启动 ===");
setContentView(R.layout.activity_main);
initViews();
initBluetoothAdapter();
registerBluetoothReceiver();
}
// 初始化UI(新增断开连接按钮)
private void initViews() {
Log.d(TAG, "初始化UI组件");
connectionStatus = findViewById(R.id.connection_status);
deviceListView = findViewById(R.id.device_list);
searchBtn = findViewById(R.id.search_button);
printBtn = findViewById(R.id.print_button);
// 新增:绑定断开连接按钮(需在layout中添加id为disconnect_button的Button)
disconnectBtn = findViewById(R.id.disconnect_button);
// 初始化列表适配器
deviceAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, deviceList);
deviceListView.setAdapter(deviceAdapter);
// 搜索按钮:点击时禁用,避免重复触发
searchBtn.setOnClickListener(v -> {
if (!searchBtn.isEnabled()) return;
Log.d(TAG, "搜索按钮被点击");
searchBtn.setEnabled(false);
clearDeviceList();
checkPermissionsAndSearch();
});
// 设备列表点击:连接打印机(增加加载状态)
deviceListView.setOnItemClickListener((parent, view, position, id) -> {
String address = deviceAddresses.get(position);
String name = deviceList.get(position).split("\n")[0];
Log.d(TAG, "选中设备: " + name + ",地址: " + address);
// 禁用UI,避免重复点击
printBtn.setEnabled(false);
disconnectBtn.setEnabled(false);
searchBtn.setEnabled(false);
updateStatus("正在连接: " + name, false);
connectToPrinter(address, name);
});
// 打印按钮:增加状态校验
printBtn.setOnClickListener(v -> {
if (!printBtn.isEnabled()) return;
Log.d(TAG, "打印按钮被点击");
if (isConnected()) {
printBtn.setEnabled(false);
printTestPage();
} else {
showToast("请先连接打印机");
Log.w(TAG, "打印失败:未连接设备");
}
});
// 新增:断开连接按钮点击事件
disconnectBtn.setOnClickListener(v -> {
if (!disconnectBtn.isEnabled()) return;
Log.d(TAG, "断开连接按钮被点击");
disconnectFromPrinter();
});
// 初始状态:打印按钮、断开连接按钮禁用
printBtn.setEnabled(false);
disconnectBtn.setEnabled(false);
}
// 初始化蓝牙适配器(增加状态日志)
private void initBluetoothAdapter() {
Log.d(TAG, "初始化蓝牙适配器");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Log.e(TAG, "设备不支持蓝牙");
showToast("设备不支持蓝牙");
finish();
} else {
Log.d(TAG, "蓝牙适配器初始化成功,状态:" + (bluetoothAdapter.isEnabled() ? "已开启" : "未开启"));
updateStatus("蓝牙已就绪(未连接设备)", false);
}
}
// 注册蓝牙广播接收器(增加权限校验)
private void registerBluetoothReceiver() {
Log.d(TAG, "注册蓝牙广播接收器");
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(bluetoothReceiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(bluetoothReceiver, filter);
}
// 蓝牙广播接收器(优化重复判断,增加搜索完成后恢复UI)
private final BroadcastReceiver bluetoothReceiver = 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);
if (device != null && ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED) {
String name = device.getName() != null ? device.getName() : "未知设备";
String address = device.getAddress();
if (!deviceAddresses.contains(address)) {
deviceList.add(name + "\n" + address);
deviceAddresses.add(address);
deviceAdapter.notifyDataSetChanged();
Log.d(TAG, "发现设备: " + name + " (" + address + ")");
}
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Log.d(TAG, "搜索完成,共发现" + deviceList.size() + "个设备");
// 恢复搜索按钮
searchBtn.setEnabled(true);
if (deviceList.isEmpty()) {
showToast("未发现蓝牙设备");
updateStatus("搜索完成:无设备", false);
} else {
showToast("找到" + deviceList.size() + "个设备");
updateStatus("搜索完成:可选择设备连接", false);
}
}
}
};
// 检查权限(补充Bluetooth权限,Android 9部分机型需要)
private void checkPermissionsAndSearch() {
Log.d(TAG, "检查Android 9所需权限");
String[] requiredPermissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
};
ArrayList<String> needPermissions = new ArrayList<>();
for (String perm : requiredPermissions) {
if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
needPermissions.add(perm);
Log.d(TAG, "缺少权限: " + perm);
}
}
if (needPermissions.isEmpty()) {
startBluetoothSearch();
} else {
ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[0]), REQUEST_PERMISSIONS);
}
}
// 开始搜索(增加状态提示)
private void startBluetoothSearch() {
Log.d(TAG, "开始搜索蓝牙设备");
if (!bluetoothAdapter.isEnabled()) {
Log.d(TAG, "蓝牙未开启,请求开启");
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
return;
}
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
Log.d(TAG, "取消正在进行的搜索");
}
// 加载已配对设备
loadPairedDevices();
// 开始搜索
updateStatus("正在搜索蓝牙设备...", false);
boolean isSearching = bluetoothAdapter.startDiscovery();
if (isSearching) {
showToast("正在搜索设备...");
Log.d(TAG, "搜索启动成功");
} else {
showToast("搜索失败,请重试");
Log.e(TAG, "搜索启动失败");
searchBtn.setEnabled(true); // 恢复按钮
}
}
// 加载已配对设备(补充权限校验)
private void loadPairedDevices() {
Log.d(TAG, "加载已配对设备");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
return;
}
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
String name = device.getName() != null ? device.getName() : "未知设备";
String address = device.getAddress();
deviceList.add(name + "\n" + address + " (已配对)");
deviceAddresses.add(address);
Log.d(TAG, "已配对设备: " + name + " (" + address + ")");
}
deviceAdapter.notifyDataSetChanged();
} else {
Log.d(TAG, "无已配对设备");
}
}
// 连接打印机(重构为线程池执行,增加异常兜底)
private void connectToPrinter(String address, String name) {
executor.execute(() -> {
BluetoothDevice device = null;
try {
// 权限校验
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
mainHandler.post(() -> {
showToast("缺少蓝牙权限,无法连接");
resetUiStatus();
});
return;
}
// 取消搜索
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
// 获取远程设备
device = bluetoothAdapter.getRemoteDevice(address);
Log.d(TAG, "开始连接设备: " + device.getName() + " (" + address + ")");
// 关闭旧连接
closeConnection();
// 创建Socket并连接(增加超时逻辑)
bluetoothSocket = device.createRfcommSocketToServiceRecord(PRINTER_UUID);
bluetoothSocket.connect(); // 底层默认超时约12秒
outputStream = bluetoothSocket.getOutputStream();
// 连接成功:更新UI(启用断开连接按钮)
Log.d(TAG, "连接成功: " + name);
mainHandler.post(() -> {
updateStatus("已连接: " + name, true);
showToast("连接成功:" + name);
printBtn.setEnabled(true);
disconnectBtn.setEnabled(true); // 启用断开连接按钮
searchBtn.setEnabled(true);
});
} catch (IOException e) {
// 连接失败:详细日志+UI恢复
Log.e(TAG, "连接失败: " + (device != null ? device.getName() : address) + ",原因:" + e.getMessage(), e);
closeConnection(); // 确保关闭资源
mainHandler.post(() -> {
updateStatus("连接失败: " + e.getMessage(), false);
showToast("连接失败:" + (e.getMessage() != null ? e.getMessage() : "未知错误"));
resetUiStatus(); // 恢复UI状态
});
}
});
}
// 断开连接打印机
private void disconnectFromPrinter() {
executor.execute(() -> {
Log.d(TAG, "开始断开蓝牙连接");
try {
// 关闭连接资源
closeConnection();
// 断开成功:更新UI
mainHandler.post(() -> {
updateStatus("已断开连接", false);
showToast("已断开与打印机的连接");
// 禁用打印和断开按钮,启用搜索按钮
printBtn.setEnabled(false);
disconnectBtn.setEnabled(false);
searchBtn.setEnabled(true);
});
Log.d(TAG, "断开连接成功");
} catch (Exception e) {
// 断开失败:日志+UI提示
Log.e(TAG, "断开连接失败: " + e.getMessage(), e);
mainHandler.post(() -> {
showToast("断开连接失败:" + e.getMessage());
});
}
});
}
// 打印测试页
private void printTestPage() {
executor.execute(() -> {
if (outputStream == null) {
mainHandler.post(() -> {
showToast("未连接打印机");
printBtn.setEnabled(true);
});
return;
}
try {
// 1. 硬重置打印机
outputStream.write(new byte[]{0x1B, 0x40});
Thread.sleep(500);
// 2. 初始化配置(只执行一次)
String initCmd =
"SIZE " + LABEL_WIDTH + "mm," + LABEL_HEIGHT + "mm\n" +
"GAP 2mm,0mm\n" +
"SET DENSITY " + PRINT_DENSITY + "\n" +
"CLS\n";
outputStream.write(initCmd.getBytes(PRINT_CHARSET));
Thread.sleep(300);
// 3. 构建打印内容
StringBuilder cmd = new StringBuilder();
cmd.append("TEXT 10,10,\"3\",0,2,2,\"您好世界您好世界您好世界您好世界您好世界\"\n");
cmd.append("TEXT 10,50,\"3\",0,1,1,\"测试打印-TSC\"\n");
cmd.append("PRINT 1,1\n");
// 4. 添加结束符
byte[] printCmd = cmd.toString().getBytes(PRINT_CHARSET);
byte[] finalCmd = new byte[printCmd.length + 1];
System.arraycopy(printCmd, 0, finalCmd, 0, printCmd.length);
finalCmd[printCmd.length] = 0x0C;
// 5. 发送完整指令
outputStream.write(finalCmd);
outputStream.flush();
Thread.sleep(200);
// 6. 成功反馈
Log.d(TAG, "打印指令发送完成,指令:\n" + cmd.toString() + "[0x0C]");
mainHandler.post(() -> {
showToast("打印成功!");
printBtn.setEnabled(true);
});
} catch (Exception e) {
Log.e(TAG, "打印异常: " + e.getMessage(), e);
mainHandler.post(() -> {
showToast("打印失败:" + (e.getMessage() != null ? e.getMessage() : "未知错误"));
printBtn.setEnabled(true);
});
}
});
}
// 关闭连接(增加空指针保护)
private void closeConnection() {
Log.d(TAG, "关闭蓝牙连接");
try {
if (outputStream != null) {
outputStream.close();
outputStream = null;
}
if (bluetoothSocket != null) {
bluetoothSocket.close();
bluetoothSocket = null;
}
} catch (IOException e) {
Log.e(TAG, "关闭连接失败: " + e.getMessage(), e);
}
}
// 检查连接状态(更严谨)
private boolean isConnected() {
return bluetoothSocket != null && bluetoothSocket.isConnected() && outputStream != null;
}
// 更新状态(封装+主线程保障)
private void updateStatus(String text, boolean isSuccess) {
mainHandler.post(() -> {
connectionStatus.setText(text);
connectionStatus.setTextColor(isSuccess ?
getResources().getColor(android.R.color.holo_green_dark) :
getResources().getColor(android.R.color.holo_red_dark));
});
}
// 显示Toast(封装)
private void showToast(String msg) {
mainHandler.post(() -> Toast.makeText(this, msg, Toast.LENGTH_SHORT).show());
}
// 清空设备列表(封装)
private void clearDeviceList() {
deviceList.clear();
deviceAddresses.clear();
deviceAdapter.notifyDataSetChanged();
}
// 恢复UI状态(统一管理,新增断开按钮状态)
private void resetUiStatus() {
printBtn.setEnabled(false);
disconnectBtn.setEnabled(false); // 新增:禁用断开按钮
searchBtn.setEnabled(true);
}
// 权限请求结果(优化提示)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.d(TAG, "权限请求结果,请求码: " + requestCode);
if (requestCode == REQUEST_PERMISSIONS) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
Log.d(TAG, "权限已授予,开始搜索");
startBluetoothSearch();
} else {
Log.w(TAG, "权限被拒绝");
new AlertDialog.Builder(this)
.setTitle("权限不足")
.setMessage("需要位置和蓝牙权限才能搜索/连接打印机,请在设置中开启")
.setPositiveButton("去设置", (dialog, which) -> {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", getPackageName(), null));
startActivity(intent);
})
.setNegativeButton("取消", null)
.show();
searchBtn.setEnabled(true); // 恢复按钮
}
}
}
// 蓝牙开启结果(优化状态)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: 请求码=" + requestCode + ", 结果码=" + resultCode);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
Log.d(TAG, "蓝牙已开启,开始搜索");
startBluetoothSearch();
} else {
Log.w(TAG, "用户拒绝开启蓝牙");
showToast("请开启蓝牙后重试");
updateStatus("蓝牙未开启", false);
searchBtn.setEnabled(true); // 恢复按钮
}
}
}
// 生命周期:优化资源释放
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "应用销毁,清理资源");
// 注销广播
try {
unregisterReceiver(bluetoothReceiver);
} catch (IllegalArgumentException e) {
Log.w(TAG, "广播接收器已注销,无需重复操作");
}
// 关闭连接
closeConnection();
// 关闭线程池
executor.shutdown();
// 移除Handler回调
mainHandler.removeCallbacksAndMessages(null);
}
// 暂停时:优化蓝牙处理
@Override
protected void onPause() {
super.onPause();
if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
Log.d(TAG, "暂停,停止搜索");
}
// 恢复按钮状态
if (!isFinishing()) {
searchBtn.setEnabled(true);
}
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 蓝牙基础权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- 位置权限(低版本蓝牙扫描需要) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 后台定位(可选,用于持续扫描) -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-feature
android:name="android.hardware.bluetooth"
android:required="true" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Bluetoothprinter_Two"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="#F8F9FA">
<!-- 连接状态卡片(简单圆角+白色背景) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:padding="16dp"
android:layout_marginBottom="20dp"
android:orientation="vertical"
android:elevation="2dp"
android:radius="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="连接状态"
android:textSize="14sp"
android:textColor="#666666"
android:layout_marginBottom="6dp"/>
<TextView
android:id="@+id/connection_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="蓝牙已就绪(未连接设备)"
android:textSize="17sp"
android:textColor="#333333"/>
</LinearLayout>
<!-- 按钮区域(圆角按钮+间距) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/search_button"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:text="搜索"
android:textSize="16sp"
android:backgroundTint="#4A90E2"
android:textColor="#FFFFFF"/>
<Button
android:id="@+id/print_button"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:text="打印"
android:textSize="16sp"
android:backgroundTint="#5CB85C"
android:textColor="#FFFFFF"
/>
<Button
android:id="@+id/disconnect_button"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:text="断开"
android:textSize="16sp"
android:backgroundTint="#D9534F"
android:textColor="#FFFFFF"
/>
</LinearLayout>
<!-- 设备列表(圆角+白色背景) -->
<ListView
android:id="@+id/device_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:divider="#EEEEEE"
android:dividerHeight="1dp"
android:padding="8dp"
android:elevation="2dp"
android:radius="8dp"
android:listSelector="#E8F4F8"/>
</LinearLayout>