- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经为 android 开发了一个应用程序,可以通过蓝牙连接到 zebra 打印机,它工作正常。这要归功于 Zebra 提供的库。
我的问题是,如果我想使用另一种类型的打印机,那将迫使我重新编程并使用另一个库。
有什么方法可以打印到任何蓝牙打印机吗?无需针对每种特定类型的品牌进行编程?
最佳答案
这是一个 github link它提供了一个简单的安卓蓝牙打印库,适用于任何蓝牙打印机。它可以很容易地集成到您的项目中。我对其进行了一些调整,这样就不必在每次打印时都选择蓝牙设备。
我用它为这个 video 中显示的应用程序提供打印功能.基本上有三个重要的类。
public class PrinterCommands {
public static final byte HT = 0x9;
public static final byte LF = 0x0A;
public static final byte CR = 0x0D;
public static final byte ESC = 0x1B;
public static final byte DLE = 0x10;
public static final byte GS = 0x1D;
public static final byte FS = 0x1C;
public static final byte STX = 0x02;
public static final byte US = 0x1F;
public static final byte CAN = 0x18;
public static final byte CLR = 0x0C;
public static final byte EOT = 0x04;
public static final byte[] INIT = {27, 64};
public static byte[] FEED_LINE = {10};
public static byte[] SELECT_FONT_A = {20, 33, 0};
public static byte[] SET_BAR_CODE_HEIGHT = {29, 104, 100};
public static byte[] PRINT_BAR_CODE_1 = {29, 107, 2};
public static byte[] SEND_NULL_BYTE = {0x00};
public static byte[] SELECT_PRINT_SHEET = {0x1B, 0x63, 0x30, 0x02};
public static byte[] FEED_PAPER_AND_CUT = {0x1D, 0x56, 66, 0x00};
public static byte[] SELECT_CYRILLIC_CHARACTER_CODE_TABLE = {0x1B, 0x74, 0x11};
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
public static byte[] SET_LINE_SPACING_24 = {0x1B, 0x33, 24};
public static byte[] SET_LINE_SPACING_30 = {0x1B, 0x33, 30};
public static byte[] TRANSMIT_DLE_PRINTER_STATUS = {0x10, 0x04, 0x01};
public static byte[] TRANSMIT_DLE_OFFLINE_PRINTER_STATUS = {0x10, 0x04, 0x02};
public static byte[] TRANSMIT_DLE_ERROR_STATUS = {0x10, 0x04, 0x03};
public static byte[] TRANSMIT_DLE_ROLL_PAPER_SENSOR_STATUS = {0x10, 0x04, 0x04};
public static final byte[] ESC_FONT_COLOR_DEFAULT = new byte[] { 0x1B, 'r',0x00 };
public static final byte[] FS_FONT_ALIGN = new byte[] { 0x1C, 0x21, 1, 0x1B,
0x21, 1 };
public static final byte[] ESC_ALIGN_LEFT = new byte[] { 0x1b, 'a', 0x00 };
public static final byte[] ESC_ALIGN_RIGHT = new byte[] { 0x1b, 'a', 0x02 };
public static final byte[] ESC_ALIGN_CENTER = new byte[] { 0x1b, 'a', 0x01 };
public static final byte[] ESC_CANCEL_BOLD = new byte[] { 0x1B, 0x45, 0 };
/*********************************************/
public static final byte[] ESC_HORIZONTAL_CENTERS = new byte[] { 0x1B, 0x44, 20, 28, 00};
public static final byte[] ESC_CANCLE_HORIZONTAL_CENTERS = new byte[] { 0x1B, 0x44, 00 };
/*********************************************/
public static final byte[] ESC_ENTER = new byte[] { 0x1B, 0x4A, 0x40 };
public static final byte[] PRINTE_TEST = new byte[] { 0x1D, 0x28, 0x41 };
下面显示的另一个类可帮助您从已配对的蓝牙设备列表中选择打印机。
public class DeviceListActivity extends Activity {
protected static final String TAG = "TAG";
private BluetoothAdapter mBluetoothAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private static PrinterSelectedListener printerSelectedListener;
@Override
protected void onCreate(Bundle mSavedInstanceState) {
super.onCreate(mSavedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.devices_list);
newConnection();
}
public static void setPrinterSelectedListener(PrinterSelectedListener printerSelectedListener_) {
printerSelectedListener = printerSelectedListener_;
}
private void newConnection() {
try {
setResult(Activity.RESULT_CANCELED);
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
ListView mPairedListView = findViewById(R.id.paired_devices);
mPairedListView.setAdapter(mPairedDevicesArrayAdapter);
mPairedListView.setOnItemClickListener(mDeviceClickListener);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> mPairedDevices = mBluetoothAdapter.getBondedDevices();
if (mPairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice mDevice : mPairedDevices) {
mPairedDevicesArrayAdapter.add(mDevice.getName() + "\n" + mDevice.getAddress());
}
} else {
String mNoDevices = "None Paired";//getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(mNoDevices);
}
}catch(Exception ex){
Log.e("exception", ex.toString());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mBluetoothAdapter != null) {
mBluetoothAdapter.cancelDiscovery();
}
}
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> mAdapterView, View mView, int mPosition, long mLong) {
try {
mBluetoothAdapter.cancelDiscovery();
String mDeviceInfo = ((TextView) mView).getText().toString();
String mDeviceAddress = mDeviceInfo.substring(mDeviceInfo.length() - 17);
String mDeviceName = mDeviceInfo.substring(0, mDeviceInfo.length()- 17);
Bundle mBundle = new Bundle();
mBundle.putString("DeviceAddress", mDeviceAddress);
//save this printer address in sharedpreference
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = pref.edit();
editor.putString("bluetooth_printer", mDeviceAddress); //
editor.putString("bluetooth_name", mDeviceName);
editor.apply();
//respond to listerner
if(printerSelectedListener != null)
{
printerSelectedListener.onPrinterSelected(mDeviceName);
}
Intent mBackIntent = new Intent();
mBackIntent.putExtras(mBundle);
setResult(Activity.RESULT_OK, mBackIntent);
finish();
}
catch (Exception ex)
{
}
}
};
第三个类是您应该扩展的类,以便 super 方法可以为您打印。该类如下所示。
public class MainActivity extends AppCompatActivity implements Runnable {
protected static final String TAG = "TAG";
protected static final int REQUEST_CONNECT_DEVICE = 1;
protected static final int REQUEST_ENABLE_BT = 2;
protected static final int BT_ON = 3;
protected BluetoothAdapter mBluetoothAdapter;
protected UUID applicationUUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
protected ProgressDialog mBluetoothConnectProgressDialog;
protected BluetoothSocket mBluetoothSocket;
protected BluetoothDevice mBluetoothDevice;
protected OutputStream outputStream;
public String BILL = "";
protected String printerName = "";
protected boolean isChangingName = false;
protected boolean isTestingPrinter = false;
@Override
protected void onCreate(Bundle mSavedInstanceState) {
super.onCreate(mSavedInstanceState);
setContentView(R.layout.activity_printer);
}// onCreate
public void doPrint(final String job) {
String name = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("bluetooth_printer", "");
printerName = name;
this.BILL = job;
this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (name.equalsIgnoreCase(""))
{
if (this.mBluetoothAdapter == null)
{
Toast.makeText(getApplicationContext(), "Your Bluetooth adapter has issues", Toast.LENGTH_LONG).show();
return;
} else if (!this.mBluetoothAdapter.isEnabled())
{
//put on the bluetooth
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
REQUEST_ENABLE_BT);
return;
} else
{
introduceNewDevice();
return;
}
}else
{
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
BT_ON);
return;
}
}
protected void printingProcess(final String BILL, String name) {
this.mBluetoothDevice = this.mBluetoothAdapter.getRemoteDevice(name);
try {
this.mBluetoothSocket = this.mBluetoothDevice.createRfcommSocketToServiceRecord(this.applicationUUID);
this.mBluetoothSocket.connect();
} catch (IOException eConnectException) {
Toast.makeText(MainActivity.this, "The printer is not available. Check if it is on", Toast.LENGTH_SHORT).show();
}
new Thread() {
public void run() {
try { //outputStream
outputStream = mBluetoothSocket.getOutputStream();
if(isTestingPrinter){
//invoice details
printConfig(BILL, 2, 1,1);//align 1=center
printNewLine();
}
closeSocket(mBluetoothSocket); //close the connection
} catch (Exception e) {
Log.e("MainActivity", "Exe ", e);
}
}
}.start();
}
protected void printConfig(String bill, int size, int style, int align)
{
//size 1 = large, size 2 = medium, size 3 = small
//style 1 = Regular, style 2 = Bold
//align 0 = left, align 1 = center, align 2 = right
try{
byte[] format = new byte[]{27,33, 0};
byte[] change = new byte[]{27,33, 0};
outputStream.write(format);
//different sizes, same style Regular
if (size==1 && style==1) //large
{
change[2] = (byte) (0x10); //large
outputStream.write(change);
}else if(size==2 && style==1) //medium
{
//nothing to change, uses the default settings
}else if(size==3 && style==1) //small
{
change[2] = (byte) (0x3); //small
outputStream.write(change);
}
//different sizes, same style Bold
if (size==1 && style==2) //large
{
change[2] = (byte) (0x10 | 0x8); //large
outputStream.write(change);
}else if(size==2 && style==2) //medium
{
change[2] = (byte) (0x8);
outputStream.write(change);
}else if(size==3 && style==2) //small
{
change[2] = (byte) (0x3 | 0x8); //small
outputStream.write(change);
}
switch (align) {
case 0:
//left align
outputStream.write(PrinterCommands.ESC_ALIGN_LEFT);
break;
case 1:
//center align
outputStream.write(PrinterCommands.ESC_ALIGN_CENTER);
break;
case 2:
//right align
outputStream.write(PrinterCommands.ESC_ALIGN_RIGHT);
break;
}
outputStream.write(bill.getBytes());
outputStream.write(PrinterCommands.LF);
}catch(Exception ex){
Log.e("error", ex.toString());
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
try {
if (mBluetoothSocket != null)
mBluetoothSocket.close();
} catch (Exception e) {
Log.e("Tag", "Exe ", e);
}
}
@Override
public void onBackPressed() {
try {
if (mBluetoothSocket != null)
mBluetoothSocket.close();
} catch (Exception e) {
Log.e("Tag", "Exe ", e);
}
setResult(RESULT_CANCELED);
finish();
}
public void onActivityResult(int mRequestCode, int mResultCode,
Intent mDataIntent) {
super.onActivityResult(mRequestCode, mResultCode, mDataIntent);
try {
switch (mRequestCode) {
case REQUEST_CONNECT_DEVICE:
if (mResultCode == Activity.RESULT_OK) {
Bundle mExtra = mDataIntent.getExtras();
String mDeviceAddress = mExtra.getString("DeviceAddress");
Log.e(TAG, "Coming incoming address " + mDeviceAddress);
mBluetoothDevice = mBluetoothAdapter
.getRemoteDevice(mDeviceAddress);
mBluetoothConnectProgressDialog = ProgressDialog.show(this,
"Connecting...", mBluetoothDevice.getName() + " : "
+ mBluetoothDevice.getAddress(), true, false);
mBluetoothAdapter.cancelDiscovery();
mHandler.sendEmptyMessage(0);
//don't print if we are just changing name
if (!isChangingName)
printingProcess(BILL, mDeviceAddress);
else {
Toast.makeText(MainActivity.this, "Printer selected successfully!", Toast.LENGTH_SHORT).show();
}
}
break;
case REQUEST_ENABLE_BT:
if (mResultCode == Activity.RESULT_OK) {
introduceNewDevice();
} else {
Toast.makeText(MainActivity.this, "Request denied", Toast.LENGTH_SHORT).show();
}
break; //BT_ON
case BT_ON:
if (mResultCode == Activity.RESULT_OK) {
if (isChangingName) {
introduceNewDevice();
} else {
printingProcess(BILL, printerName);
}
} else {
Toast.makeText(MainActivity.this, "Request denied", Toast.LENGTH_SHORT).show();
}
break;
}
}catch(Exception ex){
Log.e(TAG, ex.toString());
}
}
protected void introduceNewDevice() {
ListPairedDevices();
Intent connectIntent = new Intent(MainActivity.this,
DeviceListActivity.class);
startActivityForResult(connectIntent, REQUEST_CONNECT_DEVICE);
}
protected void ListPairedDevices() {
try {
Set<BluetoothDevice> mPairedDevices = mBluetoothAdapter
.getBondedDevices();
if (mPairedDevices.size() > 0) {
for (BluetoothDevice mDevice : mPairedDevices) {
Log.e(TAG, "PairedDevices: " + mDevice.getName() + " "
+ mDevice.getAddress());
}
}
}catch(Exception ex){
Log.e(TAG, ex.toString());
}
}
public void run() {
try {
mBluetoothSocket = mBluetoothDevice
.createRfcommSocketToServiceRecord(applicationUUID);
mBluetoothAdapter.cancelDiscovery();
mBluetoothSocket.connect();
mHandler.sendEmptyMessage(0);
Log.e("main run","inside the main run");
} catch (IOException eConnectException) {
Log.d(TAG, "CouldNotConnectToSocket", eConnectException);
closeSocket(mBluetoothSocket);
return;
}
}
protected void closeSocket(BluetoothSocket nOpenSocket) {
try {
nOpenSocket.close();
Log.d(TAG, "SocketClosed");
} catch (IOException ex) {
Log.d(TAG, "CouldNotCloseSocket");
}
}
protected Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mBluetoothConnectProgressDialog.dismiss();
// Toast.makeText(MainActivity.this, "Device Connected", Toast.LENGTH_SHORT).show();
}
};
public static byte intToByteArray(int value) {
byte[] b = ByteBuffer.allocate(4).putInt(value).array();
for (int k = 0; k < b.length; k++) {
System.out.println("Selva [" + k + "] = " + "0x"
+ UnicodeFormatter.byteToHex(b[k]));
}
return b[3];
}
public byte[] sel(int val) {
ByteBuffer buffer = ByteBuffer.allocate(2);
buffer.putInt(val);
buffer.flip();
return buffer.array();
}
//print photo
public void printPhoto(int img) {
try {
Bitmap bmp = BitmapFactory.decodeResource(getResources(),
img);
if(bmp!=null){
byte[] command = Utils.decodeBitmap(bmp);
outputStream.write(PrinterCommands.ESC_ALIGN_CENTER);
printText(command);
}else{
Log.e("Print Photo error", "the file isn't exists");
}
} catch (Exception e) {
e.printStackTrace();
Log.e("PrintTools", "the file isn't exists");
}
}
//print unicode
public void printUnicode(){
try {
outputStream.write(PrinterCommands.ESC_ALIGN_CENTER);
printText(Utils.UNICODE_TEXT);
} catch (UnsupportedEncodingException e) {
Log.e("printUnicodeProblem", e.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
//print new line
protected void printNewLine() {
try {
outputStream.write(PrinterCommands.FEED_LINE);
} catch (IOException e) {
e.printStackTrace();
}
}
public void resetPrint() {
try{
outputStream.write(PrinterCommands.ESC_FONT_COLOR_DEFAULT);
outputStream.write(PrinterCommands.FS_FONT_ALIGN);
outputStream.write(PrinterCommands.ESC_ALIGN_LEFT);
outputStream.write(PrinterCommands.ESC_CANCEL_BOLD);
outputStream.write(PrinterCommands.LF);
} catch (IOException e) {
e.printStackTrace();
}
}
//print text
protected void printText(String msg) {
try {
// Print normal text
outputStream.write(msg.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
//print byte[]
protected void printText(byte[] msg) {
try {
// Print normal text
outputStream.write(msg);
// printNewLine();
} catch (IOException e) {
Log.e("printTextError",e.toString());
}
}
protected String leftRightAlign(String str1, String str2) {
String ans = str1 +str2;
if(ans.length() <31){
int n = (31 - str1.length() + str2.length());
ans = str1 + new String(new char[n]).replace("\0", " ") + str2;
}
return ans;
}
上面类中的布局 activity_printer.xml 应更改为您的布局。但是,您需要包含此 devices_list.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">
<TextView
android:id="@+id/title_paired_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#666"
android:paddingLeft="5dip"
android:text="Bluetooth Devices"
android:textColor="#fff"
android:visibility="gone" />
<ListView
android:id="@+id/paired_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:layout_weight="1"
android:stackFromBottom="true" />
</LinearLayout>
要打印,只需将字符串传递给方法
doPrint("your strings that needs to be printed");
我做了一些补充,这样您就可以在选择打印机后得到回电。界面如下图。您必须在您希望用户选择打印机并对其进行测试的 Activity 中实现该接口(interface)
public interface PrinterSelectedListener {
void onPrinterSelected(String name); }
要选择一台打印机并在单独的 Activity 中对其进行测试,您的 Activity 必须扩展 MainActivity 并实现 PrinterSelectedListener。要选择新打印机或更改打印机,请调用此
isChangingName = true;
doPrint("");
要测试打印机,调用这个
isChangingName = false;
isTestingPrinter = true;
String test = "This is a test printer page" + "\n";
doPrint(test);
关于Android 打印到任何蓝牙打印机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43462836/
我最近在/ drawable中添加了一些.gifs,以便可以将它们与按钮一起使用。这个工作正常(没有错误)。现在,当我重建/运行我的应用程序时,出现以下错误: Error: Gradle: Execu
Android 中有返回内部存储数据路径的方法吗? 我有 2 部 Android 智能手机(Samsung s2 和 s7 edge),我在其中安装了一个应用程序。我想使用位于这条路径中的 sqlit
这个问题在这里已经有了答案: What's the difference between "?android:" and "@android:" in an android layout xml f
我只想知道 android 开发手机、android 普通手机和 android root 手机之间的实际区别。 我们不能从实体店或除 android marketplace 以外的其他地方购买开发手
自Gradle更新以来,我正在努力使这个项目达到标准。这是一个团队项目,它使用的是android-apt插件。我已经进行了必要的语法更改(编译->实现和apt->注释处理器),但是编译器仍在告诉我存在
我是android和kotlin的新手,所以请原谅要解决的一个非常简单的问题! 我已经使用导航体系结构组件创建了一个基本应用程序,使用了底部的导航栏和三个导航选项。每个导航选项都指向一个专用片段,该片
我目前正在使用 Facebook official SDK for Android . 我现在正在使用高级示例应用程序,但我不知道如何让它获取应用程序墙/流/状态而不是登录的用户。 这可能吗?在那种情
我在下载文件时遇到问题, 我可以在模拟器中下载文件,但无法在手机上使用。我已经定义了上网和写入 SD 卡的权限。 我在服务器上有一个 doc 文件,如果用户单击下载。它下载文件。这在模拟器中工作正常但
这个问题在这里已经有了答案: What is the difference between gravity and layout_gravity in Android? (22 个答案) 关闭 9
任何人都可以告诉我什么是 android 缓存和应用程序缓存,因为当我们谈论缓存清理应用程序时,它的作用是,缓存清理概念是清理应用程序缓存还是像内存管理一样主存储、RAM、缓存是不同的并且据我所知,缓
假设应用程序 Foo 和 Eggs 在同一台 Android 设备上。任一应用程序都可以获取设备上所有应用程序的列表。一个应用程序是否有可能知道另一个应用程序是否已经运行以及运行了多长时间? 最佳答案
我有点困惑,我只看到了从 android 到 pc 或者从 android 到 pc 的例子。我需要制作一个从两部手机 (android) 连接的 android 应用程序进行视频聊天。我在想,我知道
用于使用 Android 以编程方式锁定屏幕。我从 Stackoverflow 之前关于此的问题中得到了一些好主意,并且我做得很好,但是当我运行该代码时,没有异常和错误。而且,屏幕没有锁定。请在这段代
文档说: android:layout_alignParentStart If true, makes the start edge of this view match the start edge
我不知道这两个属性和高度之间的区别。 以一个TextView为例,如果我将它的layout_width设置为wrap_content,并将它的width设置为50 dip,会发生什么情况? 最佳答案
这两个属性有什么关系?如果我有 android:noHistory="true",那么有 android:finishOnTaskLaunch="true" 有什么意义吗? 最佳答案 假设您的应用中有
我是新手,正在尝试理解以下 XML 代码: 查看 developer.android.com 上的文档,它说“starStyle”是 R.attr 中的常量, public static final
在下面的代码中,为什么当我设置时单选按钮的外观会发生变化 android:layout_width="fill_parent" 和 android:width="fill_parent" 我说的是
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
假设我有一个函数 fun myFunction(name:String, email:String){},当我调用这个函数时 myFunction('Ali', 'ali@test.com ') 如何
我是一名优秀的程序员,十分优秀!