commit cae04eead5c7cfd79e4a0c56ba243fe344eea2f1
Author: Developer <91611@user.local>
Date: Mon May 18 17:52:09 2026 +0800
init
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b9d7f25
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.flutter-plugins-dependencies
+/build/
+/coverage/
diff --git a/.metadata b/.metadata
new file mode 100644
index 0000000..e771d71
--- /dev/null
+++ b/.metadata
@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "db50e20168db8fee486b9abf32fc912de3bc5b6a"
+ channel: "stable"
+
+project_type: plugin
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
+ base_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
+ - platform: android
+ create_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
+ base_revision: db50e20168db8fee486b9abf32fc912de3bc5b6a
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..41cc7d8
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ba75c69
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+TODO: Add your license here.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7d3195e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# printer
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter
+[plug-in package](https://flutter.dev/to/develop-plugins),
+a specialized package that includes platform-specific implementation code for
+Android and/or iOS.
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
+
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..a5744c1
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..161bdcd
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.cxx
diff --git a/android/build.gradle.kts b/android/build.gradle.kts
new file mode 100644
index 0000000..9fca796
--- /dev/null
+++ b/android/build.gradle.kts
@@ -0,0 +1,91 @@
+group = "com.xiarui.printer"
+version = "1.0"
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath("com.android.tools.build:gradle:8.11.1")
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ flatDir {
+ dirs("libs")
+ }
+ }
+}
+
+plugins {
+ id("com.android.library")
+}
+
+android {
+ namespace = "com.xiarui.printer"
+
+ compileSdk = 36
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ defaultConfig {
+ minSdk = 24
+ ndk {
+ abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64")
+ }
+ }
+
+ packaging {
+ jniLibs {
+ pickFirsts += listOf(
+ "lib/arm64-v8a/libjnidispatch.so",
+ "lib/armeabi-v7a/libjnidispatch.so",
+ "lib/x86/libjnidispatch.so",
+ "lib/x86_64/libjnidispatch.so"
+ )
+ }
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+
+ testOptions {
+ unitTests.all {
+ it.outputs.upToDateWhen { false }
+
+ it.testLogging {
+ events("passed", "skipped", "failed", "standardOut", "standardError")
+ showStandardStreams = true
+ }
+ }
+ }
+}
+
+dependencies {
+ testImplementation("junit:junit:4.13.2")
+ testImplementation("org.mockito:mockito-core:5.0.0")
+ implementation(files("libs/autoreplyprint.aar"))
+}
+
+// Skip AAR bundling — local .aar dependency prevents bundle* tasks from succeeding.
+// The AAR is available at runtime via flatDir repo; intermediate outputs are sufficient.
+tasks.whenTaskAdded {
+ if (name.startsWith("bundleDebugAar") || name.startsWith("bundleReleaseAar")) {
+ enabled = false
+ }
+}
diff --git a/android/libs/autoreplyprint.aar b/android/libs/autoreplyprint.aar
new file mode 100644
index 0000000..8f3e770
Binary files /dev/null and b/android/libs/autoreplyprint.aar differ
diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro
new file mode 100644
index 0000000..1c4c8ff
--- /dev/null
+++ b/android/proguard-rules.pro
@@ -0,0 +1,8 @@
+# Keep Flutter plugin classes
+-keep class com.xiarui.printer.** { *; }
+-keep class io.flutter.embedding.engine.plugins.** { *; }
+
+# Keep third-party SDKs
+-keep class com.caysn.autoreplyprint.** { *; }
+-keep class com.sun.jna.** { *; }
+-keep class com.lvrenyang.** { *; }
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..b4decdc
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'printer'
diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts
new file mode 100644
index 0000000..b4decdc
--- /dev/null
+++ b/android/settings.gradle.kts
@@ -0,0 +1 @@
+rootProject.name = 'printer'
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29e4f99
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/android/src/main/java/com/xiarui/printer/PortHandleManager.java b/android/src/main/java/com/xiarui/printer/PortHandleManager.java
new file mode 100644
index 0000000..892e147
--- /dev/null
+++ b/android/src/main/java/com/xiarui/printer/PortHandleManager.java
@@ -0,0 +1,186 @@
+package com.xiarui.printer;
+
+import com.caysn.autoreplyprint.AutoReplyPrint;
+import com.sun.jna.Pointer;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages port handles for the Flutter plugin.
+ *
+ * Provides thread-safe registration, retrieval, and cleanup of native port handles.
+ * Each registered Pointer is assigned a unique integer handle starting from 1.
+ *
+ */
+public class PortHandleManager {
+
+ /**
+ * Interface for port operations to enable unit testing without native library.
+ */
+ public interface PortOperations {
+ /**
+ * Close a port.
+ *
+ * @param handle native pointer to the port
+ * @return true if successfully closed, false otherwise
+ */
+ boolean closePort(Pointer handle);
+
+ /**
+ * Check if a port is opened.
+ *
+ * @param handle native pointer to the port
+ * @return true if port is open, false otherwise
+ */
+ boolean isPortOpened(Pointer handle);
+ }
+
+ /**
+ * Default PortOperations implementation using AutoReplyPrint native SDK.
+ */
+ private static class NativePortOperations implements PortOperations {
+ @Override
+ public boolean closePort(Pointer handle) {
+ return AutoReplyPrint.INSTANCE.CP_Port_Close(handle);
+ }
+
+ @Override
+ public boolean isPortOpened(Pointer handle) {
+ return AutoReplyPrint.INSTANCE.CP_Port_IsOpened(handle);
+ }
+ }
+
+ // Singleton instance
+ private static volatile PortHandleManager instance;
+
+ // Handle registry: integer handle -> native Pointer
+ private final ConcurrentHashMap handleRegistry = new ConcurrentHashMap<>();
+
+ // Atomic counter starting from 1
+ private final AtomicInteger counter = new AtomicInteger(1);
+
+ // Port operations abstraction for testability
+ private final PortOperations portOps;
+
+ /**
+ * Private constructor. Use {@link #getInstance()} for production,
+ * or inject custom PortOperations for testing.
+ */
+ private PortHandleManager() {
+ this(new NativePortOperations());
+ }
+
+ /**
+ * Constructor with injectable PortOperations for testing.
+ *
+ * @param portOps port operations implementation
+ */
+ PortHandleManager(PortOperations portOps) {
+ this.portOps = portOps;
+ }
+
+ /**
+ * Returns the singleton instance using native AutoReplyPrint operations.
+ *
+ * @return singleton PortHandleManager
+ */
+ public static PortHandleManager getInstance() {
+ PortHandleManager localInstance = instance;
+ if (localInstance == null) {
+ synchronized (PortHandleManager.class) {
+ localInstance = instance;
+ if (localInstance == null) {
+ instance = localInstance = new PortHandleManager();
+ }
+ }
+ }
+ return localInstance;
+ }
+
+ /**
+ * Registers a native port pointer and returns a unique integer handle.
+ *
+ * If the pointer is null or has a zero native value, registration fails
+ * and returns -1.
+ *
+ *
+ * @param pointer native port pointer to register
+ * @return positive integer handle on success, -1 on failure
+ */
+ public int registerHandle(Pointer pointer) {
+ if (pointer == null || Pointer.nativeValue(pointer) == 0) {
+ return -1;
+ }
+ int handle = counter.getAndIncrement();
+ handleRegistry.put(handle, pointer);
+ return handle;
+ }
+
+ /**
+ * Retrieves the native pointer for a registered handle.
+ *
+ * @param handle integer handle to look up
+ * @return the registered Pointer, or null if not found
+ */
+ public Pointer getHandle(int handle) {
+ return handleRegistry.get(handle);
+ }
+
+ /**
+ * Closes a registered port and removes it from the registry.
+ *
+ * Uses ConcurrentHashMap.compute() for atomic removal to prevent
+ * race conditions (fixes C-04). The port is only closed if it was
+ * successfully removed from the registry, preventing double-close.
+ *
+ *
+ * @param handle integer handle to close
+ * @return true if port was found and closed, false otherwise
+ */
+ public boolean closeHandle(int handle) {
+ Pointer pointer = handleRegistry.compute(handle, (key, existing) -> null);
+ if (pointer != null) {
+ return portOps.closePort(pointer);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if a handle is valid and the underlying port is still opened.
+ *
+ * @param handle integer handle to check
+ * @return true if handle exists and port is opened, false otherwise
+ */
+ public boolean isHandleValid(int handle) {
+ Pointer pointer = handleRegistry.get(handle);
+ if (pointer == null) {
+ return false;
+ }
+ return portOps.isPortOpened(pointer);
+ }
+
+ /**
+ * Closes all registered ports and clears the registry.
+ *
+ * Iterates through all registered handles, closing each one.
+ * Called during engine detachment to clean up resources.
+ *
+ */
+ public void closeAll() {
+ ConcurrentHashMap snapshot = new ConcurrentHashMap<>(handleRegistry);
+ for (Integer handle : snapshot.keySet()) {
+ closeHandle(handle);
+ }
+ handleRegistry.clear();
+ }
+
+ /**
+ * Returns the underlying registry for testing purposes only.
+ *
+ * @return the handle registry map
+ */
+ ConcurrentHashMap getRegistry() {
+ return handleRegistry;
+ }
+}
diff --git a/android/src/main/java/com/xiarui/printer/PrinterPlugin.java b/android/src/main/java/com/xiarui/printer/PrinterPlugin.java
new file mode 100644
index 0000000..2b04a5f
--- /dev/null
+++ b/android/src/main/java/com/xiarui/printer/PrinterPlugin.java
@@ -0,0 +1,887 @@
+package com.xiarui.printer;
+
+import androidx.annotation.NonNull;
+
+import com.caysn.autoreplyprint.AutoReplyPrint;
+import com.sun.jna.Pointer;
+import com.sun.jna.WString;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
+import io.flutter.plugin.common.MethodChannel.Result;
+
+/**
+ * Flutter plugin for printer communication via serial/USB ports.
+ *
+ * Provides MethodChannel handlers for opening, closing, and enumerating
+ * printer ports using the autoreplyprint AAR SDK.
+ *
+ */
+public class PrinterPlugin implements FlutterPlugin, MethodCallHandler {
+ /// The MethodChannel that will the communication between Flutter and native Android
+ ///
+ /// This local reference serves to register the plugin with the Flutter Engine and unregister it
+ /// when the Flutter Engine is detached from the Activity
+ private MethodChannel channel;
+ private PortHandleManager portHandleManager;
+
+ /**
+ * Valid range for baud rate: 1200 to 921600.
+ */
+ private static final int MIN_BAUD_RATE = 1200;
+ private static final int MAX_BAUD_RATE = 921600;
+
+ /**
+ * Valid range for data bits: 5 to 8.
+ */
+ private static final int MIN_DATA_BITS = 5;
+ private static final int MAX_DATA_BITS = 8;
+
+ @Override
+ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
+ channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "printer");
+ channel.setMethodCallHandler(this);
+ portHandleManager = PortHandleManager.getInstance();
+ }
+
+ @Override
+ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
+ switch (call.method) {
+ case "getPlatformVersion":
+ result.success("Android " + android.os.Build.VERSION.RELEASE);
+ break;
+ case "openComPort":
+ handleOpenComPort(call, result);
+ break;
+ case "openUsbPort":
+ handleOpenUsbPort(call, result);
+ break;
+ case "closePort":
+ handleClosePort(call, result);
+ break;
+ case "isPortOpened":
+ handleIsPortOpened(call, result);
+ break;
+ case "enumComPorts":
+ handleEnumComPorts(call, result);
+ break;
+ case "enumUsbPorts":
+ handleEnumUsbPorts(call, result);
+ break;
+ case "setMultiByteMode":
+ handleSetMultiByteMode(call, result);
+ break;
+ case "setMultiByteEncoding":
+ handleSetMultiByteEncoding(call, result);
+ break;
+ case "printText":
+ handlePrintText(call, result);
+ break;
+ case "setAlignment":
+ handleSetAlignment(call, result);
+ break;
+ case "setTextScale":
+ handleSetTextScale(call, result);
+ break;
+ case "setTextBold":
+ handleSetTextBold(call, result);
+ break;
+ case "setTextUnderline":
+ handleSetTextUnderline(call, result);
+ break;
+ case "feedLine":
+ handleFeedLine(call, result);
+ break;
+ case "feedDot":
+ handleFeedDot(call, result);
+ break;
+ case "halfCutPaper":
+ handleHalfCutPaper(call, result);
+ break;
+ case "fullCutPaper":
+ handleFullCutPaper(call, result);
+ break;
+ default:
+ result.notImplemented();
+ break;
+ }
+ }
+
+ /**
+ * Handles openComPort method call.
+ *
+ * Opens a serial port with the specified parameters on a background thread
+ * and returns the result on the main thread via Handler.
+ * Validates portName (non-empty), baudRate (1200-921600), and dataBits (5-8).
+ * Implements PORT-01, PORT-02, T-01-01.
+ *
+ *
+ * @param call the method call containing port parameters
+ * @param result the result callback
+ */
+ private void handleOpenComPort(@NonNull MethodCall call, @NonNull Result result) {
+ String portName = call.argument("portName");
+ Integer baudRate = call.argument("baudRate");
+ Integer dataBits = call.argument("dataBits");
+ Integer parity = call.argument("parity");
+ Integer stopBits = call.argument("stopBits");
+ Integer flowControl = call.argument("flowControl");
+ Integer autoReplyMode = call.argument("autoReplyMode");
+
+ // Validate port name (T-01-01)
+ if (portName == null || portName.isEmpty()) {
+ result.error("INVALID_ARGUMENT", "portName is required and cannot be empty", null);
+ return;
+ }
+
+ // Validate baud rate
+ if (baudRate == null || baudRate < MIN_BAUD_RATE || baudRate > MAX_BAUD_RATE) {
+ result.error(
+ "INVALID_ARGUMENT",
+ "baudRate must be between " + MIN_BAUD_RATE + " and " + MAX_BAUD_RATE,
+ null
+ );
+ return;
+ }
+
+ // Validate data bits (C-02 fix)
+ int db = dataBits != null ? dataBits : 8;
+ if (db < MIN_DATA_BITS || db > MAX_DATA_BITS) {
+ result.error(
+ "INVALID_ARGUMENT",
+ "dataBits must be between " + MIN_DATA_BITS + " and " + MAX_DATA_BITS,
+ null
+ );
+ return;
+ }
+
+ // Defaults
+ int p = parity != null ? parity : 0;
+ int sb = stopBits != null ? stopBits : 0;
+ int fc = flowControl != null ? flowControl : 0;
+ int arm = autoReplyMode != null ? autoReplyMode : 1;
+
+ // Execute on background thread (C-01 fix)
+ final String finalPortName = portName;
+ final int finalBaudRate = baudRate;
+ final int finalDataBits = db;
+ final int finalParity = p;
+ final int finalStopBits = sb;
+ final int finalFlowControl = fc;
+ final int finalAutoReplyMode = arm;
+ final Handler mainHandler = new Handler(Looper.getMainLooper());
+
+ new Thread(() -> {
+ try {
+ Pointer pointer = AutoReplyPrint.INSTANCE.CP_Port_OpenCom(
+ finalPortName,
+ finalBaudRate,
+ finalDataBits,
+ finalParity,
+ finalStopBits,
+ finalFlowControl,
+ finalAutoReplyMode
+ );
+
+ if (pointer == null || Pointer.nativeValue(pointer) == 0) {
+ final Pointer finalPointer = pointer;
+ mainHandler.post(() ->
+ result.error("PORT_OPEN_FAILED", "Failed to open port: " + finalPortName, null)
+ );
+ return;
+ }
+
+ int dartHandle = portHandleManager.registerHandle(pointer);
+ mainHandler.post(() -> result.success(dartHandle));
+ } catch (UnsatisfiedLinkError e) {
+ mainHandler.post(() ->
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null)
+ );
+ } catch (Exception e) {
+ mainHandler.post(() ->
+ result.error("UNKNOWN_ERROR", e.getMessage(), null)
+ );
+ }
+ }).start();
+ }
+
+ /**
+ * Handles openUsbPort method call.
+ *
+ * Opens a USB port on a background thread and returns the result on the main thread.
+ * Validates portName (non-empty) and autoReplyMode (0 or 1).
+ * Implements T-01-02.
+ *
+ *
+ * @param call the method call containing port parameters
+ * @param result the result callback
+ */
+ private void handleOpenUsbPort(@NonNull MethodCall call, @NonNull Result result) {
+ String portName = call.argument("portName");
+ Integer autoReplyMode = call.argument("autoReplyMode");
+
+ // Validate port name (T-01-02)
+ if (portName == null || portName.isEmpty()) {
+ result.error("INVALID_ARGUMENT", "portName is required and cannot be empty", null);
+ return;
+ }
+
+ int arm = autoReplyMode != null ? autoReplyMode : 1;
+
+ final String finalPortName = portName;
+ final int finalAutoReplyMode = arm;
+ final Handler mainHandler = new Handler(Looper.getMainLooper());
+
+ new Thread(() -> {
+ try {
+ Pointer pointer = AutoReplyPrint.INSTANCE.CP_Port_OpenUsb(
+ finalPortName,
+ finalAutoReplyMode
+ );
+
+ if (pointer == null || Pointer.nativeValue(pointer) == 0) {
+ mainHandler.post(() ->
+ result.error("PORT_OPEN_FAILED", "Failed to open USB port: " + finalPortName, null)
+ );
+ return;
+ }
+
+ int dartHandle = portHandleManager.registerHandle(pointer);
+ mainHandler.post(() -> result.success(dartHandle));
+ } catch (UnsatisfiedLinkError e) {
+ mainHandler.post(() ->
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null)
+ );
+ } catch (Exception e) {
+ mainHandler.post(() ->
+ result.error("UNKNOWN_ERROR", e.getMessage(), null)
+ );
+ }
+ }).start();
+ }
+
+ /**
+ * Handles closePort method call.
+ *
+ * Closes a port by its integer handle.
+ * Implements PORT-03, T-01-03.
+ *
+ *
+ * @param call the method call containing handle
+ * @param result the result callback
+ */
+ private void handleClosePort(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ boolean success = portHandleManager.closeHandle(handle);
+ result.success(success);
+ }
+
+ /**
+ * Handles isPortOpened method call.
+ *
+ * Checks if a port is currently opened by its integer handle.
+ *
+ *
+ * @param call the method call containing handle
+ * @param result the result callback
+ */
+ private void handleIsPortOpened(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ boolean isValid = portHandleManager.isHandleValid(handle);
+ result.success(isValid);
+ }
+
+ /**
+ * Handles enumComPorts method call.
+ *
+ * Enumerates available serial ports and returns a list of port names.
+ *
+ *
+ * @param call the method call (no arguments)
+ * @param result the result callback
+ */
+ private void handleEnumComPorts(@NonNull MethodCall call, @NonNull Result result) {
+ try {
+ String[] ports = AutoReplyPrint.CP_Port_EnumCom_Helper.EnumCom();
+ List portList = (ports != null) ? Arrays.asList(ports) : new ArrayList<>();
+ result.success(portList);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles enumUsbPorts method call.
+ *
+ * Enumerates available USB ports and returns a list of port names.
+ *
+ *
+ * @param call the method call (no arguments)
+ * @param result the result callback
+ */
+ private void handleEnumUsbPorts(@NonNull MethodCall call, @NonNull Result result) {
+ try {
+ String[] ports = AutoReplyPrint.CP_Port_EnumUsb_Helper.EnumUsb();
+ List portList = (ports != null) ? Arrays.asList(ports) : new ArrayList<>();
+ result.success(portList);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles setMultiByteMode method call.
+ *
+ * Sets the printer to multi-byte encoding mode.
+ * Must be called before setMultiByteEncoding and printText for Chinese/multibyte text.
+ * Implements PRINT-01.
+ *
+ *
+ * @param call the method call containing handle
+ * @param result the result callback, returns true on success
+ */
+ private void handleSetMultiByteMode(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_SetMultiByteMode(pointer);
+ if (!success) {
+ result.error("PRINT_FAILED", "setMultiByteMode failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles setMultiByteEncoding method call.
+ *
+ * Sets the multi-byte character encoding for the printer.
+ * Valid encoding values: 0=GBK, 1=UTF8, 3=BIG5, 4=ShiftJIS, 5=EUC_KR.
+ * Implements PRINT-01.
+ *
+ *
+ * @param call the method call containing handle and encoding (int)
+ * @param result the result callback, returns true on success
+ */
+ private void handleSetMultiByteEncoding(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer encoding = call.argument("encoding");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (encoding == null) {
+ result.error("INVALID_ARGUMENT", "encoding is required", null);
+ return;
+ }
+
+ if (encoding != 0 && encoding != 1 && encoding != 3 && encoding != 4 && encoding != 5) {
+ result.error("INVALID_ARGUMENT",
+ "encoding must be one of {0=GBK, 1=UTF8, 3=BIG5, 4=ShiftJIS, 5=EUC_KR}", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_SetMultiByteEncoding(pointer, encoding);
+ if (!success) {
+ result.error("PRINT_FAILED", "setMultiByteEncoding failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles printText method call.
+ *
+ * Prints text using UTF-8 encoding (WString).
+ * Requires multi-byte mode and UTF-8 encoding to be set beforehand for correct Chinese character output.
+ * Implements PRINT-02, T-02-03.
+ *
+ *
+ * @param call the method call containing handle and text (String)
+ * @param result the result callback, returns true on success
+ */
+ private void handlePrintText(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ String text = call.argument("text");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (text == null || text.isEmpty()) {
+ result.error("INVALID_ARGUMENT", "text is required and cannot be empty", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_PrintTextInUTF8(pointer, new WString(text));
+ if (!success) {
+ result.error("PRINT_FAILED", "printText failed (length: " + text.length() + ")", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles setAlignment method call.
+ *
+ * Sets the print alignment.
+ * Valid values: 0=left, 1=center, 2=right.
+ * Implements PRINT-04.
+ *
+ *
+ * @param call the method call containing handle and alignment (int)
+ * @param result the result callback, returns true on success
+ */
+ private void handleSetAlignment(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer alignment = call.argument("alignment");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (alignment == null) {
+ result.error("INVALID_ARGUMENT", "alignment is required", null);
+ return;
+ }
+
+ if (alignment != 0 && alignment != 1 && alignment != 2) {
+ result.error("INVALID_ARGUMENT", "alignment must be one of {0=left, 1=center, 2=right}", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_SetAlignment(pointer, alignment);
+ if (!success) {
+ result.error("PRINT_FAILED", "setAlignment failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles setTextScale method call.
+ *
+ * Sets text width and height scale factors.
+ * Both widthScale and heightScale must be in range [1, 8].
+ * Implements PRINT-04, T-02-02.
+ *
+ *
+ * @param call the method call containing handle, widthScale (int), heightScale (int)
+ * @param result the result callback, returns true on success
+ */
+ private void handleSetTextScale(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer widthScale = call.argument("widthScale");
+ Integer heightScale = call.argument("heightScale");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (widthScale == null) {
+ result.error("INVALID_ARGUMENT", "widthScale is required", null);
+ return;
+ }
+
+ if (heightScale == null) {
+ result.error("INVALID_ARGUMENT", "heightScale is required", null);
+ return;
+ }
+
+ if (widthScale < 1 || widthScale > 8) {
+ result.error("INVALID_ARGUMENT", "widthScale must be in range [1, 8]", null);
+ return;
+ }
+
+ if (heightScale < 1 || heightScale > 8) {
+ result.error("INVALID_ARGUMENT", "heightScale must be in range [1, 8]", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_SetTextScale(pointer, widthScale, heightScale);
+ if (!success) {
+ result.error("PRINT_FAILED", "setTextScale failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles setTextBold method call.
+ *
+ * Sets text bold printing.
+ * Valid values: 0=off, 1=on.
+ * Implements PRINT-04.
+ *
+ *
+ * @param call the method call containing handle and bold (int, 0 or 1)
+ * @param result the result callback, returns true on success
+ */
+ private void handleSetTextBold(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer bold = call.argument("bold");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (bold == null) {
+ result.error("INVALID_ARGUMENT", "bold is required", null);
+ return;
+ }
+
+ if (bold != 0 && bold != 1) {
+ result.error("INVALID_ARGUMENT", "bold must be one of {0=off, 1=on}", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_SetTextBold(pointer, bold);
+ if (!success) {
+ result.error("PRINT_FAILED", "setTextBold failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles setTextUnderline method call.
+ *
+ * Sets text underline style.
+ * Valid values: 0=none, 1=1-dot, 2=2-dot.
+ * Implements PRINT-04, T-02-02.
+ *
+ *
+ * @param call the method call containing handle and underline (int)
+ * @param result the result callback, returns true on success
+ */
+ private void handleSetTextUnderline(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer underline = call.argument("underline");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (underline == null) {
+ result.error("INVALID_ARGUMENT", "underline is required", null);
+ return;
+ }
+
+ if (underline != 0 && underline != 1 && underline != 2) {
+ result.error("INVALID_ARGUMENT", "underline must be one of {0=none, 1=1-dot, 2=2-dot}", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_SetTextUnderline(pointer, underline);
+ if (!success) {
+ result.error("PRINT_FAILED", "setTextUnderline failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles feedLine method call.
+ *
+ * Feeds paper by specified number of lines.
+ * numLines must be greater than 0.
+ * Implements PRINT-05, T-02-02.
+ *
+ *
+ * @param call the method call containing handle and numLines (int)
+ * @param result the result callback, returns true on success
+ */
+ private void handleFeedLine(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer numLines = call.argument("numLines");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (numLines == null) {
+ result.error("INVALID_ARGUMENT", "numLines is required", null);
+ return;
+ }
+
+ if (numLines <= 0) {
+ result.error("INVALID_ARGUMENT", "numLines must be greater than 0", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_FeedLine(pointer, numLines);
+ if (!success) {
+ result.error("PRINT_FAILED", "feedLine failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles feedDot method call.
+ *
+ * Feeds paper by specified number of dots.
+ * numDots must be greater than 0.
+ * Implements PRINT-05, T-02-02.
+ *
+ *
+ * @param call the method call containing handle and numDots (int)
+ * @param result the result callback, returns true on success
+ */
+ private void handleFeedDot(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+ Integer numDots = call.argument("numDots");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ if (numDots == null) {
+ result.error("INVALID_ARGUMENT", "numDots is required", null);
+ return;
+ }
+
+ if (numDots <= 0) {
+ result.error("INVALID_ARGUMENT", "numDots must be greater than 0", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_FeedDot(pointer, numDots);
+ if (!success) {
+ result.error("PRINT_FAILED", "feedDot failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles halfCutPaper method call.
+ *
+ * Triggers half-cut on the paper cutter.
+ * Implements PRINT-06.
+ *
+ *
+ * @param call the method call containing handle
+ * @param result the result callback, returns true on success
+ */
+ private void handleHalfCutPaper(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_HalfCutPaper(pointer);
+ if (!success) {
+ result.error("PRINT_FAILED", "halfCutPaper failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ /**
+ * Handles fullCutPaper method call.
+ *
+ * Triggers full-cut on the paper cutter.
+ * Implements PRINT-06.
+ *
+ *
+ * @param call the method call containing handle
+ * @param result the result callback, returns true on success
+ */
+ private void handleFullCutPaper(@NonNull MethodCall call, @NonNull Result result) {
+ Integer handle = call.argument("handle");
+
+ if (handle == null) {
+ result.error("INVALID_ARGUMENT", "handle is required", null);
+ return;
+ }
+
+ Pointer pointer = portHandleManager.getHandle(handle);
+ if (pointer == null) {
+ result.error("PORT_CLOSED", "Port handle not found: " + handle, null);
+ return;
+ }
+
+ try {
+ boolean success = AutoReplyPrint.INSTANCE.CP_Pos_FullCutPaper(pointer);
+ if (!success) {
+ result.error("PRINT_FAILED", "fullCutPaper failed", null);
+ return;
+ }
+ result.success(success);
+ } catch (UnsatisfiedLinkError e) {
+ result.error("NATIVE_LIBRARY_ERROR", e.getMessage(), null);
+ } catch (Exception e) {
+ result.error("UNKNOWN_ERROR", e.getMessage(), null);
+ }
+ }
+
+ @Override
+ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
+ channel.setMethodCallHandler(null);
+ // Clean up all open ports when engine detaches (T-01-05)
+ if (portHandleManager != null) {
+ portHandleManager.closeAll();
+ }
+ }
+}
diff --git a/android/src/test/java/com/xiarui/printer/PortHandleManagerTest.java b/android/src/test/java/com/xiarui/printer/PortHandleManagerTest.java
new file mode 100644
index 0000000..97486b4
--- /dev/null
+++ b/android/src/test/java/com/xiarui/printer/PortHandleManagerTest.java
@@ -0,0 +1,198 @@
+package com.xiarui.printer;
+
+import static org.junit.Assert.*;
+
+import com.sun.jna.Pointer;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for PortHandleManager.
+ * Uses a mock PortOperations to avoid dependency on native library.
+ */
+public class PortHandleManagerTest {
+
+ private PortHandleManager manager;
+ private MockPortOperations mockOps;
+
+ @Before
+ public void setUp() {
+ mockOps = new MockPortOperations();
+ manager = new PortHandleManager(mockOps);
+ }
+
+ /**
+ * Test 1: registerHandle with valid pointer returns positive handle.
+ */
+ @Test
+ public void testRegisterHandle_ValidPointer_ReturnsPositiveHandle() {
+ // Create a pointer with non-zero native value
+ Pointer pointer = new Pointer(0x1234L);
+
+ int handle = manager.registerHandle(pointer);
+
+ assertTrue("Handle should be > 0", handle > 0);
+ }
+
+ /**
+ * Test 2: registerHandle with null pointer returns -1.
+ */
+ @Test
+ public void testRegisterHandle_NullPointer_ReturnsMinusOne() {
+ int handle = manager.registerHandle(null);
+
+ assertEquals("Null pointer should return -1", -1, handle);
+ }
+
+ /**
+ * Test 2b: registerHandle with zero native value pointer returns -1.
+ */
+ @Test
+ public void testRegisterHandle_ZeroNativeValue_ReturnsMinusOne() {
+ Pointer pointer = new Pointer(0L);
+
+ int handle = manager.registerHandle(pointer);
+
+ assertEquals("Zero native value should return -1", -1, handle);
+ }
+
+ /**
+ * Test 3: getHandle returns the registered pointer.
+ */
+ @Test
+ public void testGetHandle_RegisteredHandle_ReturnsPointer() {
+ Pointer pointer = new Pointer(0x5678L);
+ int handle = manager.registerHandle(pointer);
+
+ Pointer retrieved = manager.getHandle(handle);
+
+ assertEquals("Retrieved pointer should match registered pointer", pointer, retrieved);
+ }
+
+ /**
+ * Test 4: getHandle for unregistered handle returns null.
+ */
+ @Test
+ public void testGetHandle_UnregisteredHandle_ReturnsNull() {
+ Pointer retrieved = manager.getHandle(999);
+
+ assertNull("Unregistered handle should return null", retrieved);
+ }
+
+ /**
+ * Test 5: closeHandle closes the port and removes registration.
+ */
+ @Test
+ public void testCloseHandle_RegisteredHandle_ReturnsTrue() {
+ Pointer pointer = new Pointer(0xABCDL);
+ int handle = manager.registerHandle(pointer);
+
+ boolean result = manager.closeHandle(handle);
+
+ assertTrue("closeHandle should return true for registered handle", result);
+ assertTrue("Mock close should have been called", mockOps.closeCalled);
+ assertNull("Handle should be removed after close", manager.getHandle(handle));
+ }
+
+ /**
+ * Test 6: closeHandle for unregistered handle returns false.
+ */
+ @Test
+ public void testCloseHandle_UnregisteredHandle_ReturnsFalse() {
+ boolean result = manager.closeHandle(999);
+
+ assertFalse("closeHandle should return false for unregistered handle", result);
+ assertFalse("Mock close should NOT have been called", mockOps.closeCalled);
+ }
+
+ /**
+ * Test 7: closeAll closes all registered ports and clears registry.
+ */
+ @Test
+ public void testCloseAll_ClosesAllPorts() {
+ Pointer p1 = new Pointer(0x1111L);
+ Pointer p2 = new Pointer(0x2222L);
+ int h1 = manager.registerHandle(p1);
+ int h2 = manager.registerHandle(p2);
+
+ manager.closeAll();
+
+ assertNull("Handle 1 should be cleared", manager.getHandle(h1));
+ assertNull("Handle 2 should be cleared", manager.getHandle(h2));
+ assertTrue("Mock close should have been called", mockOps.closeCalled);
+ }
+
+ /**
+ * Test 8: Concurrent registrations return unique handles.
+ */
+ @Test
+ public void testRegisterHandle_Concurrent_ReturnsUniqueHandles() throws InterruptedException {
+ final int threadCount = 10;
+ final int[] handles = new int[threadCount];
+ Thread[] threads = new Thread[threadCount];
+
+ for (int i = 0; i < threadCount; i++) {
+ final int index = i;
+ threads[i] = new Thread(() -> {
+ Pointer pointer = new Pointer(0x1000L + index);
+ handles[index] = manager.registerHandle(pointer);
+ });
+ }
+
+ for (Thread t : threads) t.start();
+ for (Thread t : threads) t.join();
+
+ // All handles should be unique
+ for (int i = 0; i < threadCount; i++) {
+ for (int j = i + 1; j < threadCount; j++) {
+ assertNotEquals(
+ "Handles should be unique: " + handles[i] + " vs " + handles[j],
+ handles[i], handles[j]
+ );
+ }
+ }
+ }
+
+ /**
+ * Test 9: isHandleValid returns true for valid opened handle.
+ */
+ @Test
+ public void testIsHandleValid_OpenedHandle_ReturnsTrue() {
+ Pointer pointer = new Pointer(0xEEEEL);
+ int handle = manager.registerHandle(pointer);
+ mockOps.isOpenedResult = true;
+
+ boolean valid = manager.isHandleValid(handle);
+
+ assertTrue("Opened handle should be valid", valid);
+ }
+
+ /**
+ * Test 10: isHandleValid returns false for unregistered handle.
+ */
+ @Test
+ public void testIsHandleValid_UnregisteredHandle_ReturnsFalse() {
+ boolean valid = manager.isHandleValid(999);
+
+ assertFalse("Unregistered handle should not be valid", valid);
+ }
+
+ /**
+ * Mock PortOperations for testing without native library.
+ */
+ static class MockPortOperations implements PortHandleManager.PortOperations {
+ boolean closeCalled = false;
+ boolean isOpenedResult = true;
+
+ @Override
+ public boolean closePort(Pointer handle) {
+ closeCalled = true;
+ return true;
+ }
+
+ @Override
+ public boolean isPortOpened(Pointer handle) {
+ return isOpenedResult;
+ }
+ }
+}
diff --git a/android/src/test/java/com/xiarui/printer/PrinterPluginTest.java b/android/src/test/java/com/xiarui/printer/PrinterPluginTest.java
new file mode 100644
index 0000000..04ff31f
--- /dev/null
+++ b/android/src/test/java/com/xiarui/printer/PrinterPluginTest.java
@@ -0,0 +1,178 @@
+package com.xiarui.printer;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.junit.Assert.*;
+
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import org.junit.Test;
+import org.junit.Before;
+
+/**
+ * Unit tests for PrinterPlugin.
+ * Tests parameter validation and method routing.
+ */
+public class PrinterPluginTest {
+
+ private PrinterPlugin plugin;
+
+ @Before
+ public void setUp() {
+ plugin = new PrinterPlugin();
+ }
+
+ @Test
+ public void onMethodCall_getPlatformVersion_returnsExpectedValue() {
+ final MethodCall call = new MethodCall("getPlatformVersion", null);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE);
+ }
+
+ @Test
+ public void onMethodCall_openComPort_emptyPortName_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("openComPort", new java.util.HashMap() {{
+ put("portName", "");
+ put("baudRate", 115200);
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("portName"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_openComPort_nullPortName_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("openComPort", new java.util.HashMap() {{
+ put("portName", null);
+ put("baudRate", 115200);
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("portName"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_openComPort_invalidBaudRate_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("openComPort", new java.util.HashMap() {{
+ put("portName", "/dev/ttyS0");
+ put("baudRate", 100); // Below minimum 1200
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("baudRate"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_openComPort_invalidDataBits_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("openComPort", new java.util.HashMap() {{
+ put("portName", "/dev/ttyS0");
+ put("baudRate", 115200);
+ put("dataBits", 9); // Above maximum 8
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("dataBits"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_openUsbPort_emptyPortName_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("openUsbPort", new java.util.HashMap() {{
+ put("portName", "");
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("portName"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_closePort_nullHandle_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("closePort", new java.util.HashMap() {{
+ put("handle", null);
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("handle"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_isPortOpened_nullHandle_returnsInvalidArgument() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("isPortOpened", new java.util.HashMap() {{
+ put("handle", null);
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).error("INVALID_ARGUMENT", org.mockito.ArgumentMatchers.contains("handle"), org.mockito.ArgumentMatchers.isNull());
+ }
+
+ @Test
+ public void onMethodCall_unknownMethod_returnsNotImplemented() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("unknownMethod", null);
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).notImplemented();
+ }
+
+ @Test
+ public void onMethodCall_closePort_validHandle_callsPortHandleManager() {
+ // Register a handle first to test close
+ PortHandleManager manager = PortHandleManager.getInstance();
+ com.sun.jna.Pointer pointer = new com.sun.jna.Pointer(0x1234L);
+ int handle = manager.registerHandle(pointer);
+
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("closePort", new java.util.HashMap() {{
+ put("handle", handle);
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).success(true);
+ }
+
+ @Test
+ public void onMethodCall_closePort_invalidHandle_returnsFalse() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("closePort", new java.util.HashMap() {{
+ put("handle", 99999); // Non-existent handle
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ verify(mockResult).success(false);
+ }
+
+ @Test
+ public void onMethodCall_isPortOpened_validHandle_callsPortHandleManager() {
+ PortHandleManager manager = PortHandleManager.getInstance();
+ com.sun.jna.Pointer pointer = new com.sun.jna.Pointer(0x5678L);
+ int handle = manager.registerHandle(pointer);
+
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MethodCall call = new MethodCall("isPortOpened", new java.util.HashMap() {{
+ put("handle", handle);
+ }});
+
+ plugin.onMethodCall(call, mockResult);
+
+ // Note: Without native library, isPortOpened will fail due to UnsatisfiedLinkError
+ // but the test verifies the routing logic
+ }
+}
diff --git a/docs/apis.md b/docs/apis.md
new file mode 100644
index 0000000..5cd87bd
--- /dev/null
+++ b/docs/apis.md
@@ -0,0 +1,5938 @@
+# 接口说明文档
+
+> 本文档为打印机SDK接口说明文档,涵盖枚举定义、回调接口、端口函数、票据/标签/页模式/黑标打印函数等完整API参考。
+
+## 目录
+
+- 开发包简介 (第6页)
+
+- 常见问题说明 (第7页)
+
+- 接口说明 (第8页)
+
+- 枚举和宏定义 (第8页)
+
+- CP_ComDataBits (第8页)
+
+- CP_ComParity (第9页)
+
+- CP_ComStopBits (第10页)
+
+- CP_ComFlowControl (第11页)
+
+- CP_CharacterSet (第12页)
+
+- CP_CharacterCodepage (第13页)
+
+- CP_MultiByteEncoding (第15页)
+
+- CP_ImageBinarizationMethod (第16页)
+
+- CP_ImageCompressionMethod (第17页)
+
+- CP_ImagePixelsFormat (第18页)
+
+- CP_QRCodeECC (第19页)
+
+- CP_Pos_Alignment (第20页)
+
+- CP_Pos_BarcodeType (第21页)
+
+- CP_Pos_BarcodeTextPrintPosition (第22页)
+
+- CP_Page_DrawDirection (第23页)
+
+- CP_Page_DrawAlignment (第24页)
+
+- CP_Label_BarcodeType (第25页)
+
+- CP_Label_BarcodeTextPrintPosition (第26页)
+
+- CP_Label_Rotation (第27页)
+
+- CP_Label_Color (第28页)
+
+- CP_PRINTERSTATUS (第29页)
+
+- CP_RTSTATUS (第32页)
+
+- CP_LABEL_TEXT_STYLE (第34页)
+
+- 回调接口 (第35页)
+
+- CP_OnNetPrinterDiscovered (第35页)
+
+- CP_OnBluetoothDeviceDiscovered (第36页)
+
+- CP_OnWiFiP2PDeviceDiscovered (第37页)
+
+- CP_OnPortOpenedEvent (第38页)
+
+- CP_OnPortOpenFailedEvent (第39页)
+
+- CP_OnPortClosedEvent (第40页)
+
+- CP_OnPortWrittenEvent (第41页)
+
+- CP_OnPortReceivedEvent (第42页)
+
+- CP_OnPrinterStatusEvent (第43页)
+
+- CP_OnPrinterReceivedEvent (第44页)
+
+- CP_OnPrinterPrintedEvent (第45页)
+
+- 添加移除回调 (第46页)
+
+- CP_Port_AddOnPortOpenedEvent (第46页)
+
+- CP_Port_AddOnPortOpenFailedEvent (第47页)
+
+- CP_Port_AddOnPortClosedEvent (第48页)
+
+- CP_Port_AddOnPortWrittenEvent (第49页)
+
+- CP_Port_AddOnPortReceivedEvent (第50页)
+
+- CP_Port_RemoveOnPortOpenedEvent (第51页)
+
+- CP_Port_RemoveOnPortOpenFailedEvent (第52页)
+
+- CP_Port_RemoveOnPortClosedEvent (第53页)
+
+- CP_Port_RemoveOnPortWrittenEvent (第54页)
+
+- CP_Port_RemoveOnPortReceivedEvent (第55页)
+
+- CP_Printer_AddOnPrinterStatusEvent (第56页)
+
+- CP_Printer_AddOnPrinterReceivedEvent (第57页)
+
+- CP_Printer_AddOnPrinterPrintedEvent (第58页)
+
+- CP_Printer_RemoveOnPrinterStatusEvent (第59页)
+
+- CP_Printer_RemoveOnPrinterReceivedEvent (第60页)
+
+- CP_Printer_RemoveOnPrinterPrintedEvent (第61页)
+
+- 端口函数 (第62页)
+
+- CP_Port_EnumCom (第62页)
+
+- CP_Port_EnumUsb (第63页)
+
+- CP_Port_EnumNetPrinter (第64页)
+
+- CP_Port_EnumBtDevice (第65页)
+
+- CP_Port_EnumBleDevice (第66页)
+
+- CP_Port_EnumWiFiP2PDevice (第67页)
+
+- CP_Port_OpenCom (第68页)
+
+- CP_Port_OpenUsb (第70页)
+
+- CP_Port_OpenTcp (第71页)
+
+- CP_Port_OpenBtSpp (第72页)
+
+- CP_Port_OpenBtBle (第73页)
+
+- CP_Port_WiFiP2P_Connect (第74页)
+
+- CP_Port_WiFiP2P_Disconnect (第75页)
+
+- CP_Port_WiFiP2P_IsConnected (第76页)
+
+- CP_Port_Write (第77页)
+
+- CP_Port_Read (第78页)
+
+- CP_Port_ReadUntilByte (第79页)
+
+- CP_Port_Available (第80页)
+
+- CP_Port_SkipAvailable (第81页)
+
+- CP_Port_IsConnectionValid (第82页)
+
+- CP_Port_IsOpened (第83页)
+
+- CP_Port_Close (第84页)
+
+- 获取打印机信息函数 (第85页)
+
+- CP_Printer_GetPrinterResolutionInfo (第85页)
+
+- CP_Printer_GetPrinterFirmwareVersion (第86页)
+
+- CP_Printer_GetPrinterStatusInfo (第87页)
+
+- CP_Printer_GetPrinterReceivedInfo (第88页)
+
+- CP_Printer_GetPrinterPrintedInfo (第89页)
+
+- CP_Printer_GetPrinterLabelPositionAdjustmentInfo (第90页)
+
+- CP_Printer_SetPrinterLabelPositionAdjustmentInfo (第91页)
+
+- CP_Printer_ClearPrinterBuffer (第92页)
+
+- CP_Printer_ClearPrinterError (第93页)
+
+- 票据函数 (第94页)
+
+- CP_Pos_QueryRTStatus (第94页)
+
+- CP_Pos_QueryPrintResult (第95页)
+
+- CP_Pos_KickOutDrawer (第96页)
+
+- CP_Pos_Beep (第97页)
+
+- CP_Pos_FeedAndHalfCutPaper (第98页)
+
+- CP_Pos_FullCutPaper (第99页)
+
+- CP_Pos_HalfCutPaper (第100页)
+
+- CP_Pos_FeedLine (第101页)
+
+- CP_Pos_FeedDot (第102页)
+
+- CP_Pos_PrintSelfTestPage (第103页)
+
+- CP_Pos_PrintText (第104页)
+
+- CP_Pos_PrintTextInUTF8 (第105页)
+
+- CP_Pos_PrintTextInGBK (第106页)
+
+- CP_Pos_PrintTextInBIG5 (第107页)
+
+- CP_Pos_PrintTextInShiftJIS (第108页)
+
+- CP_Pos_PrintTextInEUCKR (第109页)
+
+- CP_Pos_PrintBarcode (第110页)
+
+- CP_Pos_PrintBarcode_Code128Auto (第111页)
+
+- CP_Pos_PrintQRCode (第112页)
+
+- CP_Pos_PrintQRCodeUseEpsonCmd (第113页)
+
+- CP_Pos_PrintQRCodeUseImageCmd (第114页)
+
+- CP_Pos_PrintDoubleQRCode (第115页)
+
+- CP_Pos_PrintPDF417BarcodeUseEpsonCmd (第116页)
+
+- CP_Pos_PrintRasterImageFromFile (第117页)
+
+- CP_Pos_PrintRasterImageFromData (第118页)
+
+- CP_Pos_PrintRasterImageFromPixels (第119页)
+
+- CP_Pos_PrintHorizontalLine (第121页)
+
+- CP_Pos_PrintHorizontalLineSpecifyThickness (第122页)
+
+- CP_Pos_PrintMultipleHorizontalLinesAtOneRow (第123页)
+
+- CP_Pos_ResetPrinter (第124页)
+
+- CP_Pos_SetPrintSpeed (第125页)
+
+- CP_Pos_SetPrintDensity (第126页)
+
+- CP_Pos_SetSingleByteMode (第127页)
+
+- CP_Pos_SetCharacterSet (第128页)
+
+- CP_Pos_SetCharacterCodepage (第129页)
+
+- CP_Pos_SetMultiByteMode (第130页)
+
+- CP_Pos_SetMultiByteEncoding (第131页)
+
+- CP_Pos_SetMovementUnit (第132页)
+
+- CP_Pos_SetPrintAreaLeftMargin (第133页)
+
+- CP_Pos_SetPrintAreaWidth (第134页)
+
+- CP_Pos_SetHorizontalAbsolutePrintPosition (第135页)
+
+- CP_Pos_SetHorizontalRelativePrintPosition (第136页)
+
+- CP_Pos_SetVerticalAbsolutePrintPosition (第137页)
+
+- CP_Pos_SetVerticalRelativePrintPosition (第138页)
+
+- CP_Pos_SetAlignment (第139页)
+
+- CP_Pos_SetTextScale (第140页)
+
+- CP_Pos_SetAsciiTextFontType (第141页)
+
+- CP_Pos_SetTextBold (第142页)
+
+- CP_Pos_SetTextUnderline (第143页)
+
+- CP_Pos_SetTextUpsideDown (第144页)
+
+- CP_Pos_SetTextWhiteOnBlack (第145页)
+
+- CP_Pos_SetTextRotate (第146页)
+
+- CP_Pos_SetTextLineHeight (第147页)
+
+- CP_Pos_SetAsciiTextCharRightSpacing (第148页)
+
+- CP_Pos_SetKanjiTextCharSpacing (第149页)
+
+- CP_Pos_SetBarcodeUnitWidth (第150页)
+
+- CP_Pos_SetBarcodeHeight (第151页)
+
+- CP_Pos_SetBarcodeReadableTextFontType (第152页)
+
+- CP_Pos_SetBarcodeReadableTextPosition (第153页)
+
+- 页模式函数 (第154页)
+
+- CP_Page_SelectPageMode (第154页)
+
+- CP_Page_SelectPageModeEx (第155页)
+
+- CP_Page_ExitPageMode (第156页)
+
+- CP_Page_PrintPage (第157页)
+
+- CP_Page_ClearPage (第158页)
+
+- CP_Page_SetPageArea (第159页)
+
+- CP_Page_SetPageDrawDirection (第160页)
+
+- CP_Page_DrawRect (第161页)
+
+- CP_Page_DrawBox (第162页)
+
+- CP_Page_DrawText (第163页)
+
+- CP_Page_DrawTextInUTF8 (第164页)
+
+- CP_Page_DrawTextInGBK (第165页)
+
+- CP_Page_DrawTextInBIG5 (第166页)
+
+- CP_Page_DrawTextInShiftJIS (第167页)
+
+- CP_Page_DrawTextInEUCKR (第168页)
+
+- CP_Page_DrawBarcode (第169页)
+
+- CP_Page_DrawQRCode (第170页)
+
+- CP_Page_DrawRasterImageFromFile (第171页)
+
+- CP_Page_DrawRasterImageFromData (第172页)
+
+- CP_Page_DrawRasterImageFromPixels (第173页)
+
+- 黑标函数 (第175页)
+
+- CP_BlackMark_EnableBlackMarkMode (第175页)
+
+- CP_BlackMark_DisableBlackMarkMode (第176页)
+
+- CP_BlackMark_SetBlackMarkMaxFindLength (第177页)
+
+- CP_BlackMark_FindNextBlackMark (第178页)
+
+- CP_BlackMark_SetBlackMarkPaperPrintPosition (第179页)
+
+- CP_BlackMark_SetBlackMarkPaperCutPosition (第180页)
+
+- CP_BlackMark_FullCutBlackMarkPaper (第181页)
+
+- CP_BlackMark_HalfCutBlackMarkPaper (第182页)
+
+- 标签函数 (第183页)
+
+- CP_Label_EnableLabelMode (第183页)
+
+- CP_Label_DisableLabelMode (第184页)
+
+- CP_Label_CalibrateLabel (第185页)
+
+- CP_Label_FeedLabel (第186页)
+
+- CP_Label_BackPaperToPrintPosition (第187页)
+
+- CP_Label_FeedPaperToTearPosition (第188页)
+
+- CP_Label_PageBegin (第189页)
+
+- CP_Label_PagePrint (第190页)
+
+- CP_Label_DrawText (第191页)
+
+- CP_Label_DrawTextInUTF8 (第192页)
+
+- CP_Label_DrawTextInGBK (第193页)
+
+- CP_Label_DrawBarcode (第194页)
+
+- CP_Label_DrawQRCode (第196页)
+
+- CP_Label_DrawPDF417Code (第198页)
+
+- CP_Label_DrawImageFromFile (第200页)
+
+- CP_Label_DrawImageFromData (第201页)
+
+- CP_Label_DrawImageFromPixels (第203页)
+
+- CP_Label_DrawLine (第205页)
+
+- CP_Label_DrawRect (第206页)
+
+- CP_Label_DrawBox (第207页)
+
+- 其他函数 (第208页)
+
+- CP_Library_Version (第208页)
+
+- CP_Proto_QueryBatteryLevel (第209页)
+
+- CP_Proto_QuerySerialNumber (第210页)
+
+- CP_Proto_SetSystemNameAndSerialNumber (第211页)
+
+- CP_Proto_SetBluetoothNameAndPassword (第212页)
+
+- CP_Proto_SetPTPBasicParameters (第213页)
+
+- CP_Settings_Hardware_SetPrintSpeed (第216页)
+
+---
+
+## 开发包简介
+
+1 开发包带有很多详细的例子,开发之前,请先运行相应的例子测试,测试完全没问题,再考虑开发。
+
+2 开发包支持各种打印机,包括但不限于票据打印,标签打印,页模式打印,黑标打印。
+
+3 开发包支持自动回传功能,开启该功能需要打印机支持自动回传。
+
+4 开发包所有的函数都以CP_作为前缀,避免与别家开发包混淆。
+
+5 开发包主要由宏定义,枚举,回调,端口函数,票据打印函数,标签打印函数,页模式打印函数,
+
+黑标相关函数组成。
+
+端口函数以CP_Port_开头,包括打开端口,关闭端口,读写端口等函数。
+
+票据打印函数以CP_Pos_开头,主要封装了各种票据指令,可以打印文本,条码,二维码,图片等
+
+标签打印函数以CP_Label_开头,主要封装了标签指令,可以打印文本,条码,二维码,图片等
+
+页模式打印函数以CP_Page_开头,主要封装了页模式相关指令,可以打印文本,条码,二维码,图片等
+
+黑标相关函数以CP_BlackMark_开头,主要封装了黑标定位相关指令
+
+6 一个完整的打印流程是,打开端口,各种打印函数,关闭端口。
+
+回调接口,可用可不用,不影响正常打印流程,回调只是用于提示信息。
+
+7 开发包的所有函数,都在AutoReplyPrint接口里面,
+
+工程代码里面,导入com.caysn.autoreplyprint包,即可调用开发包的所有函数。
+
+8 如需混淆,在proguard-rules.pro文件加入以下内容即可
+
+-keep class com.sun.** {*;}
+
+-keep class com.lvrenyang.** {*;}
+
+-keep class com.caysn.autoreplyprint.** {*;}
+
+---
+
+## 常见问题说明
+
+1 怎么分辨我的打印机是什么机型,该用什么函数?
+
+要注意看机型,是什么机型,用什么函数,用错了就打印不了,或者会打印乱码
+
+放票据纸打印的,就是票据机型,使用CP_Pos_系列函数进行打印
+
+放标签纸的,就是标签机型,使用CP_Label_系列函数进行打印
+
+有些机器既可以放票据纸打印,也可以放标签纸打印的。可以调用函数,开启或关闭标签模式。
+
+最好是咨询卖家,看该用什么例子测试,参考例子来写最省事。
+
+2 为什么打印一半关机了?
+
+看是不是电源不够,额定电压下,一般是要2A的电源就够了。
+
+打印机开机时,指示灯的闪烁一般是不一样的,能很明显的看出来。
+
+出现问题,要仔细观察指示灯或声音,这样便于定位问题。
+
+3 标签打印完,为什么没有定位到缝隙?
+
+看是不是开启了标签模式,标签是否识别到,测试方法是按一下进纸按键,是不是完整的进一张纸
+
+---
+
+## 接口说明
+
+#### CP_ComDataBits
+
+枚举和宏定义
+
+串口数据位。打开串口时,需要指定数据位,一般为8位数据位。
+
+**定义:**
+
+```java
+public static final int CP_ComDataBits_4 = 4;
+public static final int CP_ComDataBits_5 = 5;
+public static final int CP_ComDataBits_6 = 6;
+public static final int CP_ComDataBits_7 = 7;
+public static final int CP_ComDataBits_8 = 8;
+```
+
+---
+
+#### CP_ComParity
+
+串口校验位。打开串口时,需要指定校验位,一般是无校验。
+
+**定义:**
+
+```java
+public static final int CP_ComParity_NoParity = 0;
+public static final int CP_ComParity_OddParity = 1;
+public static final int CP_ComParity_EvenParity = 2;
+public static final int CP_ComParity_MarkParity = 3;
+public static final int CP_ComParity_SpaceParity = 4;
+```
+
+---
+
+#### CP_ComStopBits
+
+串口停止位。打开串口时,需要指定停止位,一般是一位停止位。
+
+**定义:**
+
+```java
+public static final int CP_ComStopBits_One = 0;
+public static final int CP_ComStopBits_OnePointFive = 1;
+public static final int CP_ComStopBits_Two = 2;
+```
+
+---
+
+#### CP_ComFlowControl
+
+串口流控制。打开串口时,需要指定流控制,一般选无流控或者软件流控。硬件流控需要线连对才能用。
+
+**定义:**
+
+```java
+public static final int CP_ComFlowControl_None = 0;
+public static final int CP_ComFlowControl_XonXoff = 1;
+public static final int CP_ComFlowControl_RtsCts = 2;
+public static final int CP_ComFlowControl_DtrDsr = 3;
+```
+
+---
+
+#### CP_CharacterSet
+
+单字节模式下的国际字符集。当打印机处于单字节模式下时,设置打印机国际字符集,会改变0x20-0x7F这个区间
+
+的部分文字的打印。比如货币符号人命币或美元。具体细节请看打印机指令集部分。当打印机处于多字节模式下时,
+
+设置该属性无影响。
+
+**定义:**
+
+```java
+public static final int CP_CharacterSet_USA = 0;
+public static final int CP_CharacterSet_FRANCE = 1;
+public static final int CP_CharacterSet_GERMANY = 2;
+public static final int CP_CharacterSet_UK = 3;
+public static final int CP_CharacterSet_DENMARK_I = 4;
+public static final int CP_CharacterSet_SWEDEN = 5;
+public static final int CP_CharacterSet_ITALY = 6;
+public static final int CP_CharacterSet_SPAIN_I = 7;
+public static final int CP_CharacterSet_JAPAN = 8;
+public static final int CP_CharacterSet_NORWAY = 9;
+public static final int CP_CharacterSet_DENMARK_II = 10;
+public static final int CP_CharacterSet_SPAIN_II = 11;
+public static final int CP_CharacterSet_LATIN = 12;
+public static final int CP_CharacterSet_KOREA = 13;
+public static final int CP_CharacterSet_SLOVENIA = 14;
+public static final int CP_CharacterSet_CHINA = 15;
+```
+
+---
+
+#### CP_CharacterCodepage
+
+单字节模式下的字符代码页。当打印机处于单字节模式下时,设置打印机字符代码页,会改变0x80-0xFF这个区间
+
+的部分文字的打印。具体细节请看打印机指令集部分。当打印机处于多字节模式下时,设置该属性无影响。
+
+**定义:**
+
+```java
+public static final int CP_CharacterCodepage_CP437 = 0;
+public static final int CP_CharacterCodepage_KATAKANA = 1;
+public static final int CP_CharacterCodepage_CP850 = 2;
+public static final int CP_CharacterCodepage_CP860 = 3;
+public static final int CP_CharacterCodepage_CP863 = 4;
+public static final int CP_CharacterCodepage_CP865 = 5;
+public static final int CP_CharacterCodepage_WCP1251 = 6;
+public static final int CP_CharacterCodepage_CP866 = 7;
+public static final int CP_CharacterCodepage_MIK = 8;
+public static final int CP_CharacterCodepage_CP755 = 9;
+public static final int CP_CharacterCodepage_IRAN = 10;
+public static final int CP_CharacterCodepage_CP862 = 15;
+public static final int CP_CharacterCodepage_WCP1252 = 16;
+public static final int CP_CharacterCodepage_WCP1253 = 17;
+public static final int CP_CharacterCodepage_CP852 = 18;
+public static final int CP_CharacterCodepage_CP858 = 19;
+public static final int CP_CharacterCodepage_IRAN_II = 20;
+public static final int CP_CharacterCodepage_LATVIAN = 21;
+public static final int CP_CharacterCodepage_CP864 = 22;
+public static final int CP_CharacterCodepage_ISO_8859_1 = 23;
+public static final int CP_CharacterCodepage_CP737 = 24;
+public static final int CP_CharacterCodepage_WCP1257 = 25;
+public static final int CP_CharacterCodepage_THAI = 26;
+public static final int CP_CharacterCodepage_CP720 = 27;
+public static final int CP_CharacterCodepage_CP855 = 28;
+public static final int CP_CharacterCodepage_CP857 = 29;
+public static final int CP_CharacterCodepage_WCP1250 = 30;
+public static final int CP_CharacterCodepage_CP775 = 31;
+public static final int CP_CharacterCodepage_WCP1254 = 32;
+public static final int CP_CharacterCodepage_WCP1255 = 33;
+public static final int CP_CharacterCodepage_WCP1256 = 34;
+public static final int CP_CharacterCodepage_WCP1258 = 35;
+public static final int CP_CharacterCodepage_ISO_8859_2 = 36;
+public static final int CP_CharacterCodepage_ISO_8859_3 = 37;
+public static final int CP_CharacterCodepage_ISO_8859_4 = 38;
+public static final int CP_CharacterCodepage_ISO_8859_5 = 39;
+public static final int CP_CharacterCodepage_ISO_8859_6 = 40;
+public static final int CP_CharacterCodepage_ISO_8859_7 = 41;
+public static final int CP_CharacterCodepage_ISO_8859_8 = 42;
+```
+
+---
+
+#### CP_MultiByteEncoding
+
+多字节模式下的字符编码。打印机处于多字节模式下时,收到的打印数据,将按照指定的编码进行打印。比如说,
+
+设置打印机为多字节模式,再指定多字节模式下字符编码为 UTF8 编码,应用程序需按照 UTF8 编码发送字符串给
+
+打印机,打印机就会将字符串打印出来。
+
+**定义:**
+
+```java
+public static final int CP_MultiByteEncoding_GBK = 0;
+public static final int CP_MultiByteEncoding_UTF8 = 1;
+public static final int CP_MultiByteEncoding_BIG5 = 3;
+public static final int CP_MultiByteEncoding_ShiftJIS = 4;
+public static final int CP_MultiByteEncoding_EUCKR = 5;
+```
+
+---
+
+#### CP_ImageBinarizationMethod
+
+图像二值化算法。由于打印机只能打印黑白单色位图,打印图像的过程中,如果原图是彩图或灰度图,则需要使用
+
+二值化算法,将原图转为单色图。不同的算法有不同的效果。
+
+阈值算法适用于图片内容都是文字的。
+
+误差扩散法适用于所有的图片,但细看会有毛刺。
+
+抖动算法效果不如误差扩散法,不建议使用,仅做兼容性保留。
+
+**定义:**
+
+```java
+public static final int CP_ImageBinarizationMethod_Dithering = 0;
+public static final int CP_ImageBinarizationMethod_Thresholding = 1;
+public static final int CP_ImageBinarizationMethod_ErrorDiffusion = 2;
+```
+
+---
+
+#### CP_ImageCompressionMethod
+
+图片压缩算法。部分打印机支持使用压缩指令打印图片,提高数据传输效率。具体是否支持需要看实际测试结果才
+
+知道。
+
+**定义:**
+
+```java
+public static final int CP_ImageCompressionMethod_None = 0;
+public static final int CP_ImageCompressionMethod_Level1 = 1;
+public static final int CP_ImageCompressionMethod_Level2 = 2;
+```
+
+---
+
+#### CP_ImagePixelsFormat
+
+图片像素格式。打印图片时,如果是直接传的像素数据打印的,那么数据和格式要对应。
+
+**定义:**
+
+```java
+public static final int CP_ImagePixelsFormat_MONO = 1;
+public static final int CP_ImagePixelsFormat_MONOLSB = 2;
+public static final int CP_ImagePixelsFormat_GRAY8 = 3;
+public static final int CP_ImagePixelsFormat_BYTEORDERED_RGB24 = 4;
+public static final int CP_ImagePixelsFormat_BYTEORDERED_BGR24 = 5;
+public static final int CP_ImagePixelsFormat_BYTEORDERED_ARGB32 = 6;
+public static final int CP_ImagePixelsFormat_BYTEORDERED_RGBA32 = 7;
+public static final int CP_ImagePixelsFormat_BYTEORDERED_ABGR32 = 8;
+public static final int CP_ImagePixelsFormat_BYTEORDERED_BGRA32 = 9;
+CP_ImagePixelsFormat_MONO = 1,
+```
+
+单色位图,高位在前
+
+```java
+CP_ImagePixelsFormat_MONOLSB = 2,
+```
+
+单色位图,低位在前
+
+```java
+CP_ImagePixelsFormat_GRAY8 = 3,
+```
+
+灰度图,每个颜色占一个字节
+
+```java
+CP_ImagePixelsFormat_BYTEORDERED_RGB24 = 4,
+```
+
+按照字节顺序,R G B每个颜色占一个字节
+
+```java
+CP_ImagePixelsFormat_BYTEORDERED_BGR24 = 5,
+```
+
+按照字节顺序,B G R每个颜色占一个字节
+
+```java
+CP_ImagePixelsFormat_BYTEORDERED_ARGB32 = 6,
+```
+
+按照字节顺序,A R G B每个颜色占一个字节
+
+```java
+CP_ImagePixelsFormat_BYTEORDERED_RGBA32 = 7,
+```
+
+按照字节顺序,R G B A每个颜色占一个字节
+
+```java
+CP_ImagePixelsFormat_BYTEORDERED_ABGR32 = 8,
+```
+
+按照字节顺序,A B G R每个颜色占一个字节
+
+```java
+CP_ImagePixelsFormat_BYTEORDERED_BGRA32 = 9
+```
+
+按照字节顺序,B G R A每个颜色占一个字节
+
+---
+
+#### CP_QRCodeECC
+
+二维码纠错等级。
+
+**定义:**
+
+```java
+public static final int CP_QRCodeECC_L = 1;
+public static final int CP_QRCodeECC_M = 2;
+public static final int CP_QRCodeECC_Q = 3;
+public static final int CP_QRCodeECC_H = 4;
+```
+
+---
+
+#### CP_Pos_Alignment
+
+票据模式下打印对齐方式。有左对齐,中对齐,右对齐。
+
+**定义:**
+
+```java
+public static final int CP_Pos_Alignment_Left = 0;
+public static final int CP_Pos_Alignment_HCenter = 1;
+public static final int CP_Pos_Alignment_Right = 2;
+```
+
+---
+
+#### CP_Pos_BarcodeType
+
+票据指令打印条码时,指定条码类型。
+
+**定义:**
+
+```java
+public static final int CP_Pos_BarcodeType_UPCA = 0x41;
+public static final int CP_Pos_BarcodeType_UPCE = 0x42;
+public static final int CP_Pos_BarcodeType_EAN13 = 0x43;
+public static final int CP_Pos_BarcodeType_EAN8 = 0x44;
+public static final int CP_Pos_BarcodeType_CODE39 = 0x45;
+public static final int CP_Pos_BarcodeType_ITF = 0x46;
+public static final int CP_Pos_BarcodeType_CODEBAR = 0x47;
+public static final int CP_Pos_BarcodeType_CODE93 = 0x48;
+public static final int CP_Pos_BarcodeType_CODE128 = 0x49;
+```
+
+---
+
+#### CP_Pos_BarcodeTextPrintPosition
+
+票据指令打印条码时,指定条码文字打印位置。
+
+**定义:**
+
+```java
+public static final int CP_Pos_BarcodeTextPrintPosition_None = 0;
+public static final int CP_Pos_BarcodeTextPrintPosition_AboveBarcode = 1;
+public static final int CP_Pos_BarcodeTextPrintPosition_BelowBarcode = 2;
+public static final int CP_Pos_BarcodeTextPrintPosition_AboveAndBelowBarcode = 3;
+```
+
+---
+
+#### CP_Page_DrawDirection
+
+页模式下打印时,指定页面绘制方向。
+
+**定义:**
+
+```java
+public static final int CP_Page_DrawDirection_LeftToRight = 0;
+public static final int CP_Page_DrawDirection_BottomToTop = 1;
+public static final int CP_Page_DrawDirection_RightToLeft = 2;
+public static final int CP_Page_DrawDirection_TopToBottom = 3;
+```
+
+---
+
+#### CP_Page_DrawAlignment
+
+页模式下的相关绘制函数,坐标如果是大于等于零,就是实际坐标。也可以指定为此处的特定值,指定在区域内对
+
+齐打印。
+
+**定义:**
+
+```java
+public static final int CP_Page_DrawAlignment_Left = -1;
+public static final int CP_Page_DrawAlignment_HCenter = -2;
+public static final int CP_Page_DrawAlignment_Right = -3;
+public static final int CP_Page_DrawAlignment_Top = -1;
+public static final int CP_Page_DrawAlignment_VCenter = -2;
+public static final int CP_Page_DrawAlignment_Bottom = -3;
+```
+
+---
+
+#### CP_Label_BarcodeType
+
+标签指令打印条码时,指定条码类型。
+
+**定义:**
+
+```java
+public static final int CP_Label_BarcodeType_UPCA = 0;
+public static final int CP_Label_BarcodeType_UPCE = 1;
+public static final int CP_Label_BarcodeType_EAN13 = 2;
+public static final int CP_Label_BarcodeType_EAN8 = 3;
+public static final int CP_Label_BarcodeType_CODE39 = 4;
+public static final int CP_Label_BarcodeType_ITF = 5;
+public static final int CP_Label_BarcodeType_CODEBAR = 6;
+public static final int CP_Label_BarcodeType_CODE93 = 7;
+public static final int CP_Label_BarcodeType_CODE128 = 8;
+public static final int CP_Label_BarcodeType_CODE11 = 9;
+public static final int CP_Label_BarcodeType_MSI = 10;
+public static final int CP_Label_BarcodeType_128M = 11;
+public static final int CP_Label_BarcodeType_EAN128 = 12;
+public static final int CP_Label_BarcodeType_25C = 13;
+public static final int CP_Label_BarcodeType_39C = 14;
+public static final int CP_Label_BarcodeType_39 = 15;
+public static final int CP_Label_BarcodeType_EAN13PLUS2 = 16;
+public static final int CP_Label_BarcodeType_EAN13PLUS5 = 17;
+public static final int CP_Label_BarcodeType_EAN8PLUS2 = 18;
+public static final int CP_Label_BarcodeType_EAN8PLUS5 = 19;
+public static final int CP_Label_BarcodeType_POST = 20;
+public static final int CP_Label_BarcodeType_UPCAPLUS2 = 21;
+public static final int CP_Label_BarcodeType_UPCAPLUS5 = 22;
+public static final int CP_Label_BarcodeType_UPCEPLUS2 = 23;
+public static final int CP_Label_BarcodeType_UPCEPLUS5 = 24;
+public static final int CP_Label_BarcodeType_CPOST = 25;
+public static final int CP_Label_BarcodeType_MSIC = 26;
+public static final int CP_Label_BarcodeType_PLESSEY = 27;
+public static final int CP_Label_BarcodeType_ITF14 = 28;
+public static final int CP_Label_BarcodeType_EAN14 = 29;
+```
+
+---
+
+#### CP_Label_BarcodeTextPrintPosition
+
+标签指令打印条码时,指定条码文字打印位置。
+
+**定义:**
+
+```java
+public static final int CP_Label_BarcodeTextPrintPosition_None = 0;
+public static final int CP_Label_BarcodeTextPrintPosition_AboveBarcode = 1;
+public static final int CP_Label_BarcodeTextPrintPosition_BelowBarcode = 2;
+public static final int CP_Label_BarcodeTextPrintPosition_AboveAndBelowBarcode = 3;
+```
+
+---
+
+#### CP_Label_Rotation
+
+标签指令绘制控件时,指定旋转角度。
+
+**定义:**
+
+```java
+public static final int CP_Label_Rotation_0 = 0;
+public static final int CP_Label_Rotation_90 = 1;
+public static final int CP_Label_Rotation_180 = 2;
+public static final int CP_Label_Rotation_270 = 3;
+```
+
+---
+
+#### CP_Label_Color
+
+标签指令绘制控件时,指定绘制颜色。可以是白色或者黑色。
+
+**定义:**
+
+```java
+public static final int CP_Label_Color_White = 0;
+public static final int CP_Label_Color_Black = 1;
+```
+
+---
+
+#### CP_PRINTERSTATUS
+
+打印机自动回传的状态定义。一般只需要关注是否有错误,信息部分主要是起到提示功能。
+
+**定义:**
+
+```java
+public class CP_PrinterStatus {
+private long error_status = 0;
+private long info_status = 0;
+public CP_PrinterStatus(long error_status, long info_status) {
+this.error_status = error_status;
+this.info_status = info_status;
+}
+public long errorStatus() {
+return error_status;
+}
+public long infoStatus() {
+return info_status;
+}
+public boolean ERROR_OCCURED() {
+return error_status != 0;
+}
+public boolean ERROR_CUTTER() {
+return (error_status & 0x01) != 0;
+}
+public boolean ERROR_FLASH() {
+return (error_status & 0x02) != 0;
+}
+public boolean ERROR_NOPAPER() {
+return (error_status & 0x04) != 0;
+}
+public boolean ERROR_VOLTAGE() {
+return (error_status & 0x08) != 0;
+}
+public boolean ERROR_MARKER() {
+return (error_status & 0x10) != 0;
+```
+
+---
+
+#### CP_RTSTATUS
+
+实时状态查询返回的状态定义。此处说明仅供参考,适用于大部分机型,部分机型如不一致,以实际机型指令集为
+
+准。
+
+**定义:**
+
+```java
+public class CP_RTSTATUS_Helper {
+public static boolean CP_RTSTATUS_DRAWER_OPENED(long status) { return (((status >> 0) & 0x04) == 0x00); };
+public static boolean CP_RTSTATUS_OFFLINE(long status) { return (((status >> 0) & 0x08) == 0x08); };
+public static boolean CP_RTSTATUS_COVERUP(long status) { return (((status >> 8) & 0x04) == 0x04); };
+public static boolean CP_RTSTATUS_FEED_PRESSED(long status) { return (((status >> 8) & 0x08) == 0x08); };
+public static boolean CP_RTSTATUS_NOPAPER(long status) { return (((status >> 8) & 0x20) == 0x20); };
+public static boolean CP_RTSTATUS_ERROR_OCCURED(long status) { return (((status >> 8) & 0x40) == 0x40); };
+public static boolean CP_RTSTATUS_CUTTER_ERROR(long status) { return (((status >> 16) & 0x08) == 0x08); };
+public static boolean CP_RTSTATUS_UNRECOVERABLE_ERROR(long status) { return (((status >> 16) & 0x20) ==
+```
+
+0x20); };
+
+```java
+public static boolean CP_RTSTATUS_DEGREE_OR_VOLTAGE_OVERRANGE(long status) { return (((status >> 16) &
+```
+
+0x40) == 0x40); };
+
+```java
+public static boolean CP_RTSTATUS_PAPER_NEAREND(long status) { return (((status >> 24) & 0x08) == 0x08); };
+public static boolean CP_RTSTATUS_PAPER_TAKEOUT(long status) { return (((status >> 24) & 0x04) == 0x04); };
+}
+// 这里的实时状态,共占四字节。
+// 从低字节到高字节依次对应指令集中这四个指令:
+// 10 04 01
+// 10 04 02
+// 10 04 03
+// 10 04 04
+// 部分机型由于定制或其他原因,状态值定义可能与此处不一致,以实测为准。
+//
+// DRAWER_OPENED
+// 钱箱打开
+// OFFLINE
+// 脱机
+// COVERUP
+// 盖子打开
+// FEED_PRESSED
+// 走纸键按下
+// NOPAPER
+// 缺纸
+// ERROR_OCCURED
+// 出错
+// CUTTER_ERROR
+// 切刀错误
+// UNRECOVERABLE_ERROR
+```
+
+---
+
+#### CP_LABEL_TEXT_STYLE
+
+标签指令打印文本时,指定文字打印风格。分别为加粗,下划线,反色,删除线,旋转,宽高加倍。
+
+**定义:**
+
+```java
+public class CP_Label_TextStyle {
+private int style = 0;
+public CP_Label_TextStyle(boolean bold, boolean underline, boolean highlight, boolean strikethrough, int
+```
+
+rotation, int widthscale, int heightscale) {
+
+int style = 0;
+
+if (bold)
+
+style |= (1 << 0);
+
+if (underline)
+
+style |= (1 << 1);
+
+if (highlight)
+
+style |= (1 << 2);
+
+if (strikethrough)
+
+style |= (1 << 3);
+
+style |= (rotation << 4);
+
+style |= (widthscale << 8);
+
+style |= (heightscale << 12);
+
+```java
+this.style = style;
+}
+public int getStyle() {
+return style;
+}
+}
+```
+
+---
+
+### 回调接口
+
+CP_OnNetPrinterDiscovered
+
+枚举网络打印机时,传入的回调函数。查到到网络打印机时,会回调该函数。
+
+定义
+
+public interface CP_OnNetPrinterDiscovered_Callback extends Callback {
+
+void CP_OnNetPrinterDiscovered(String local_ip, String discovered_mac, String discovered_ip, String
+
+discovered_name, Pointer private_data);
+
+}
+
+#### CP_OnBluetoothDeviceDiscovered
+
+枚举蓝牙设备时,传入的回调函数。搜索到蓝牙设备时,会回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnBluetoothDeviceDiscovered_Callback extends Callback {
+```
+
+void CP_OnBluetoothDeviceDiscovered(String device_name, String device_address, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnWiFiP2PDeviceDiscovered
+
+枚举WiFiP2P设备时,传入的回调接口。搜索到WiFiP2P设备时,会回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnWiFiP2PDeviceDiscovered_Callback extends Callback {
+```
+
+void CP_OnWiFiP2PDeviceDiscovered(String device_name, String device_address, String device_type, Pointer
+
+private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPortOpenedEvent
+
+端口打开成功时,回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnPortOpenedEvent_Callback extends Callback {
+```
+
+void CP_OnPortOpenedEvent(Pointer handle, String name, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPortOpenFailedEvent
+
+端口打开失败时,回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnPortOpenFailedEvent_Callback extends Callback {
+```
+
+void CP_OnPortOpenFailedEvent(Pointer handle, String name, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPortClosedEvent
+
+端口关闭时,会回调该接口。
+
+**定义:**
+
+```java
+public interface CP_OnPortClosedEvent_Callback extends Callback {
+```
+
+void CP_OnPortClosedEvent(Pointer handle, Pointer private_data);
+
+```java
+}
+```
+
+备注
+
+端口异常时,比如USB数据线拔出,会自动关闭端口,并触发回调。
+
+---
+
+#### CP_OnPortWrittenEvent
+
+端口写入数据成功时,会回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnPortWrittenEvent_Callback extends Callback {
+```
+
+void CP_OnPortWrittenEvent(Pointer handle, Pointer buffer, int count, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPortReceivedEvent
+
+端口收到数据时,会回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnPortReceivedEvent_Callback extends Callback {
+```
+
+void CP_OnPortReceivedEvent(Pointer handle, Pointer buffer, int count, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPrinterStatusEvent
+
+收到打印机自动回传的状态时,会回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnPrinterStatusEvent_Callback extends Callback {
+```
+
+void CP_OnPrinterStatusEvent(Pointer handle, long printer_error_status, long printer_info_status, Pointer
+
+private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPrinterReceivedEvent
+
+收到打印机自动回传的已接收字节数信息时,会回调该函数。
+
+**定义:**
+
+```java
+public interface CP_OnPrinterReceivedEvent_Callback extends Callback {
+```
+
+void CP_OnPrinterReceivedEvent(Pointer handle, int printer_received_byte_count, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+#### CP_OnPrinterPrintedEvent
+
+收到打印机自动回传的单据打完信息时,会回调该函数。该函数将弃用,不建议使用。
+
+**定义:**
+
+```java
+public interface CP_OnPrinterPrintedEvent_Callback extends Callback {
+```
+
+void CP_OnPrinterPrintedEvent(Pointer handle, int printer_printed_page_id, Pointer private_data);
+
+```java
+}
+```
+
+---
+
+### 添加移除回调
+
+CP_Port_AddOnPortOpenedEvent
+
+添加回调接口,端口打开成功
+
+定义
+
+public boolean CP_Port_AddOnPortOpenedEvent(CP_OnPortOpenedEvent_Callback event, Pointer private_data);
+
+// 添加回调接口,端口打开成功
+
+//
+
+// event
+
+// 回调接口
+
+//
+
+// private_data
+
+// 传给回调接口的参数
+
+//
+
+// return
+
+// true on success.
+
+// false on failed.
+
+#### CP_Port_AddOnPortOpenFailedEvent
+
+添加回调接口,端口打开失败
+
+**定义:**
+
+```java
+public boolean CP_Port_AddOnPortOpenFailedEvent(CP_OnPortOpenFailedEvent_Callback event, Pointer
+```
+
+private_data);
+
+```java
+// 添加回调接口,端口打开失败
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_AddOnPortClosedEvent
+
+添加回调接口,端口关闭
+
+**定义:**
+
+```java
+public boolean CP_Port_AddOnPortClosedEvent(CP_OnPortClosedEvent_Callback event, Pointer private_data);
+// 添加回调接口,端口关闭
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_AddOnPortWrittenEvent
+
+添加回调接口,端口写入数据
+
+**定义:**
+
+```java
+public boolean CP_Port_AddOnPortWrittenEvent(CP_OnPortWrittenEvent_Callback event, Pointer private_data);
+// 添加回调接口,端口写入数据
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_AddOnPortReceivedEvent
+
+添加回调接口,端口收到数据
+
+**定义:**
+
+```java
+public boolean CP_Port_AddOnPortReceivedEvent(CP_OnPortReceivedEvent_Callback event, Pointer private_data);
+// 添加回调接口,端口收到数据
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_RemoveOnPortOpenedEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Port_RemoveOnPortOpenedEvent(CP_OnPortOpenedEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_RemoveOnPortOpenFailedEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Port_RemoveOnPortOpenFailedEvent(CP_OnPortOpenFailedEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_RemoveOnPortClosedEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Port_RemoveOnPortClosedEvent(CP_OnPortClosedEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_RemoveOnPortWrittenEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Port_RemoveOnPortWrittenEvent(CP_OnPortWrittenEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_RemoveOnPortReceivedEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Port_RemoveOnPortReceivedEvent(CP_OnPortReceivedEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_AddOnPrinterStatusEvent
+
+添加回调接口,打印机状态更新
+
+**定义:**
+
+```java
+public boolean CP_Printer_AddOnPrinterStatusEvent(CP_OnPrinterStatusEvent_Callback event, Pointer private_data);
+// 添加回调接口,打印机状态更新
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_AddOnPrinterReceivedEvent
+
+添加回调接口,打印机已接收字节数更新
+
+**定义:**
+
+```java
+public boolean CP_Printer_AddOnPrinterReceivedEvent(CP_OnPrinterReceivedEvent_Callback event, Pointer
+```
+
+private_data);
+
+```java
+// 添加回调接口,打印机已接收字节数更新
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_AddOnPrinterPrintedEvent
+
+添加回调接口,打印机已打印页面ID更新
+
+**定义:**
+
+```java
+public boolean CP_Printer_AddOnPrinterPrintedEvent(CP_OnPrinterPrintedEvent_Callback event, Pointer
+```
+
+private_data);
+
+```java
+// 添加回调接口,打印机已打印页面ID更新
+//
+// event
+// 回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_RemoveOnPrinterStatusEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Printer_RemoveOnPrinterStatusEvent(CP_OnPrinterStatusEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_RemoveOnPrinterReceivedEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Printer_RemoveOnPrinterReceivedEvent(CP_OnPrinterReceivedEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_RemoveOnPrinterPrintedEvent
+
+移除回调接口
+
+**定义:**
+
+```java
+public boolean CP_Printer_RemoveOnPrinterPrintedEvent(CP_OnPrinterPrintedEvent_Callback event);
+// 移除回调接口
+//
+// event
+// 回调接口
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+### 端口函数
+
+CP_Port_EnumCom
+
+枚举本地串口
+
+定义
+
+public class CP_Port_EnumCom_Helper {
+
+public static String[] EnumCom()
+
+}
+
+// return
+
+// 枚举到的端口
+
+#### CP_Port_EnumUsb
+
+枚举本地USB打印口
+
+**定义:**
+
+```java
+public class CP_Port_EnumUsb_Helper {
+public static String[] EnumUsb()
+}
+// return
+// 枚举到的端口
+```
+
+---
+
+#### CP_Port_EnumNetPrinter
+
+枚举网络打印机
+
+**定义:**
+
+```java
+public void CP_Port_EnumNetPrinter(int timeout, IntByReference cancel, CP_OnNetPrinterDiscovered_Callback
+```
+
+on_discovered, Pointer data);
+
+```java
+// 枚举网络打印机
+//
+// timeout
+// 超时毫秒时间
+//
+// cancel
+// 取消标记位,如果设为非零,则枚举提前退出
+//
+// on_discovered
+// 枚举回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// 无
+```
+
+---
+
+#### CP_Port_EnumBtDevice
+
+枚举蓝牙打印机
+
+**定义:**
+
+```java
+public void CP_Port_EnumBtDevice(int timeout, IntByReference cancel, CP_OnBluetoothDeviceDiscovered_Callback
+```
+
+on_discovered, Pointer data);
+
+```java
+// 枚举蓝牙打印机
+//
+// timeout
+// 超时毫秒时间
+//
+// cancel
+// 取消标记位,如果设为非零,则枚举提前退出
+//
+// on_discovered
+// 枚举回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// 无
+```
+
+---
+
+#### CP_Port_EnumBleDevice
+
+枚举BLE蓝牙打印机
+
+**定义:**
+
+```java
+public void CP_Port_EnumBleDevice(int timeout, IntByReference cancel, CP_OnBluetoothDeviceDiscovered_Callback
+```
+
+on_discovered, Pointer data);
+
+```java
+// 枚举BLE蓝牙打印机
+//
+// timeout
+// 超时毫秒时间
+//
+// cancel
+// 取消标记位,如果设为非零,则枚举提前退出
+//
+// on_discovered
+// 枚举回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// 无
+```
+
+---
+
+#### CP_Port_EnumWiFiP2PDevice
+
+枚举WiFi P2P打印机
+
+**定义:**
+
+```java
+public void CP_Port_EnumWiFiP2PDevice(int timeout, IntByReference cancel,
+```
+
+CP_OnWiFiP2PDeviceDiscovered_Callback on_discovered, Pointer data);
+
+```java
+// 枚举WiFi P2P打印机
+//
+// timeout
+// 超时毫秒时间
+//
+// cancel
+// 取消标记位,如果设为非零,则枚举提前退出
+//
+// on_discovered
+// 枚举回调接口
+//
+// private_data
+// 传给回调接口的参数
+//
+// return
+// 无
+```
+
+---
+
+#### CP_Port_OpenCom
+
+打开串口
+
+**定义:**
+
+```java
+public Pointer CP_Port_OpenCom(String name, int baudrate, int databits, int parity, int stopbits, int flowcontrol, int
+```
+
+autoreplymode);
+
+```java
+// 打开串口
+//
+// name
+// 端口名称
+// 例如:COM1,COM2,COM3,...COM11...
+//
+// baudrate
+// 波特率
+// 一般取 9600,19200,38400,57600,115200.
+// 需要和打印机波特率保持一致,建议使用高波特率以获得较好的打印速度
+//
+// databits
+// 数据位,范围[4,8]
+//
+// parity
+// 校验位,各值定义如下:
+// 值 定义
+// 0 无校验
+// 1 奇校验
+// 2 偶校验
+// 3 标记校验
+// 4 空白校验
+//
+// stopbits
+// 停止位,各值定义如下:
+// 值 定义
+// 0 1位停止位
+// 1 1.5位停止位
+// 2 2位停止位
+//
+// flowcontrol
+// 流控制
+//
+// autoreplymode
+// 0 不开启自动回传模式
+// 1 开启自动回传模式
+// 注意:
+```
+
+---
+
+#### CP_Port_OpenUsb
+
+打开USB
+
+**定义:**
+
+```java
+public Pointer CP_Port_OpenUsb(String name, int autoreplymode);
+// 打开USB
+//
+// name
+// 端口名称
+// 可由EnumUsb获得
+// 也可以不指定,这时候,如果找到 USB 打印机,会直接打开
+//
+// autoreplymode
+// 0 不开启自动回传模式
+// 1 开启自动回传模式
+// 注意:
+// 仅部分机型支持自动回传模式,是否支持请询问卖家
+// 启动自动回传模式之后,打印机会自动回传状态
+// 不启动则无法自动获取打印机状态
+//
+// return
+// 返回打开的端口句柄。非零表示打开成功,零表示打开失败。
+//
+// remarks
+// USB 打印机接到电脑上,如果设备管理器中出现了 USB Printing Support,则可以使用该函数打开。
+```
+
+---
+
+#### CP_Port_OpenTcp
+
+打开网口
+
+**定义:**
+
+```java
+public Pointer CP_Port_OpenTcp(String local_ip, String dest_ip, short dest_port, int timeout, int autoreplymode);
+// 打开网口
+//
+// local_ip
+// 绑定到本地IP
+// 用于多网卡或多个本地IP时,选择指定的IP
+// 传入0表示不指定
+//
+// dest_ip
+// 地址或名称
+// 例如:192.168.1.87
+//
+// dest_port
+// 端口号
+// 固定值:9100
+//
+// timeout
+// 连接超时
+//
+// autoreplymode
+// 0 不开启自动回传模式
+// 1 开启自动回传模式
+// 注意:
+// 仅部分机型支持自动回传模式,是否支持请询问卖家
+// 启动自动回传模式之后,打印机会自动回传状态
+// 不启动则无法自动获取打印机状态
+//
+// return
+// 返回打开的端口句柄。非零表示打开成功,零表示打开失败。
+//
+// remarks
+// PC和打印机需要同网段的才可以连接
+```
+
+---
+
+#### CP_Port_OpenBtSpp
+
+通过SPP连接蓝牙打印机
+
+**定义:**
+
+```java
+public Pointer CP_Port_OpenBtSpp(String address, int autoreplymode);
+// 通过SPP连接蓝牙打印机
+//
+// address
+// 打印机地址
+// 例如:"01:02:03:04:05:06"
+//
+// autoreplymode
+// 0 不开启自动回传模式
+// 1 开启自动回传模式
+// 注意:
+// 仅部分机型支持自动回传模式,是否支持请询问卖家
+// 启动自动回传模式之后,打印机会自动回传状态
+// 不启动则无法自动获取打印机状态
+//
+// return
+// 返回打开的端口句柄。非零表示打开成功,零表示打开失败。
+//
+// remarks
+// only for android
+```
+
+---
+
+#### CP_Port_OpenBtBle
+
+通过BLE连接蓝牙打印机
+
+**定义:**
+
+```java
+public Pointer CP_Port_OpenBtBle(String address, int autoreplymode);
+// 通过BLE连接蓝牙打印机
+//
+// address
+// 打印机地址
+// 例如:"01:02:03:04:05:06"
+//
+// autoreplymode
+// 0 不开启自动回传模式
+// 1 开启自动回传模式
+// 注意:
+// 仅部分机型支持自动回传模式,是否支持请询问卖家
+// 启动自动回传模式之后,打印机会自动回传状态
+// 不启动则无法自动获取打印机状态
+//
+// return
+// 返回打开的端口句柄。非零表示打开成功,零表示打开失败。
+//
+// remarks
+// only for android,ios,macos
+```
+
+---
+
+#### CP_Port_WiFiP2P_Connect
+
+通过WiFi P2P连接打印机
+
+**定义:**
+
+```java
+public int CP_Port_WiFiP2P_Connect(String device_address, int timeout);
+// 通过WiFi P2P连接打印机
+//
+// address
+// 打印机地址
+// 例如:"01:02:03:04:05:06"
+//
+// timeout
+// 连接超时毫秒时间,建议填10000
+//
+// return
+// 返回打印机的IP地址(网络字节序)。
+// 非零表示连接成功,零表示连接失败。
+//
+// remarks
+// only for android
+```
+
+---
+
+#### CP_Port_WiFiP2P_Disconnect
+
+断开WiFi P2P连接
+
+**定义:**
+
+```java
+public void CP_Port_WiFiP2P_Disconnect();
+```
+
+---
+
+#### CP_Port_WiFiP2P_IsConnected
+
+WiFi P2P是否已连接
+
+**定义:**
+
+```java
+public boolean CP_Port_WiFiP2P_IsConnected();
+// WiFi P2P是否已连接
+//
+// return
+// 如果已连接,则返回true
+// 如果未连接,则返回false
+```
+
+---
+
+#### CP_Port_Write
+
+向端口写入数据
+
+**定义:**
+
+```java
+public int CP_Port_Write(Pointer handle, byte[] buffer, int count, int timeout);
+// 向端口写入数据
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// buffer
+// 要写入的数据
+//
+// count
+// 要写入的长度
+//
+// timeout
+// 写入超时毫秒
+//
+// return
+// 返回写入的字节数,-1表示写入失败
+```
+
+---
+
+#### CP_Port_Read
+
+从端口接收数据
+
+**定义:**
+
+```java
+public int CP_Port_Read(Pointer handle, byte[] buffer, int count, int timeout);
+// 从端口接收数据
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// buffer
+// 接收数据的缓冲区
+//
+// count
+// 要接收的数据长度
+//
+// timeout
+// 读取超时毫秒
+//
+// return
+// 返回读取的字节数,-1表示失败
+```
+
+---
+
+#### CP_Port_ReadUntilByte
+
+从端口接收数据
+
+**定义:**
+
+```java
+public int CP_Port_ReadUntilByte(Pointer handle, byte[] buffer, int count, int timeout, byte breakByte);
+// 从端口接收数据
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// buffer
+// 接收数据的缓冲区
+//
+// count
+// 要接收的数据长度
+//
+// timeout
+// 读取超时毫秒
+//
+// breakByte
+// 结束读取字符
+//
+// return
+// 返回读取的字节数,-1表示失败
+```
+
+---
+
+#### CP_Port_Available
+
+返回可读取的字节数
+
+**定义:**
+
+```java
+public int CP_Port_Available(Pointer handle);
+// 返回可读取的字节数
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回可读取的字节数,-1表示失败
+```
+
+---
+
+#### CP_Port_SkipAvailable
+
+忽略接收缓冲区的数据
+
+**定义:**
+
+```java
+public boolean CP_Port_SkipAvailable(Pointer handle);
+// 忽略接收缓冲区的数据
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Port_IsConnectionValid
+
+连接是否有效
+
+**定义:**
+
+```java
+public boolean CP_Port_IsConnectionValid(Pointer handle);
+// 连接是否有效
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 如果端口已打开,且状态持续更新,则返回true
+// 如果端口未打开,已关闭,或状态超过6秒未更新,则返回false
+```
+
+---
+
+#### CP_Port_IsOpened
+
+检查端口是否打开
+
+**定义:**
+
+```java
+public boolean CP_Port_IsOpened(Pointer handle);
+// 检查端口是否打开
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 如果端口已打开,且连接未断开未关闭,则返回true
+// 如果端口未打开,或连接已断开已关闭,则返回false
+```
+
+---
+
+#### CP_Port_Close
+
+关闭端口
+
+**定义:**
+
+```java
+public boolean CP_Port_Close(Pointer handle);
+// 关闭端口
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+### 获取打印机信息函数
+
+CP_Printer_GetPrinterResolutionInfo
+
+获取打印机分辨率信息
+
+定义
+
+public boolean CP_Printer_GetPrinterResolutionInfo(Pointer handle, IntByReference width_mm, IntByReference
+
+height_mm, IntByReference dots_per_mm);
+
+// 获取打印机分辨率信息
+
+//
+
+// handle
+
+// 端口句柄,由OpenXXX返回
+
+//
+
+// width_mm
+
+// 标签最大宽度
+
+//
+
+// height_mm
+
+// 标签最大高度
+
+//
+
+// dots_per_mm
+
+// 每毫米打印点数
+
+//
+
+// return
+
+// true on success.
+
+// false on failed.
+
+#### CP_Printer_GetPrinterFirmwareVersion
+
+获取打印机固件版本
+
+**定义:**
+
+```java
+public class CP_Printer_GetPrinterFirmwareVersion_Helper {
+public static String GetPrinterFirmwareVersion(Pointer handle)
+}
+```
+
+---
+
+#### CP_Printer_GetPrinterStatusInfo
+
+获取打印机自动回传的状态
+
+**定义:**
+
+```java
+public boolean CP_Printer_GetPrinterStatusInfo(Pointer handle, LongByReference printer_error_status,
+```
+
+LongByReference printer_info_status, LongByReference timestamp_ms);
+
+```java
+// 获取打印机自动回传的状态
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// printer_error_status
+// 打印机错误状态
+//
+// printer_info_status
+// 打印机信息状态
+//
+// timestamp_ms
+// 时间戳
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_GetPrinterReceivedInfo
+
+获取打印机已接收字节数
+
+**定义:**
+
+```java
+public boolean CP_Printer_GetPrinterReceivedInfo(Pointer handle, IntByReference printer_received_byte_count,
+```
+
+LongByReference timestamp_ms);
+
+```java
+// 获取打印机已接收字节数
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// printer_received_byte_count
+// 打印机已接收字节数
+//
+// timestamp_ms
+// 时间戳
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_GetPrinterPrintedInfo
+
+获取打印机已打印的单据号
+
+**定义:**
+
+```java
+public boolean CP_Printer_GetPrinterPrintedInfo(Pointer handle, IntByReference printer_printed_page_id,
+```
+
+LongByReference timestamp_ms);
+
+```java
+// 获取打印机已打印的单据号
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// printer_printed_page_id
+// 打印机已打印的单据号
+//
+// timestamp_ms
+// 时间戳
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_GetPrinterLabelPositionAdjustmentInfo
+
+获取打印机标签位置微调信息
+
+**定义:**
+
+```java
+public boolean CP_Printer_GetPrinterLabelPositionAdjustmentInfo(Pointer handle, DoubleByReference
+```
+
+label_print_position_adjustment, DoubleByReference label_tear_position_adjustment, LongByReference
+
+timestamp_ms);
+
+```java
+// 获取打印机标签位置微调信息
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// label_print_position_adjustment
+// 打印机标签打印位置微调
+//
+// label_tear_position_adjustment
+// 打印机标签撕纸位置微调
+//
+// timestamp_ms
+// 时间戳
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_SetPrinterLabelPositionAdjustmentInfo
+
+设置标签打印位置和撕纸位置微调
+
+**定义:**
+
+```java
+public boolean CP_Printer_SetPrinterLabelPositionAdjustmentInfo(Pointer handle, double
+```
+
+label_print_position_adjustment, double label_tear_position_adjustment);
+
+```java
+// 设置标签打印位置和撕纸位置微调
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// label_print_position_adjustment
+// 标签打印位置微调mm(微调不超过±4mm)
+//
+// label_tear_position_adjustment
+// 标签撕纸位置微调mm(微调不超过±4mm)
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Printer_ClearPrinterBuffer
+
+实时清除打印机缓存
+
+**定义:**
+
+```java
+public boolean CP_Printer_ClearPrinterBuffer(Pointer handle);
+// 实时清除打印机缓存
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+#### CP_Printer_ClearPrinterError
+
+实时清除打印机错误
+
+**定义:**
+
+```java
+public boolean CP_Printer_ClearPrinterError(Pointer handle);
+// 实时清除打印机错误
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// true on success.
+// false on failed.
+```
+
+---
+
+### 票据函数
+
+CP_Pos_QueryRTStatus
+
+查询打印机实时状态
+
+定义
+
+public int CP_Pos_QueryRTStatus(Pointer handle, int timeout);
+
+// 查询打印机实时状态
+
+// 如果是支持自动回传的机型,状态会自动回传,不需要使用本指令查询
+
+// 由于实时状态指令,无校验,无法保证结果一定正确
+
+//
+
+// handle
+
+// 端口句柄,由OpenXXX返回
+
+//
+
+// timeout
+
+// 超时毫秒时间。
+
+// 查询等待时间不超过此时间。
+
+//
+
+// return
+
+// 返回值仅指示指令是否成功。成功返回实时状态,失败返回0。
+
+// 详细状态请查看CP_RTSTATUS_XXX,如果状态定义与实际机型不符,以实测为准。
+
+#### CP_Pos_QueryPrintResult
+
+查询前面内容的打印结果
+
+**定义:**
+
+```java
+public boolean CP_Pos_QueryPrintResult(Pointer handle, int timeout);
+// 查询前面内容的打印结果
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// timeout
+// 超时毫秒时间。
+// 查询打印结果等待时间不超过此时间。
+//
+// return
+// 返回值仅指示指令是否打印成功。返回true表示打印成功,返回false表示打印失败或查询失败。
+```
+
+---
+
+#### CP_Pos_KickOutDrawer
+
+开钱箱(产生钱箱脉冲)
+
+**定义:**
+
+```java
+public boolean CP_Pos_KickOutDrawer(Pointer handle, int nDrawerIndex, int nHighLevelTime, int nLowLevelTime);
+// 开钱箱(产生钱箱脉冲)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nDrawerIndex
+// 钱箱编号,各值说明如下
+// 编号 说明
+// 0 钱箱引脚2
+// 1 钱箱引脚5
+//
+// nHighLevelTime
+// 高电平毫秒时间
+//
+// nLowLevelTime
+// 低电平毫秒时间
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_Beep
+
+蜂鸣器鸣叫
+
+**定义:**
+
+```java
+public boolean CP_Pos_Beep(Pointer handle, int nBeepCount, int nBeepMs);
+// 蜂鸣器鸣叫
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nBeepCount
+// 鸣叫次数
+//
+// nBeepMs
+// 蜂鸣毫秒时间,取值范围[100,900]。取整到百毫秒。
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_FeedAndHalfCutPaper
+
+走纸到切刀位置并半切纸
+
+**定义:**
+
+```java
+public boolean CP_Pos_FeedAndHalfCutPaper(Pointer handle);
+// 走纸到切刀位置并半切纸
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_FullCutPaper
+
+切刀全切
+
+**定义:**
+
+```java
+public boolean CP_Pos_FullCutPaper(Pointer handle);
+// 切刀全切
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_HalfCutPaper
+
+切刀半切
+
+**定义:**
+
+```java
+public boolean CP_Pos_HalfCutPaper(Pointer handle);
+// 切刀半切
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_FeedLine
+
+打印机进纸指定行数
+
+**定义:**
+
+```java
+public boolean CP_Pos_FeedLine(Pointer handle, int numLines);
+// 打印机进纸指定行数
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// numLines
+// 要进的行数
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_FeedDot
+
+打印机进纸指定点数
+
+**定义:**
+
+```java
+public boolean CP_Pos_FeedDot(Pointer handle, int numDots);
+// 打印机进纸指定点数
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// numDots
+// 要进的点数
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintSelfTestPage
+
+打印机打印自检页
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintSelfTestPage(Pointer handle);
+// 打印机打印自检页
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintText
+
+打印文本
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintText(Pointer handle, String str);
+// 打印文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintTextInUTF8
+
+打印文本
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintTextInUTF8(Pointer handle, WString str);
+// 打印文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为UTF8编码发送。
+```
+
+---
+
+#### CP_Pos_PrintTextInGBK
+
+打印文本
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintTextInGBK(Pointer handle, WString str);
+// 打印文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为GBK编码发送。
+```
+
+---
+
+#### CP_Pos_PrintTextInBIG5
+
+打印文本
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintTextInBIG5(Pointer handle, WString str);
+// 打印文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为BIG5编码发送。
+```
+
+---
+
+#### CP_Pos_PrintTextInShiftJIS
+
+打印文本
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintTextInShiftJIS(Pointer handle, WString str);
+// 打印文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为ShiftJIS编码发送。
+```
+
+---
+
+#### CP_Pos_PrintTextInEUCKR
+
+打印文本
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintTextInEUCKR(Pointer handle, WString str);
+// 打印文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为EUCKR编码发送。
+```
+
+---
+
+#### CP_Pos_PrintBarcode
+
+打印一维条码
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintBarcode(Pointer handle, int nBarcodeType, String str);
+// 打印一维条码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nBarcodeType
+// 标识条码类型
+// 各值定义如下:
+// 值 类型
+// 0x41 UPC-A
+// 0x42 UPC-E
+// 0x43 EAN13
+// 0x44 EAN8
+// 0x45 CODE39
+// 0x46 ITF
+// 0x47 CODABAR
+// 0x48 CODE93
+// 0x49 CODE128
+//
+// str
+// 要打印的条码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintBarcode_Code128Auto
+
+打印CODE128条码,该函数自动切换编码,以便节省空间
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintBarcode_Code128Auto(Pointer handle, String str);
+// 打印CODE128条码,该函数自动切换编码,以便节省空间
+// 正常情况下,请不要使用这个函数进行打印CODE128码
+// 这个函数主要用于兼容部分老款机型
+// 新款机型默认已经是支持自动切换编码的
+// 新款机型使用这个函数是无法打印条码的
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的条码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintQRCode
+
+打印QR码
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintQRCode(Pointer handle, int nVersion, int nECCLevel, String str);
+// 打印QR码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nVersion
+// 指定字符版本。取值范围:[0,16]。
+// 当 version 为 0 时,打印机根据字符串长度自动计算版本号。
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[1, 4]。
+// 各值定义如下:
+// ECC 纠错等级
+// 1 L:7%,低纠错,数据多。
+// 2 M:15%,中纠错
+// 3 Q:优化纠错
+// 4 H:30%,最高纠错,数据少。
+//
+// str
+// 要打印的QR码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintQRCodeUseEpsonCmd
+
+打印QR码
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintQRCodeUseEpsonCmd(Pointer handle, int nQRCodeUnitWidth, int nECCLevel, String str);
+// 打印QR码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nQRCodeUnitWidth
+// QRCode 码码块宽度,取值范围:[1, 16]。
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[1, 4]。
+// 各值定义如下:
+// ECC 纠错等级
+// 1 L:7%,低纠错,数据多。
+// 2 M:15%,中纠错
+// 3 Q:优化纠错
+// 4 H:30%,最高纠错,数据少。
+//
+// str
+// 要打印的QR码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintQRCodeUseImageCmd
+
+打印QR码(以图片指令打印二维码,可用于不支持二维码指令的机型)
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintQRCodeUseImageCmd(Pointer handle, String str, int nVersion, int nQRCodeUnitWidth,
+```
+
+int nECCLevel, int compression_method);
+
+```java
+// 打印QR码(以图片指令打印二维码,可用于不支持二维码指令的机型)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// str
+// 要打印的QR码
+//
+// nVersion
+// 指定字符版本。取值范围:[0,16]。
+// 当 version 为 0 时,打印机根据字符串长度自动计算版本号。
+//
+// nQRCodeUnitWidth
+// QRCode 码码块宽度,取值范围:[1, 16]。
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[1, 4]。
+// 各值定义如下:
+// ECC 纠错等级
+// 1 L:7%,低纠错,数据多。
+// 2 M:15%,中纠错
+// 3 Q:优化纠错
+// 4 H:30%,最高纠错,数据少。
+//
+// compression_method
+// 最终打印数据的压缩方式,各值定义如下
+// 值 定义
+// 0 不压缩
+// 1 一级压缩
+// 2 二级压缩
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintDoubleQRCode
+
+打印两个QR码
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintDoubleQRCode(Pointer handle, int nQRCodeUnitWidth, int nQR1Position, int
+```
+
+nQR1Version, int nQR1ECCLevel, String strQR1, int nQR2Position, int nQR2Version, int nQR2ECCLevel, String strQR2);
+
+```java
+// 打印两个QR码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nQRCodeUnitWidth
+// QRCode 码码块宽度,取值范围:[1, 8]。
+//
+// nQR1Position
+// nQR2Position
+// QRCode position
+//
+// nQR1Version
+// nQR2Version
+// 指定字符版本。取值范围:[0,16]。
+// 当 version 为 0 时,打印机根据字符串长度自动计算版本号。
+//
+// nQR1ECCLevel
+// nQR2ECCLevel
+// 指定纠错等级。取值范围:[1, 4]。
+// 各值定义如下:
+// ECC 纠错等级
+// 1 L:7%,低纠错,数据多。
+// 2 M:15%,中纠错
+// 3 Q:优化纠错
+// 4 H:30%,最高纠错,数据少。
+//
+// strQR1
+// strQR2
+// 要打印的QR码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintPDF417BarcodeUseEpsonCmd
+
+打印PDF417条码
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintPDF417BarcodeUseEpsonCmd(Pointer handle, int columnCount, int rowCount, int
+```
+
+unitWidth, int rowHeight, int nECCLevel, int dataProcessingMode, String str);
+
+```java
+// 打印PDF417条码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// columnCount
+// 列数,取值范围[0,30]
+//
+// rowCount
+// 行数,取值范围0,[3,90]
+//
+// unitWidth
+// 模块单元宽度,取值范围[2,8]
+//
+// rowHeight
+// 行高,取值范围[2,8]
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[0,8]。
+//
+// dataProcessingMode
+// 数据处理模式。0选择标准PDF417,1选择截断PDF417。
+//
+// str
+// 要打印的PDF417码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintRasterImageFromFile
+
+打印图片
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintRasterImageFromFile(Pointer handle, int dstw, int dsth, String pszFile, int
+```
+
+binaryzation_method, int compression_method);
+
+```java
+// 打印图片
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// dstw
+// 要打印的宽度
+//
+// dsth
+// 要打印的高度
+//
+// pszFile
+// 图片的路径
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法。具体效果请测试查看。
+//
+// compression_method
+// 最终打印数据的压缩方式,各值定义如下
+// 值 定义
+// 0 不压缩
+// 1 一级压缩
+// 2 二级压缩
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintRasterImageFromData
+
+打印图片(图片可由文件读取)
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintRasterImageFromData(Pointer handle, int dstw, int dsth, byte[] data, int data_size, int
+```
+
+binaryzation_method, int compression_method);
+
+```java
+// 打印图片(图片可由文件读取)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// dstw
+// 要打印的宽度
+//
+// dsth
+// 要打印的高度
+//
+// data
+// 图片数据。
+//
+// data_size
+// 图片数据长度
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法。具体效果请测试查看。
+//
+// compression_method
+// 最终打印数据的压缩方式,各值定义如下
+// 值 定义
+// 0 不压缩
+// 1 一级压缩
+// 2 二级压缩
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+也可以使用下面的函数
+
+```java
+public class CP_Pos_PrintRasterImageFromData_Helper {
+public static boolean PrintRasterImageFromBitmap(Pointer handle, int dstw, int dsth, Bitmap bitmap, int
+```
+
+binaryzation_method, int compression_method)
+
+```java
+}
+```
+
+---
+
+#### CP_Pos_PrintRasterImageFromPixels
+
+打印图片像素数据
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintRasterImageFromPixels(Pointer handle, byte[] img_data, int img_datalen, int img_width,
+```
+
+int img_height, int img_stride, int img_format, int binaryzation_method, int compression_method);
+
+```java
+// 打印图片像素数据
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// img_data
+// 图片的像素数据。
+//
+// img_datalen
+// 图片的像素数据字节数。
+//
+// img_width
+// 图片的像素宽度。
+//
+// img_height
+// 图片的像素高度。
+//
+// img_stride
+// 图片水平跨度。表示每行字节数。
+//
+// img_format
+// 图片像素数据格式,各值定义如下
+// 值 定义
+// 1 mono
+// 2 monolsb
+// 3 gray
+// 4 r.g.b in byte-ordered
+// 5 b.g.r in byte-ordered
+// 6 a.r.g.b in byte-ordered
+// 7 r.g.b.a in byte-ordered
+// 8 a.b.g.r in byte-ordered
+// 9 b.g.r.a in byte-ordered
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法。具体效果请测试查看。
+//
+// compression_method
+```
+
+---
+
+#### CP_Pos_PrintHorizontalLine
+
+打印一条水平线
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintHorizontalLine(Pointer handle, int nLineStartPosition, int nLineEndPosition);
+// 打印一条水平线
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nLineStartPosition
+// 线段起点位置
+//
+// nLineEndPosition
+// 线段终点位置
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintHorizontalLineSpecifyThickness
+
+打印一条水平线
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintHorizontalLineSpecifyThickness(Pointer handle, int nLineStartPosition, int
+```
+
+nLineEndPosition, int nLineThickness);
+
+```java
+// 打印一条水平线
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nLineStartPosition
+// 线段起点位置
+//
+// nLineEndPosition
+// 线段终点位置
+//
+// nLineThickness
+// 线段粗细
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_PrintMultipleHorizontalLinesAtOneRow
+
+同一行上打印多条水平线,连续调用可打印曲线
+
+**定义:**
+
+```java
+public boolean CP_Pos_PrintMultipleHorizontalLinesAtOneRow(Pointer handle, int nLineCount, int[]
+```
+
+pLineStartPosition, int[] pLineEndPosition);
+
+```java
+// 同一行上打印多条水平线,连续调用可打印曲线
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nLineCount
+// 线段条数
+//
+// pLineStartPosition
+// 线段起点位置
+//
+// pLineEndPosition
+// 线段终点位置
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_ResetPrinter
+
+复位打印机,清除设置
+
+**定义:**
+
+```java
+public boolean CP_Pos_ResetPrinter(Pointer handle);
+// 复位打印机,清除设置
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetPrintSpeed
+
+设置打印速度(部分机型支持)
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetPrintSpeed(Pointer handle, int nSpeed);
+// 设置打印速度(部分机型支持)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nSpeed
+// 打印速度,单位毫米每秒
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetPrintDensity
+
+设置打印浓度(部分机型支持)
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetPrintDensity(Pointer handle, int nDensity);
+// 设置打印浓度(部分机型支持)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nDensity
+// 设置打印浓度[0,15]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetSingleByteMode
+
+设置打印机为单字节编码
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetSingleByteMode(Pointer handle);
+// 设置打印机为单字节编码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetCharacterSet
+
+设置打印机字符集
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetCharacterSet(Pointer handle, int nCharacterSet);
+// 设置打印机字符集
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nCharacterSet
+// 打印机字符集,范围[0,15]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetCharacterCodepage
+
+设置字符代码页
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetCharacterCodepage(Pointer handle, int nCharacterCodepage);
+// 设置字符代码页
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nCharacterCodepage
+// 字符代码页,范围[0,255]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetMultiByteMode
+
+设置打印机为多字节编码
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetMultiByteMode(Pointer handle);
+// 设置打印机为多字节编码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetMultiByteEncoding
+
+设置打印机多字节编码
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetMultiByteEncoding(Pointer handle, int nEncoding);
+// 设置打印机多字节编码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nEncoding
+// 多字节编码,各值定义如下:
+// 值 定义
+// 0 GBK
+// 1 UTF8
+// 3 BIG5
+// 4 SHIFT-JIS
+// 5 EUC-KR
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetMovementUnit
+
+设置打印移动单位
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetMovementUnit(Pointer handle, int nHorizontalMovementUnit, int nVerticalMovementUnit);
+// 设置打印移动单位
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nHorizontalMovementUnit
+// 水平移动单位
+//
+// nVerticalMovementUnit
+// 垂直移动单位
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 移动单位设置为200,则1mm=8点。
+```
+
+---
+
+#### CP_Pos_SetPrintAreaLeftMargin
+
+设置打印区域左边空白
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetPrintAreaLeftMargin(Pointer handle, int nLeftMargin);
+// 设置打印区域左边空白
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nLeftMargin
+// 左边空白
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetPrintAreaWidth
+
+设置打印区域宽度
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetPrintAreaWidth(Pointer handle, int nWidth);
+// 设置打印区域宽度
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nWidth
+// 打印区域宽度
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetHorizontalAbsolutePrintPosition
+
+设置横向绝对打印位置
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetHorizontalAbsolutePrintPosition(Pointer handle, int nPosition);
+// 设置横向绝对打印位置
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nPosition
+// 打印位置
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetHorizontalRelativePrintPosition
+
+设置横向相对打印位置
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetHorizontalRelativePrintPosition(Pointer handle, int nPosition);
+// 设置横向相对打印位置
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nPosition
+// 打印位置
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetVerticalAbsolutePrintPosition
+
+设置纵向绝对打印位置,仅在页模式下有效。
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetVerticalAbsolutePrintPosition(Pointer handle, int nPosition);
+// 设置纵向绝对打印位置,仅在页模式下有效。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nPosition
+// 打印位置
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetVerticalRelativePrintPosition
+
+设置纵向相对打印位置,仅在页模式下有效。
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetVerticalRelativePrintPosition(Pointer handle, int nPosition);
+// 设置纵向相对打印位置,仅在页模式下有效。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nPosition
+// 打印位置
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetAlignment
+
+设置打印对齐方式
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetAlignment(Pointer handle, int nAlignment);
+// 设置打印对齐方式
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nAlignment
+// 打印对齐方式,各值定义如下:
+// 值 定义
+// 0 左对齐
+// 1 中对齐
+// 2 右对齐
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextScale
+
+设置文本放大倍数
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextScale(Pointer handle, int nWidthScale, int nHeightScale);
+// 设置文本放大倍数
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nWidthScale
+// 宽度放大倍数
+//
+// nHeightScale
+// 高度放大倍数
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetAsciiTextFontType
+
+设置英文字符字体类型
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetAsciiTextFontType(Pointer handle, int nFontType);
+// 设置英文字符字体类型
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nFontType
+// 英文字符字体类型,各值定义如下:
+// 值 定义
+// 0 字型A(12x24)
+// 1 字型B(9x17)
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextBold
+
+设置文本加粗打印
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextBold(Pointer handle, int nBold);
+// 设置文本加粗打印
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nBold
+// 是否加粗,各值定义如下:
+// 值 定义
+// 0 不加粗
+// 1 加粗
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextUnderline
+
+设置文本下划线
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextUnderline(Pointer handle, int nUnderline);
+// 设置文本下划线
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nUnderline
+// 文本下划线,各值定义如下:
+// 值 定义
+// 0 无下划线
+// 1 1点下划线
+// 2 2点下划线
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextUpsideDown
+
+设置文本倒置打印
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextUpsideDown(Pointer handle, int nUpsideDown);
+// 设置文本倒置打印
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nUpsideDown
+// 倒置打印,各值定义如下:
+// 值 定义
+// 0 不倒置打印
+// 1 倒置打印
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextWhiteOnBlack
+
+设置黑白反显
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextWhiteOnBlack(Pointer handle, int nWhiteOnBlack);
+// 设置黑白反显
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nWhiteOnBlack
+// 黑白反显,各值定义如下:
+// 值 定义
+// 0 不黑白反显
+// 1 黑白反显
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextRotate
+
+设置文本旋转90度打印
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextRotate(Pointer handle, int nRotate);
+// 设置文本旋转90度打印
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nRotate
+// 旋转打印,各值定义如下:
+// 值 定义
+// 0 不旋转打印
+// 1 旋转90度打印
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetTextLineHeight
+
+设置行高
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetTextLineHeight(Pointer handle, int nLineHeight);
+// 设置行高
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nLineHeight
+// 行高,范围[1,255]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetAsciiTextCharRightSpacing
+
+设置ASCII字符右边空白
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetAsciiTextCharRightSpacing(Pointer handle, int nSpacing);
+// 设置ASCII字符右边空白
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nSpacing
+// 右边空白,范围[1,255]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetKanjiTextCharSpacing
+
+设置汉字文本字符左边空白和右边空白
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetKanjiTextCharSpacing(Pointer handle, int nLeftSpacing, int nRightSpacing);
+// 设置汉字文本字符左边空白和右边空白
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nLeftSpacing
+// 右边空白,范围[1,255]
+//
+// nRightSpacing
+// 右边空白,范围[1,255]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetBarcodeUnitWidth
+
+设置条码和二维码单元宽度
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetBarcodeUnitWidth(Pointer handle, int nBarcodeUnitWidth);
+// 设置条码和二维码单元宽度
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nBarcodeUnitWidth
+// 条码单元宽度,取值范围:[1,6]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetBarcodeHeight
+
+设置条码高度
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetBarcodeHeight(Pointer handle, int nBarcodeHeight);
+// 设置条码高度
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nBarcodeHeight
+// 定义条码高度。取值范围:[1,255]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetBarcodeReadableTextFontType
+
+设置条码可读字符字体类型
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetBarcodeReadableTextFontType(Pointer handle, int nFontType);
+// 设置条码可读字符字体类型
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nFontType
+// 指定可读字符的字体类型,各值定义如下:
+// 值 类型
+// 0 标准ASCII
+// 1 压缩ASCII
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Pos_SetBarcodeReadableTextPosition
+
+设置条码可读字符打印位置
+
+**定义:**
+
+```java
+public boolean CP_Pos_SetBarcodeReadableTextPosition(Pointer handle, int nTextPosition);
+// 设置条码可读字符打印位置
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nTextPosition
+// 条码可读字符位置,取值范围:[0, 3].
+// 各值定义如下:
+// 值 定义
+// 0 不显示可读字符
+// 1 在条码下方显示可读字符
+// 2 在条码上方显示可读字符
+// 3 在条码上方和条码下方显示可读字符
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+### 页模式函数
+
+CP_Page_SelectPageMode
+
+选择页模式
+
+定义
+
+public boolean CP_Page_SelectPageMode(Pointer handle);
+
+// 选择页模式
+
+//
+
+// handle
+
+// 端口句柄,由OpenXXX返回
+
+//
+
+// return
+
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+
+#### CP_Page_SelectPageModeEx
+
+选择页模式,并设置移动单位和页面大小,还会设置其他一系列参数为默认值
+
+**定义:**
+
+```java
+public boolean CP_Page_SelectPageModeEx(Pointer handle, int nHorizontalMovementUnit, int
+```
+
+nVerticalMovementUnit, int x, int y, int width, int height);
+
+```java
+// 选择页模式,并设置移动单位和页面大小,还会设置其他一系列参数为默认值
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nHorizontalMovementUnit
+// 水平移动单位
+//
+// nVerticalMovementUnit
+// 垂直移动单位
+//
+// x
+// 横向起始位置
+//
+// y
+// 纵向起始位置
+//
+// width
+// 打印区域宽度
+//
+// height
+// 打印区域高度
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_ExitPageMode
+
+退出页模式并回到标准模式
+
+**定义:**
+
+```java
+public boolean CP_Page_ExitPageMode(Pointer handle);
+// 退出页模式并回到标准模式
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_PrintPage
+
+页模式下打印内容
+
+**定义:**
+
+```java
+public boolean CP_Page_PrintPage(Pointer handle);
+// 页模式下打印内容
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_ClearPage
+
+页模式下清除页面
+
+**定义:**
+
+```java
+public boolean CP_Page_ClearPage(Pointer handle);
+// 页模式下清除页面
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_SetPageArea
+
+页模式下设置页区域,页面最高2000点(1mm8点)
+
+**定义:**
+
+```java
+public boolean CP_Page_SetPageArea(Pointer handle, int x, int y, int width, int height);
+// 页模式下设置页区域,页面最高2000点(1mm8点)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向起始位置
+//
+// y
+// 纵向起始位置
+//
+// width
+// 打印区域宽度
+//
+// height
+// 打印区域高度
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_SetPageDrawDirection
+
+页模式下设置打印方向
+
+**定义:**
+
+```java
+public boolean CP_Page_SetPageDrawDirection(Pointer handle, int nDirection);
+// 页模式下设置打印方向
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nDirection
+// 打印区域方向,各值定义如下:
+// 0 从左到右
+// 1 从下到上
+// 2 从右到左
+// 3 从上到下
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawRect
+
+页模式下画矩形
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawRect(Pointer handle, int x, int y, int width, int height, int color);
+// 页模式下画矩形
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// width
+// 矩形宽度
+//
+// height
+// 矩形高度
+//
+// color
+// 矩形颜色,0是白色,1是黑色
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawBox
+
+页模式下画矩形框
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawBox(Pointer handle, int x, int y, int width, int height, int borderwidth, int bordercolor);
+// 页模式下画矩形框
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// width
+// 矩形框宽度
+//
+// height
+// 矩形框高度
+//
+// borderwidth
+// 矩形框边框宽度
+//
+// bordercolor
+// 矩形框边框颜色,0是白色,1是黑色
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawText
+
+页模式下画文本
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawText(Pointer handle, int x, int y, String str);
+// 页模式下画文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawTextInUTF8
+
+页模式下画文本
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawTextInUTF8(Pointer handle, int x, int y, WString str);
+// 页模式下画文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为UTF8编码发送。
+```
+
+---
+
+#### CP_Page_DrawTextInGBK
+
+页模式下画文本
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawTextInGBK(Pointer handle, int x, int y, WString str);
+// 页模式下画文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为GBK编码发送。
+```
+
+---
+
+#### CP_Page_DrawTextInBIG5
+
+页模式下画文本
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawTextInBIG5(Pointer handle, int x, int y, WString str);
+// 页模式下画文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为BIG5编码发送。
+```
+
+---
+
+#### CP_Page_DrawTextInShiftJIS
+
+页模式下画文本
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawTextInShiftJIS(Pointer handle, int x, int y, WString str);
+// 页模式下画文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为ShiftJIS编码发送。
+```
+
+---
+
+#### CP_Page_DrawTextInEUCKR
+
+页模式下画文本
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawTextInEUCKR(Pointer handle, int x, int y, WString str);
+// 页模式下画文本
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为EUCKR编码发送。
+```
+
+---
+
+#### CP_Page_DrawBarcode
+
+页模式下打印一维条码
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawBarcode(Pointer handle, int x, int y, int nBarcodeType, String str);
+// 页模式下打印一维条码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// nBarcodeType
+// 标识条码类型
+// 各值定义如下:
+// 值 类型
+// 0x41 UPC-A
+// 0x42 UPC-E
+// 0x43 EAN13
+// 0x44 EAN8
+// 0x45 CODE39
+// 0x46 ITF
+// 0x47 CODABAR
+// 0x48 CODE93
+// 0x49 CODE128
+//
+// str
+// 要打印的条码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawQRCode
+
+页模式下打印QR码
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawQRCode(Pointer handle, int x, int y, int nVersion, int nECCLevel, String str);
+// 页模式下打印QR码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// nVersion
+// 指定字符版本。取值范围:[0,16]。
+// 当 version 为 0 时,打印机根据字符串长度自动计算版本号。
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[1, 4]。
+// 各值定义如下:
+// ECC 纠错等级
+// 1 L:7%,低纠错,数据多。
+// 2 M:15%,中纠错
+// 3 Q:优化纠错
+// 4 H:30%,最高纠错,数据少。
+//
+// str
+// 要打印的QR码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawRasterImageFromFile
+
+页模式下打印图片
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawRasterImageFromFile(Pointer handle, int x, int y, int dstw, int dsth, String pszFile, int
+```
+
+binaryzation_method);
+
+```java
+// 页模式下打印图片
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// dstw
+// 要打印的宽度
+//
+// dsth
+// 要打印的高度
+//
+// pszFile
+// 图片的路径
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法。具体效果请测试查看。
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Page_DrawRasterImageFromData
+
+页模式下打印图片(图片可由文件读取)
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawRasterImageFromData(Pointer handle, int x, int y, int dstw, int dsth, byte[] data, int
+```
+
+data_size, int binaryzation_method);
+
+```java
+// 页模式下打印图片(图片可由文件读取)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// dstw
+// 要打印的宽度
+//
+// dsth
+// 要打印的高度
+//
+// data
+// 图片数据。
+//
+// data_size
+// 图片数据长度
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法,2表示误差扩散法。具体效果请
+```
+
+测试查看。
+
+```java
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+也可以使用下面的函数
+
+```java
+public class CP_Page_DrawRasterImageFromData_Helper {
+public static boolean DrawRasterImageFromBitmap(Pointer handle, int x, int y, int dstw, int dsth, Bitmap bitmap,
+```
+
+int binaryzation_method)
+
+```java
+}
+```
+
+---
+
+#### CP_Page_DrawRasterImageFromPixels
+
+页模式下打印图片像素数据
+
+**定义:**
+
+```java
+public boolean CP_Page_DrawRasterImageFromPixels(Pointer handle, int x, int y, byte[] img_data, int img_datalen, int
+```
+
+img_width, int img_height, int img_stride, int img_format, int binaryzation_method);
+
+```java
+// 页模式下打印图片像素数据
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// img_data
+// 图片的像素数据。
+//
+// img_datalen
+// 图片的像素数据字节数。
+//
+// img_width
+// 图片的像素宽度。
+//
+// img_height
+// 图片的像素高度。
+//
+// img_stride
+// 图片水平跨度。表示每行字节数。
+//
+// img_format
+// 图片像素数据格式,各值定义如下
+// 值 定义
+// 1 mono
+// 2 monolsb
+// 3 gray
+// 4 r.g.b in byte-ordered
+// 5 b.g.r in byte-ordered
+// 6 a.r.g.b in byte-ordered
+// 7 r.g.b.a in byte-ordered
+// 8 a.b.g.r in byte-ordered
+```
+
+---
+
+### 黑标函数
+
+CP_BlackMark_EnableBlackMarkMode
+
+启用黑标模式,重启打印机生效
+
+定义
+
+public boolean CP_BlackMark_EnableBlackMarkMode(Pointer handle);
+
+// 启用黑标模式,重启打印机生效
+
+//
+
+// handle
+
+// 端口句柄,由OpenXXX返回
+
+//
+
+// return
+
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+
+#### CP_BlackMark_DisableBlackMarkMode
+
+禁用黑标模式
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_DisableBlackMarkMode(Pointer handle);
+// 禁用黑标模式
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_BlackMark_SetBlackMarkMaxFindLength
+
+设置黑标最大查找距离(重启仍有效)
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_SetBlackMarkMaxFindLength(Pointer handle, int maxFindLength);
+// 设置黑标最大查找距离(重启仍有效)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// maxFindLength
+// 最大查找距离(maxFindLength x 0.125 毫米)
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_BlackMark_FindNextBlackMark
+
+查找下一个黑标
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_FindNextBlackMark(Pointer handle);
+// 查找下一个黑标
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_BlackMark_SetBlackMarkPaperPrintPosition
+
+黑标模式下,设置起始打印位置的调整值
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_SetBlackMarkPaperPrintPosition(Pointer handle, int position);
+// 黑标模式下,设置起始打印位置的调整值
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// position
+// 大于0则指定为进纸,小于0则指定为退纸。距离为 position x 0.125 毫米。
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_BlackMark_SetBlackMarkPaperCutPosition
+
+黑标模式下,设置切纸位置
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_SetBlackMarkPaperCutPosition(Pointer handle, int position);
+// 黑标模式下,设置切纸位置
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// position
+// 大于0则指定为进纸,小于0则指定为退纸。距离为 position x 0.125 毫米。
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_BlackMark_FullCutBlackMarkPaper
+
+切刀全切
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_FullCutBlackMarkPaper(Pointer handle);
+// 切刀全切
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_BlackMark_HalfCutBlackMarkPaper
+
+切刀半切
+
+**定义:**
+
+```java
+public boolean CP_BlackMark_HalfCutBlackMarkPaper(Pointer handle);
+// 切刀半切
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+### 标签函数
+
+CP_Label_EnableLabelMode
+
+启用标签模式
+
+定义
+
+public boolean CP_Label_EnableLabelMode(Pointer handle);
+
+// 启用标签模式
+
+//
+
+// handle
+
+// 端口句柄,由OpenXXX返回
+
+//
+
+// return
+
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+
+#### CP_Label_DisableLabelMode
+
+关闭标签模式
+
+**定义:**
+
+```java
+public boolean CP_Label_DisableLabelMode(Pointer handle);
+// 关闭标签模式
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_CalibrateLabel
+
+校准标签纸(更换不同规格标签纸,需要校准)
+
+**定义:**
+
+```java
+public boolean CP_Label_CalibrateLabel(Pointer handle);
+// 校准标签纸(更换不同规格标签纸,需要校准)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_FeedLabel
+
+走纸到标签缝隙处
+
+**定义:**
+
+```java
+public boolean CP_Label_FeedLabel(Pointer handle);
+// 走纸到标签缝隙处
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_BackPaperToPrintPosition
+
+打印机退纸到打印位置(适用于标签打印开头定位)
+
+**定义:**
+
+```java
+public boolean CP_Label_BackPaperToPrintPosition(Pointer handle);
+// 打印机退纸到打印位置(适用于标签打印开头定位)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_FeedPaperToTearPosition
+
+打印机进纸到撕纸位置(适用于标签打印结束定位)
+
+**定义:**
+
+```java
+public boolean CP_Label_FeedPaperToTearPosition(Pointer handle);
+// 打印机进纸到撕纸位置(适用于标签打印结束定位)
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_PageBegin
+
+指示一个标签页面的开始,并设置标签页的大小,参考点坐标和页面旋转角度
+
+**定义:**
+
+```java
+public boolean CP_Label_PageBegin(Pointer handle, int x, int y, int width, int height, int rotation);
+// 指示一个标签页面的开始,并设置标签页的大小,参考点坐标和页面旋转角度
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 页面起始点 x 坐标
+//
+// y
+// 页面起始点 y 坐标
+//
+// width
+// 页面页宽
+//
+// height
+// 页面页高
+//
+// rotation
+// 页面旋转。 rotate 的取值范围为{0,1}。为 0,页面不旋转打印,为 1,页面旋转 90 度打印。
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_PagePrint
+
+将标签页上的内容打印到标签纸上
+
+**定义:**
+
+```java
+public boolean CP_Label_PagePrint(Pointer handle, int copies);
+// 将标签页上的内容打印到标签纸上
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// copies
+// 份数 [ 1 - 255 ]
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_DrawText
+
+在标签页面上指定位置绘制文本。只能单行打印。
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawText(Pointer handle, int x, int y, int font, int style, String str);
+// 在标签页面上指定位置绘制文本。只能单行打印。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 定义文本起始位置 x 坐标,取值范围:[0, Page_Width-1]
+//
+// y
+// 定义文本起始位置 y 坐标,取值范围:[0, Page_Height-1]
+//
+// font
+// 选择字体,可以使用24。
+// 带矢量字机型支持16,[20,99]。
+//
+// style
+// 字符风格。
+// 数据位 定义
+// 0 加粗标志位: 置 1 字体加粗,清零则字体不加粗。
+// 1 下划线标志位: 置 1 文本带下划线,清零则无下划线。
+// 2 反白标志位: 置 1 文本反白(黑底白字),清零不反白。
+// 3 删除线标志位: 置 1 文本带删除线,清零则无删除线。
+// [5,4] 旋转标志位: 00 旋转 0° ;
+// 01 旋转 90°;
+// 10 旋转 180°;
+// 11 旋转 270°;
+// [11,8] 字体宽度放大倍数;
+// [15,12] 字体高度放大倍数;
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_DrawTextInUTF8
+
+在标签页面上指定位置绘制文本。只能单行打印。
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawTextInUTF8(Pointer handle, int x, int y, int font, int style, WString str);
+// 在标签页面上指定位置绘制文本。只能单行打印。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 定义文本起始位置 x 坐标,取值范围:[0, Page_Width-1]
+//
+// y
+// 定义文本起始位置 y 坐标,取值范围:[0, Page_Height-1]
+//
+// font
+// 选择字体,可以使用24。
+// 带矢量字机型支持16,[20,99]。
+//
+// style
+// 字符风格。
+// 数据位 定义
+// 0 加粗标志位: 置 1 字体加粗,清零则字体不加粗。
+// 1 下划线标志位: 置 1 文本带下划线,清零则无下划线。
+// 2 反白标志位: 置 1 文本反白(黑底白字),清零不反白。
+// 3 删除线标志位: 置 1 文本带删除线,清零则无删除线。
+// [5,4] 旋转标志位: 00 旋转 0° ;
+// 01 旋转 90°;
+// 10 旋转 180°;
+// 11 旋转 270°;
+// [11,8] 字体宽度放大倍数;
+// [15,12] 字体高度放大倍数;
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为UTF8编码发送。
+```
+
+---
+
+#### CP_Label_DrawTextInGBK
+
+在标签页面上指定位置绘制文本。只能单行打印。
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawTextInGBK(Pointer handle, int x, int y, int font, int style, WString str);
+// 在标签页面上指定位置绘制文本。只能单行打印。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 定义文本起始位置 x 坐标,取值范围:[0, Page_Width-1]
+//
+// y
+// 定义文本起始位置 y 坐标,取值范围:[0, Page_Height-1]
+//
+// font
+// 选择字体,可以使用24。
+// 带矢量字机型支持16,[20,99]。
+//
+// style
+// 字符风格。
+// 数据位 定义
+// 0 加粗标志位: 置 1 字体加粗,清零则字体不加粗。
+// 1 下划线标志位: 置 1 文本带下划线,清零则无下划线。
+// 2 反白标志位: 置 1 文本反白(黑底白字),清零不反白。
+// 3 删除线标志位: 置 1 文本带删除线,清零则无删除线。
+// [5,4] 旋转标志位: 00 旋转 0° ;
+// 01 旋转 90°;
+// 10 旋转 180°;
+// 11 旋转 270°;
+// [11,8] 字体宽度放大倍数;
+// [15,12] 字体高度放大倍数;
+//
+// str
+// 要打印的字符串
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+//
+// remarks
+// 该函数会将数据转为GBK编码发送。
+```
+
+---
+
+#### CP_Label_DrawBarcode
+
+在标签页指定位置绘制一维条码。
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawBarcode(Pointer handle, int x, int y, int nBarcodeType, int nBarcodeTextPrintPosition,
+```
+
+int height, int unitwidth, int rotation, String str);
+
+```java
+// 在标签页指定位置绘制一维条码。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 条码左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// y
+// 条码左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+//
+// nBarcodeType
+// 标识条码类型
+// 各值定义看宏定义
+//
+// nBarcodeTextPrintPosition
+// 条码可读字符位置,取值范围:[0, 3].
+// 各值定义如下:
+// 值 定义
+// 0 不显示可读字符
+// 1 在条码下方显示可读字符
+// 2 在条码上方显示可读字符
+// 3 在条码上方和条码下方显示可读字符
+//
+// height
+// 定义条码高度。
+//
+// unitwidth
+// 定义码块单元宽度。取值范围:[1, 4]。
+//
+// rotation
+// 表示旋转角度。取值范围:[0, 3]。各值定义如下:
+// 值 定义
+// 0 不旋转绘制。
+// 1 旋转 90°绘制。
+// 2 旋转 180°绘制。
+// 3 旋转 270°绘制。
+```
+
+---
+
+#### CP_Label_DrawQRCode
+
+在标签页指定位置绘制QR码。
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawQRCode(Pointer handle, int x, int y, int nVersion, int nECCLevel, int unitwidth, int
+```
+
+rotation, String str);
+
+```java
+// 在标签页指定位置绘制QR码。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 左上角 x 坐标值,取值范围:[0,Page_Width-1]。
+//
+// y
+// 左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+//
+// nVersion
+// 指定字符版本。取值范围:[0,16]。
+// 当 version 为 0 时,打印机根据字符串长度自动计算版本号。
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[1, 4]。
+// 各值定义如下:
+// ECC 纠错等级
+// 1 L:7%,低纠错,数据多。
+// 2 M:15%,中纠错
+// 3 Q:优化纠错
+// 4 H:30%,最高纠错,数据少。
+//
+// unitwidth
+// 定义码块单元宽度。取值范围:[1, 4]。
+//
+// rotation
+// 表示旋转角度。取值范围:[0, 3]。各值定义如下:
+// 值 定义
+// 0 不旋转绘制。
+// 1 旋转 90°绘制。
+// 2 旋转 180°绘制。
+// 3 旋转 270°绘制。
+//
+// str
+// 要打印的QR码
+```
+
+---
+
+#### CP_Label_DrawPDF417Code
+
+在标签页指定位置绘制 PDF417 条码
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawPDF417Code(Pointer handle, int x, int y, int column, int nAspectRatio, int nECCLevel,
+```
+
+int unitwidth, int rotation, String str);
+
+```java
+// 在标签页指定位置绘制 PDF417 条码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// y
+// 左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+//
+// column
+// ColNum 为列数,表述每行容纳多少码字。一个码字为 17*UnitWidth 个点。行数由打印机自动产生,行数
+```
+
+范围限定为 3~90。ColNum 的取值范围:[1,30]。
+
+```java
+//
+// nECCLevel
+// 指定纠错等级。取值范围:[0, 8]。
+// 纠错等级取值 纠错码数 可存资料量(字节)
+// 0 2 1108
+// 1 4 1106
+// 2 8 1101
+// 3 16 1092
+// 4 32 1072
+// 5 64 1024
+// 6 128 957
+// 7 256 804
+// 8 512 496
+//
+// unitwidth
+// 定义码块单元宽度。取值范围:[1, 3]。
+//
+// rotation
+// 表示旋转角度。取值范围:[0, 3]。各值定义如下:
+// 值 定义
+// 0 不旋转绘制。
+// 1 旋转 90°绘制。
+// 2 旋转 180°绘制。
+```
+
+---
+
+#### CP_Label_DrawImageFromFile
+
+在标签页指定位置绘制位图
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawImageFromFile(Pointer handle, int x, int y, int dstw, int dsth, String pszFile, int
+```
+
+binaryzation_method, int compression_method);
+
+```java
+// 在标签页指定位置绘制位图
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// y
+// 左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+//
+// dstw
+// 要打印的宽度
+//
+// dsth
+// 要打印的高度
+//
+// pszFile
+// 图片的路径
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法。具体效果请测试查看。
+//
+// compression_method
+// 最终打印数据的压缩方式,各值定义如下
+// 值 定义
+// 0 不压缩
+// 1 一级压缩
+// 2 二级压缩
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_DrawImageFromData
+
+在标签页指定位置绘制位图
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawImageFromData(Pointer handle, int x, int y, int dstw, int dsth, byte[] data, int data_size,
+```
+
+int binaryzation_method, int compression_method);
+
+```java
+// 在标签页指定位置绘制位图
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// y
+// 左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+//
+// dstw
+// 要打印的宽度
+//
+// dsth
+// 要打印的高度
+//
+// data
+// 图片数据。
+//
+// data_size
+// 图片数据长度
+//
+// binaryzation_method
+// 图片二值化算法。0表示抖动算法,1表示阀值算法,2表示误差扩散法。具体效果请测试查看。
+//
+// compression_method
+// 最终打印数据的压缩方式,各值定义如下
+// 值 定义
+// 0 不压缩
+// 1 一级压缩
+// 2 二级压缩
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+也可以使用下面的函数
+
+---
+
+#### CP_Label_DrawImageFromPixels
+
+在标签页指定位置绘制位图
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawImageFromPixels(Pointer handle, int x, int y, byte[] img_data, int img_datalen, int
+```
+
+img_width, int img_height, int img_stride, int img_format, int binaryzation_method, int compression_method);
+
+```java
+// 在标签页指定位置绘制位图
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 左上角 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// y
+// 左上角 y 坐标值,取值范围:[0, Page_Height-1]。
+//
+// img_data
+// 图片的像素数据。
+//
+// img_datalen
+// 图片的像素数据字节数。
+//
+// img_width
+// 图片的像素宽度。
+//
+// img_height
+// 图片的像素高度。
+//
+// img_stride
+// 图片水平跨度。表示每行字节数。
+//
+// img_format
+// 图片像素数据格式,各值定义如下
+// 值 定义
+// 1 mono
+// 2 monolsb
+// 3 gray
+// 4 r.g.b in byte-ordered
+// 5 b.g.r in byte-ordered
+// 6 a.r.g.b in byte-ordered
+// 7 r.g.b.a in byte-ordered
+// 8 a.b.g.r in byte-ordered
+```
+
+---
+
+#### CP_Label_DrawLine
+
+在标签页指定位置绘制线段
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawLine(Pointer handle, int startx, int starty, int endx, int endy, int linewidth, int linecolor);
+// 在标签页指定位置绘制线段
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// startx
+// 直线段起始点 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// starty
+// 直线段起始点 y 坐标值,取值范围:[0,Page_Height-1]。
+//
+// endx
+// 直线段终止点 x 坐标值,取值范围:[0, Page_Width-1]。
+//
+// endy
+// 直线段终止点 y 坐标值,取值范围:[0,Page_Height-1]。
+//
+// linewidth
+// 直线段线宽,取值范围:[1,Page_Height-1]。
+//
+// linecolor
+// 直线段颜色线条颜色,0是白色,1是黑色
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_DrawRect
+
+在标签页指定位置绘制矩形
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawRect(Pointer handle, int x, int y, int width, int height, int color);
+// 在标签页指定位置绘制矩形
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// width
+// 矩形宽度
+//
+// height
+// 矩形高度
+//
+// color
+// 矩形颜色,0是白色,1是黑色
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Label_DrawBox
+
+在标签页指定位置绘制矩形框
+
+**定义:**
+
+```java
+public boolean CP_Label_DrawBox(Pointer handle, int x, int y, int width, int height, int borderwidth, int bordercolor);
+// 在标签页指定位置绘制矩形框
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// x
+// 横向坐标
+//
+// y
+// 纵向坐标
+//
+// width
+// 矩形框宽度
+//
+// height
+// 矩形框高度
+//
+// borderwidth
+// 矩形框边框宽度
+//
+// bordercolor
+// 矩形框边框颜色,0是白色,1是黑色
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+### 其他函数
+
+CP_Library_Version
+
+获取开发包版本字符串
+
+定义
+
+public String CP_Library_Version();
+
+// 获取开发包版本字符串
+
+//
+
+// return
+
+// 返回开发包版本
+
+#### CP_Proto_QueryBatteryLevel
+
+查询电池电量
+
+**定义:**
+
+```java
+public int CP_Proto_QueryBatteryLevel(Pointer handle, int timeout);
+// 查询电池电量
+// 仅部分带电池的机型支持该指令
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// timeout
+// 超时毫秒时间。
+// 查询等待时间不超过此时间。
+//
+// return
+// 返回电池电量,范围在0-100之间。返回-1表示查询失败。
+```
+
+---
+
+#### CP_Proto_QuerySerialNumber
+
+查询序列号
+
+Syntax
+
+```java
+public class CP_Proto_QuerySerialNumber_Helper {
+public static String QuerySerialNumber(Pointer handle, int timeout);
+}
+// 查询序列号
+// 仅部分机型支持该命令
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// timeout
+// 超时毫秒时间。
+// 查询等待时间不超过此时间。
+//
+// return
+// 返回序列号
+```
+
+---
+
+#### CP_Proto_SetSystemNameAndSerialNumber
+
+设置系统名称和序列号
+
+**定义:**
+
+```java
+public boolean CP_Proto_SetSystemNameAndSerialNumber(Pointer handle, String systemName, String
+```
+
+serialNumber);
+
+```java
+// 设置系统名称和序列号
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// systemName
+// 系统名称
+//
+// serialNumber
+// 序列号
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Proto_SetBluetoothNameAndPassword
+
+设置蓝牙名称和密码
+
+**定义:**
+
+```java
+public boolean CP_Proto_SetBluetoothNameAndPassword(Pointer handle, String bluetoothName, String
+```
+
+bluetoothPassword);
+
+```java
+// 设置蓝牙名称和密码
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// bluetoothName
+// 蓝牙名称
+//
+// bluetoothPassword
+// 蓝牙密码
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
+
+#### CP_Proto_SetPTPBasicParameters
+
+设置基础信息,包括语言、波特率、浓度等参数,对应设置工具PTP页。
+
+**定义:**
+
+```java
+public boolean CP_Proto_SetPTPBasicParameters(Pointer handle, int baudrate, int codepage, int density, int
+```
+
+asciiFontType, int lineFeed, int idleTime, int powerOffTime, int maxFeedLength, int pageLength);
+
+```java
+// 设置基础信息,包括语言、波特率、浓度等参数,对应设置工具PTP页。
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// baudrate
+// 要设置的波特率
+//
+// codepage
+// 要设置的语言
+// 具体语言对应的数值如下:
+// { ("简体中文"), 255 },
+// { ("繁體中文"), 254 },
+// { ("UTF - 8"), 253 },
+// { ("SHIFT - JIS"), 252 },
+// { ("EUC - KR"), 251 },
+// { ("CP437[U.S.A., Standard Europe]"), 0 },
+// { ("Katakana"), 1 },
+// { ("CP850[Multilingual]"), 2 },
+// { ("CP860[Portuguese]"), 3 },
+// { ("CP863[Canadian - French]"), 4 },
+// { ("CP865[Nordic]"), 5 },
+// { ("WCP1251[Cyrillic]"), 6 },
+// { ("CP866 Cyrilliec #2"), 7 },
+// { ("MIK[Cyrillic / Bulgarian]"), 8 },
+// { ("CP755[East Europe, Latvian 2]"), 9 },
+// { ("Iran"), 10 },
+// { ("CP862[Hebrew]"), 15 },
+// { ("WCP1252 Latin I"), 16 },
+// { ("WCP1253[Greek]"), 17 },
+// { ("CP852[Latina 2]"), 18 },
+// { ("CP858 Multilingual Latin I + Euro)"), 19 },
+// { ("Iran II"), 20 },
+// { ("Latvian"), 21 },
+// { ("CP864[Arabic]"), 22 },
+// { ("ISO - 8859 - 1[West Europe]"), 23 },
+// { ("CP737[Greek]"), 24 },
+```
+
+---
+
+#### CP_Settings_Hardware_SetPrintSpeed
+
+设置打印速度
+
+**定义:**
+
+```java
+public boolean CP_Settings_Hardware_SetPrintSpeed(Pointer handle, int nSpeed);
+// 设置打印速度
+//
+// handle
+// 端口句柄,由OpenXXX返回
+//
+// nSpeed
+// 打印速度,单位毫米每秒
+//
+// return
+// 返回值仅指示指令是否写入成功。返回true表示写入成功,返回false表示写入失败。
+```
+
+---
diff --git a/docs/autoreplyprint.aar b/docs/autoreplyprint.aar
new file mode 100644
index 0000000..8f3e770
Binary files /dev/null and b/docs/autoreplyprint.aar differ
diff --git a/docs/superpowers/specs/2026-04-22-printer-plugin-design.md b/docs/superpowers/specs/2026-04-22-printer-plugin-design.md
new file mode 100644
index 0000000..e84ffc9
--- /dev/null
+++ b/docs/superpowers/specs/2026-04-22-printer-plugin-design.md
@@ -0,0 +1,157 @@
+# 打印机插件设计文档
+
+**日期:** 2026-04-22
+**状态:** 已确认
+**目标:** 将 printer 插件开发为完整的打印插件,支持通过 CH34 串口 + autoreplyprint.aar 进行打印
+
+## 1. 项目概述
+
+### 用途
+公司内部多个 Flutter 项目共用的打印插件,用于打印拉曼检测结果(简单文字票据)。
+
+### 技术架构
+- CH34 插件提供串口通道
+- 本项目 Android 原生层集成 autoreplyprint.aar
+- Dart 层通过 MethodChannel 调用原生层
+- 底层指令式 API:调用方控制打开→打印→关闭全流程
+
+## 2. 整体架构
+
+```
+┌─────────────────────────────────────────────┐
+│ 调用方 Flutter 项目 │
+│ Printer.openComPort() → PrinterPortHandle │
+│ handle.printText() → handle.close() │
+└──────────────┬───────────────────────────────┘
+ │ MethodChannel 调用
+┌──────────────▼───────────────────────────────┐
+│ Flutter 插件 Dart 层 │
+│ Printer → PrinterPlatform │
+│ → MethodChannelPrinterPort │
+│ → PrinterPortHandle │
+└──────────────┬───────────────────────────────┐
+ │ MethodChannel + portHandle
+┌──────────────▼───────────────────────────────┐
+│ Android 原生层 (Java) │
+│ PrinterPlugin (MethodCallHandler) │
+│ → PortHandleManager │
+│ → autoreplyprint.aar │
+└───────────────────────────────────────────────┘
+```
+
+## 3. API 设计
+
+### 使用示例
+```dart
+// 打开端口
+PrinterPortHandle port = await Printer.openComPort(
+ portName: 'COM3',
+ baudRate: 9600,
+ dataBits: 8,
+ parity: Parity.none,
+ stopBits: StopBits.one,
+ flowControl: FlowControl.none,
+);
+
+// 设置编码
+await port.setMultiByteMode();
+await port.setMultiByteEncoding(MultiByteEncoding.utf8);
+
+// 打印
+await port.setAlignment(Alignment.center);
+await port.setTextScale(width: 2, height: 2);
+await port.printText('拉曼检测结果报告');
+
+// 走纸切纸
+await port.feedLine(3);
+await port.halfCutPaper();
+
+// 关闭
+await port.close();
+```
+
+### API 分类
+
+| 类别 | 方法 |
+|------|------|
+| 端口管理 | `openComPort`, `close` |
+| 打印文本 | `printText`, `printTextInUtf8`, `printTextInGbk` |
+| 格式控制 | `setAlignment`, `setTextScale`, `setTextBold`, `setTextUnderline` |
+| 走纸切纸 | `feedLine`, `feedDot`, `halfCutPaper`, `fullCutPaper` |
+| 编码模式 | `setMultiByteMode`, `setSingleByteMode`, `setMultiByteEncoding` |
+| 条码/二维码 | `printBarcode`, `printQRCode` |
+| 图片 | `printRasterImageFromData` |
+| 其他 | `resetPrinter`, `kickOutDrawer`, `beep` |
+
+## 4. MethodChannel 协议
+
+### 协议格式
+```
+MethodChannel 名称: "printer"
+
+Method: "openComPort"
+ Args: { portName, baudRate, dataBits, parity, stopBits, flowControl, autoReplyMode }
+ Return: { success: bool, portHandle: int?, error: String? }
+
+Method: "closePort"
+ Args: { portHandle }
+ Return: { success: bool, error: String? }
+
+Method: "printText"
+ Args: { portHandle, text }
+ Return: { success: bool, error: String? }
+
+... // 每个操作对应一个 method call
+```
+
+### 错误处理
+- 原生层异常通过 `result.error()` 返回
+- Dart 层统一包装为 `PrinterException`
+
+## 5. 原生层设计
+
+### 端口句柄管理
+- `PrinterPlugin.java` 维护 `Map portHandles`
+- `openComPort` 调用 `CP_Port_OpenCom` 返回 Pointer 存入 map
+- 生成递增 int 作为 Dart 层 portHandle
+- 每个 method call 从 map 中取出 Pointer,调用对应 AAR 函数
+
+### AAR 集成
+- 将 `docs/autoreplyprint.aar` 移至 `android/libs/`
+- `build.gradle.kts` 配置 `implementation files('libs/autoreplyprint.aar')`
+
+## 6. 项目结构
+
+```
+printer/
+├── lib/
+│ ├── printer.dart # 主入口
+│ ├── printer_platform_interface.dart # 平台接口
+│ ├── printer_method_channel.dart # MethodChannel 实现
+│ └── src/
+│ ├── models/
+│ │ ├── parity.dart # 串口校验枚举
+│ │ ├── alignment.dart # 对齐枚举
+│ │ ├── encoding.dart # 字符编码枚举
+│ │ └── printer_exception.dart # 自定义异常
+│ └── port_handle.dart # 端口句柄封装
+├── android/
+│ ├── build.gradle.kts
+│ ├── libs/
+│ │ └── autoreplyprint.aar
+│ └── src/main/java/com/xiarui/printer/
+│ ├── PrinterPlugin.java
+│ └── PortHandleManager.java
+└── test/
+ └── printer_test.dart
+```
+
+## 7. 关键决策
+
+| 决策 | 选择 | 理由 |
+|------|------|------|
+| SDK 集成方式 | 原生层调用 AAR | 利用已有封装,可靠 |
+| API 风格 | 底层指令式 | 灵活,调用方控制流程 |
+| 字符编码 | UTF8 | 中文支持,现代标准 |
+| 连接方式 | 串口 (通过 CH34) | 项目实际硬件需求 |
+| 状态回调 | 暂不需要 | 最小实现,后续可扩展 |
diff --git a/docs/usage.md b/docs/usage.md
new file mode 100644
index 0000000..62b3d76
--- /dev/null
+++ b/docs/usage.md
@@ -0,0 +1,471 @@
+# Printer 插件使用指南
+
+> 本文档介绍 Flutter Printer 插件的安装、配置和使用方法。该插件封装了 Android `autoreplyprint` SDK,提供了串口/USB 端口管理和票据打印功能。
+
+## 目录
+
+- [安装](#安装)
+- [快速开始](#快速开始)
+- [端口管理](#端口管理)
+- [票据打印](#票据打印)
+- [异常处理](#异常处理)
+- [完整示例](#完整示例)
+- [API 参考](#api-参考)
+
+---
+
+## 安装
+
+### 1. 添加依赖
+
+在 `pubspec.yaml` 中添加本地依赖:
+
+```yaml
+dependencies:
+ printer:
+ path: ../printer # 根据实际路径调整
+```
+
+### 2. 配置 Android
+
+将 `docs/autoreplyprint.aar` 文件放置到 Android 项目的 `app/libs/` 目录下:
+
+```
+your_flutter_app/
+└── android/
+ └── app/
+ └── libs/
+ └── autoreplyprint.aar
+```
+
+在 `android/app/build.gradle` 中确保 `libs` 目录被引用:
+
+```gradle
+dependencies {
+ implementation files('libs/autoreplyprint.aar')
+ // ... 其他依赖
+}
+```
+
+---
+
+## 快速开始
+
+### 基本打印流程
+
+一个完整的打印流程包含三个步骤:**打开端口 → 打印内容 → 关闭端口**。
+
+```dart
+import 'package:printer/printer.dart';
+
+final printer = Printer();
+
+// 1. 打开端口
+final handle = await printer.openComPort(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+);
+
+// 2. 设置编码并打印文本
+await printer.setMultiByteMode(handle);
+await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8);
+await printer.setAlignment(handle, PrinterAlignment.center);
+await printer.printText(handle, 'Hello 中文\n');
+await printer.feedLine(handle, 3);
+
+// 3. 关闭端口
+await printer.closePort(handle);
+```
+
+---
+
+## 端口管理
+
+### 枚举端口
+
+```dart
+// 枚举串口
+final comPorts = await printer.enumComPorts();
+print('可用串口: $comPorts');
+
+// 枚举USB端口
+final usbPorts = await printer.enumUsbPorts();
+print('可用USB口: $usbPorts');
+```
+
+### 打开串口 (COM Port)
+
+```dart
+final handle = await printer.openComPort(
+ portName: '/dev/ttyS0', // 端口名称(必填)
+ baudRate: 115200, // 波特率(必填),需与打印机保持一致
+ dataBits: 8, // 数据位,默认8
+ parity: SerialParity.none, // 校验位,默认无校验
+ stopBits: SerialStopBits.one, // 停止位,默认1位
+ flowControl: SerialFlowControl.none, // 流控制,默认无
+ autoReplyMode: true, // 是否开启自动回传模式
+);
+```
+
+**参数说明:**
+
+| 参数 | 类型 | 必填 | 默认值 | 说明 |
+|------|------|------|--------|------|
+| `portName` | `String` | 是 | - | 端口名称,如 `/dev/ttyS0` 或 `COM1` |
+| `baudRate` | `int` | 是 | - | 波特率,如 `9600`, `19200`, `38400`, `57600`, `115200` |
+| `dataBits` | `int` | 否 | `8` | 数据位,范围 `[4, 8]` |
+| `parity` | `SerialParity` | 否 | `none` | 校验位:`none`, `odd`, `even`, `mark`, `space` |
+| `stopBits` | `SerialStopBits` | 否 | `one` | 停止位:`one`, `onePointFive`, `two` |
+| `flowControl` | `SerialFlowControl` | 否 | `none` | 流控制:`none`, `xonXoff`, `rtsCts`, `dtrDsr` |
+| `autoReplyMode` | `bool` | 否 | `true` | 是否开启自动回传模式 |
+
+### 打开 USB 端口
+
+```dart
+final handle = await printer.openUsbPort(
+ portName: 'USB001', // 端口名称(必填),可不指定以自动查找
+ autoReplyMode: true, // 是否开启自动回传模式
+);
+```
+
+### 检查端口状态
+
+```dart
+final isOpen = await printer.isPortOpened(handle);
+if (isOpen) {
+ print('端口已打开');
+}
+```
+
+### 关闭端口
+
+```dart
+final success = await printer.closePort(handle);
+```
+
+### 使用安全句柄 (推荐)
+
+使用 `PrinterPortHandle` 可以更安全地管理端口资源,避免资源泄漏:
+
+```dart
+// 打开带句柄的串口
+final portHandle = await printer.openComPortWithHandle(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+);
+
+try {
+ // 执行打印操作
+ await printer.printText(portHandle.handle, 'Hello\n');
+} finally {
+ // 确保端口被关闭
+ await portHandle.close();
+}
+```
+
+同样支持 USB 端口:
+
+```dart
+final portHandle = await printer.openUsbPortWithHandle(
+ portName: 'USB001',
+);
+```
+
+---
+
+## 票据打印
+
+### 打印文本
+
+在打印文本之前,需要先设置多字节编码模式:
+
+```dart
+// 设置多字节模式
+await printer.setMultiByteMode(handle);
+
+// 设置编码为 UTF-8(支持中文等多语言字符)
+await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8);
+
+// 打印文本
+await printer.printText(handle, 'Hello 中文\n');
+```
+
+**支持的编码类型 (`MultiByteEncoding`):**
+
+| 编码 | 值 | 说明 |
+|------|-----|------|
+| `gbk` | `0` | GBK 编码(简体中文) |
+| `utf8` | `1` | UTF-8 编码(Unicode,推荐) |
+| `big5` | `3` | BIG5 编码(繁体中文) |
+| `shiftJis` | `4` | Shift-JIS 编码(日文) |
+| `eucKr` | `5` | EUC-KR 编码(韩文) |
+
+### 设置文本对齐
+
+```dart
+// 左对齐
+await printer.setAlignment(handle, PrinterAlignment.left);
+
+// 居中对齐
+await printer.setAlignment(handle, PrinterAlignment.center);
+
+// 右对齐
+await printer.setAlignment(handle, PrinterAlignment.right);
+```
+
+### 设置文本缩放
+
+宽度和高度缩放值范围为 `1` 到 `8`:
+
+```dart
+await printer.setTextScale(
+ handle,
+ widthScale: 2, // 宽度放大2倍
+ heightScale: 2, // 高度放大2倍
+);
+
+await printer.printText(handle, 'Large Text\n');
+```
+
+### 设置文本加粗
+
+```dart
+// 开启加粗
+await printer.setTextBold(handle, true);
+await printer.printText(handle, 'Bold Text\n');
+
+// 关闭加粗
+await printer.setTextBold(handle, false);
+```
+
+### 设置文本下划线
+
+```dart
+// 0 = 无下划线
+// 1 = 1点下划线
+// 2 = 2点下划线
+await printer.setTextUnderline(handle, 1);
+await printer.printText(handle, 'Underlined Text\n');
+```
+
+### 走纸
+
+```dart
+// 走纸指定行数
+await printer.feedLine(handle, 5);
+
+// 走纸指定点数
+await printer.feedDot(handle, 100);
+```
+
+### 切纸
+
+```dart
+// 半切(虚线切,纸张不完全分离)
+await printer.halfCutPaper(handle);
+
+// 全切(实线切,纸张完全分离)
+await printer.fullCutPaper(handle);
+```
+
+---
+
+## 异常处理
+
+所有端口打开操作在失败时会抛出 `PrinterException`:
+
+```dart
+try {
+ final handle = await printer.openComPort(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+ );
+} on PrinterException catch (e) {
+ print('端口打开失败: ${e.code} - ${e.message}');
+}
+```
+
+`PrinterException` 包含以下信息:
+
+| 属性 | 类型 | 说明 |
+|------|------|------|
+| `code` | `String` | 机器可读的错误码,如 `INVALID_ARGUMENT`, `PORT_OPEN_FAILED` |
+| `message` | `String` | 人类可读的错误消息 |
+| `details` | `dynamic` | 额外的错误详情(可能为 null) |
+
+---
+
+## 完整示例
+
+以下是一个完整的票据打印示例:
+
+```dart
+import 'package:printer/printer.dart';
+
+/// 打印收据示例
+Future printReceipt() async {
+ final printer = Printer();
+ PrinterPortHandle? portHandle;
+
+ try {
+ // 1. 枚举可用端口
+ final comPorts = await printer.enumComPorts();
+ if (comPorts.isEmpty) {
+ print('没有可用的串口');
+ return;
+ }
+
+ // 2. 打开第一个可用端口
+ portHandle = await printer.openComPortWithHandle(
+ portName: comPorts.first,
+ baudRate: 115200,
+ );
+ final handle = portHandle.handle;
+
+ // 3. 设置编码
+ await printer.setMultiByteMode(handle);
+ await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8);
+
+ // 4. 打印标题(居中、加粗、放大)
+ await printer.setAlignment(handle, PrinterAlignment.center);
+ await printer.setTextBold(handle, true);
+ await printer.setTextScale(handle, widthScale: 2, heightScale: 2);
+ await printer.printText(handle, '收据标题\n');
+
+ // 5. 重置样式并打印内容
+ await printer.setTextBold(handle, false);
+ await printer.setTextScale(handle, widthScale: 1, heightScale: 1);
+ await printer.setAlignment(handle, PrinterAlignment.left);
+ await printer.printText(handle, '商品名称 数量 价格\n');
+ await printer.printText(handle, '----------------------------\n');
+ await printer.printText(handle, '商品A 2 ¥20.00\n');
+ await printer.printText(handle, '商品B 1 ¥15.00\n');
+ await printer.printText(handle, '----------------------------\n');
+ await printer.printText(handle, '总计: ¥35.00\n');
+
+ // 6. 走纸并切纸
+ await printer.feedLine(handle, 5);
+ await printer.halfCutPaper(handle);
+
+ print('打印完成');
+ } on PrinterException catch (e) {
+ print('打印失败: ${e.code} - ${e.message}');
+ } finally {
+ // 7. 确保端口关闭
+ await portHandle?.close();
+ }
+}
+```
+
+---
+
+## API 参考
+
+### Printer 类
+
+| 方法 | 返回值 | 说明 |
+|------|--------|------|
+| `getPlatformVersion()` | `Future` | 获取平台版本 |
+| `enumComPorts()` | `Future>` | 枚举可用串口 |
+| `enumUsbPorts()` | `Future>` | 枚举可用USB端口 |
+| `openComPort({...})` | `Future` | 打开串口 |
+| `openUsbPort({...})` | `Future` | 打开USB端口 |
+| `openComPortWithHandle({...})` | `Future` | 打开串口并返回安全句柄 |
+| `openUsbPortWithHandle({...})` | `Future` | 打开USB端口并返回安全句柄 |
+| `closePort(int handle)` | `Future` | 关闭端口 |
+| `isPortOpened(int handle)` | `Future` | 检查端口是否打开 |
+| `setMultiByteMode(int handle)` | `Future` | 设置多字节编码模式 |
+| `setMultiByteEncoding(int, MultiByteEncoding)` | `Future` | 设置多字节编码类型 |
+| `printText(int handle, String text)` | `Future` | 打印文本 |
+| `setAlignment(int, PrinterAlignment)` | `Future` | 设置文本对齐 |
+| `setTextScale(int, {width, height})` | `Future` | 设置文本缩放 |
+| `setTextBold(int handle, bool bold)` | `Future` | 设置文本加粗 |
+| `setTextUnderline(int handle, int level)` | `Future` | 设置文本下划线 |
+| `feedLine(int handle, int numLines)` | `Future` | 走纸指定行数 |
+| `feedDot(int handle, int numDots)` | `Future` | 走纸指定点数 |
+| `halfCutPaper(int handle)` | `Future` | 半切纸 |
+| `fullCutPaper(int handle)` | `Future` | 全切纸 |
+
+### 枚举类型
+
+#### SerialParity (串口校验位)
+
+| 值 | 说明 |
+|----|------|
+| `none` | 无校验 |
+| `odd` | 奇校验 |
+| `even` | 偶校验 |
+| `mark` | 标记校验 |
+| `space` | 空白校验 |
+
+#### SerialStopBits (串口停止位)
+
+| 值 | 说明 |
+|----|------|
+| `one` | 1位停止位 |
+| `onePointFive` | 1.5位停止位 |
+| `two` | 2位停止位 |
+
+#### SerialFlowControl (串口流控制)
+
+| 值 | 说明 |
+|----|------|
+| `none` | 无流控 |
+| `xonXoff` | XON/XOFF 软件流控 |
+| `rtsCts` | RTS/CTS 硬件流控 |
+| `dtrDsr` | DTR/DSR 硬件流控 |
+
+#### PrinterAlignment (打印对齐)
+
+| 值 | 说明 |
+|----|------|
+| `left` | 左对齐 |
+| `center` | 居中对齐 |
+| `right` | 右对齐 |
+
+#### MultiByteEncoding (多字节编码)
+
+| 值 | 说明 |
+|----|------|
+| `gbk` | GBK 编码(简体中文) |
+| `utf8` | UTF-8 编码(推荐) |
+| `big5` | BIG5 编码(繁体中文) |
+| `shiftJis` | Shift-JIS 编码(日文) |
+| `eucKr` | EUC-KR 编码(韩文) |
+
+### PrinterPortHandle 类
+
+| 属性/方法 | 类型 | 说明 |
+|-----------|------|------|
+| `handle` | `int` | 整数端口句柄 |
+| `isValid` | `bool` | 端口是否仍然有效 |
+| `close()` | `Future` | 关闭端口,多次调用为 no-op |
+
+### PrinterException 类
+
+| 属性 | 类型 | 说明 |
+|------|------|------|
+| `code` | `String` | 错误码 |
+| `message` | `String` | 错误消息 |
+| `details` | `dynamic` | 额外详情 |
+
+---
+
+## 常见问题
+
+### 1. 打印乱码怎么办?
+
+- 确认编码设置与发送的文本编码一致,推荐使用 `MultiByteEncoding.utf8`
+- 确认打印机机型是否正确(票据机型使用 `CP_Pos_` 系列函数)
+- 检查波特率是否与打印机设置一致
+
+### 2. 端口打开失败?
+
+- 检查端口名称是否正确
+- 确认端口未被其他应用占用
+- 检查 USB 连接或串口线连接是否正常
+
+### 3. 打印到一半停止?
+
+- 检查电源是否充足(一般需要 2A 电源)
+- 检查是否缺纸
diff --git a/example/.gitignore b/example/.gitignore
new file mode 100644
index 0000000..3820a95
--- /dev/null
+++ b/example/.gitignore
@@ -0,0 +1,45 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.build/
+.buildlog/
+.history
+.svn/
+.swiftpm/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+/coverage/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/example/README.md b/example/README.md
new file mode 100644
index 0000000..d22f08b
--- /dev/null
+++ b/example/README.md
@@ -0,0 +1,17 @@
+# printer_example
+
+Demonstrates how to use the printer plugin.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
+- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/example/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/example/android/.gitignore b/example/android/.gitignore
new file mode 100644
index 0000000..be3943c
--- /dev/null
+++ b/example/android/.gitignore
@@ -0,0 +1,14 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+.cxx/
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts
new file mode 100644
index 0000000..a0e1260
--- /dev/null
+++ b/example/android/app/build.gradle.kts
@@ -0,0 +1,44 @@
+plugins {
+ id("com.android.application")
+ id("kotlin-android")
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id("dev.flutter.flutter-gradle-plugin")
+}
+
+android {
+ namespace = "com.xiarui.printer_example"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_17.toString()
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.xiarui.printer_example"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = flutter.minSdkVersion
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.getByName("debug")
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/example/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f79673c
--- /dev/null
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/java/com/xiarui/printer_example/MainActivity.java b/example/android/app/src/main/java/com/xiarui/printer_example/MainActivity.java
new file mode 100644
index 0000000..8f3045e
--- /dev/null
+++ b/example/android/app/src/main/java/com/xiarui/printer_example/MainActivity.java
@@ -0,0 +1,6 @@
+package com.xiarui.printer_example;
+
+import io.flutter.embedding.android.FlutterActivity;
+
+public class MainActivity extends FlutterActivity {
+}
diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/example/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..db77bb4
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..17987b7
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09d4391
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d5f1c8d
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4d6372e
Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/example/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/example/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/example/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts
new file mode 100644
index 0000000..dbee657
--- /dev/null
+++ b/example/android/build.gradle.kts
@@ -0,0 +1,24 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+val newBuildDir: Directory =
+ rootProject.layout.buildDirectory
+ .dir("../../build")
+ .get()
+rootProject.layout.buildDirectory.value(newBuildDir)
+
+subprojects {
+ val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
+ project.layout.buildDirectory.value(newSubprojectBuildDir)
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean") {
+ delete(rootProject.layout.buildDirectory)
+}
diff --git a/example/android/build/reports/problems/problems-report.html b/example/android/build/reports/problems/problems-report.html
new file mode 100644
index 0000000..f7c9369
--- /dev/null
+++ b/example/android/build/reports/problems/problems-report.html
@@ -0,0 +1,663 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gradle Configuration Cache
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+
diff --git a/example/android/gradle.properties b/example/android/gradle.properties
new file mode 100644
index 0000000..ae9783e
--- /dev/null
+++ b/example/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+android.overridePathCheck=true
diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e4ef43f
--- /dev/null
+++ b/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts
new file mode 100644
index 0000000..ca7fe06
--- /dev/null
+++ b/example/android/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ val flutterSdkPath =
+ run {
+ val properties = java.util.Properties()
+ file("local.properties").inputStream().use { properties.load(it) }
+ val flutterSdkPath = properties.getProperty("flutter.sdk")
+ require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
+ flutterSdkPath
+ }
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
+ id("com.android.application") version "8.11.1" apply false
+ id("org.jetbrains.kotlin.android") version "2.2.20" apply false
+}
+
+include(":app")
diff --git a/example/integration_test/plugin_integration_test.dart b/example/integration_test/plugin_integration_test.dart
new file mode 100644
index 0000000..550d552
--- /dev/null
+++ b/example/integration_test/plugin_integration_test.dart
@@ -0,0 +1,24 @@
+// This is a basic Flutter integration test.
+//
+// Since integration tests run in a full Flutter application, they can interact
+// with the host side of a plugin implementation, unlike Dart unit tests.
+//
+// For more information about Flutter integration tests, please see
+// https://flutter.dev/to/integration-testing
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+
+import 'package:printer/printer.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ testWidgets('getPlatformVersion test', (WidgetTester tester) async {
+ final Printer plugin = Printer();
+ final String? version = await plugin.getPlatformVersion();
+ // The version string depends on the host platform running the test, so
+ // just assert that some non-empty string is returned.
+ expect(version?.isNotEmpty, true);
+ });
+}
diff --git a/example/lib/main.dart b/example/lib/main.dart
new file mode 100644
index 0000000..8dd8bb6
--- /dev/null
+++ b/example/lib/main.dart
@@ -0,0 +1,59 @@
+import 'package:flutter/material.dart';
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+import 'package:printer/printer.dart';
+
+void main() {
+ runApp(const MyApp());
+}
+
+class MyApp extends StatefulWidget {
+ const MyApp({super.key});
+
+ @override
+ State createState() => _MyAppState();
+}
+
+class _MyAppState extends State {
+ String _platformVersion = 'Unknown';
+ final _printerPlugin = Printer();
+
+ @override
+ void initState() {
+ super.initState();
+ initPlatformState();
+ }
+
+ // Platform messages are asynchronous, so we initialize in an async method.
+ Future initPlatformState() async {
+ String platformVersion;
+ // Platform messages may fail, so we use a try/catch PlatformException.
+ // We also handle the message potentially returning null.
+ try {
+ platformVersion =
+ await _printerPlugin.getPlatformVersion() ?? 'Unknown platform version';
+ } on PlatformException {
+ platformVersion = 'Failed to get platform version.';
+ }
+
+ // If the widget was removed from the tree while the asynchronous platform
+ // message was in flight, we want to discard the reply rather than calling
+ // setState to update our non-existent appearance.
+ if (!mounted) return;
+
+ setState(() {
+ _platformVersion = platformVersion;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(title: const Text('Plugin example app')),
+ body: Center(child: Text('Running on: $_platformVersion\n')),
+ ),
+ );
+ }
+}
diff --git a/example/pubspec.lock b/example/pubspec.lock
new file mode 100644
index 0000000..c5d3588
--- /dev/null
+++ b/example/pubspec.lock
@@ -0,0 +1,283 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.13.1"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.1.2"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.4.1"
+ clock:
+ dependency: transitive
+ description:
+ name: clock
+ sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.1.2"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.19.1"
+ cupertino_icons:
+ dependency: "direct main"
+ description:
+ name: cupertino_icons
+ sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.0.9"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.3.3"
+ file:
+ dependency: transitive
+ description:
+ name: file
+ sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "7.0.1"
+ flutter:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_driver:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "6.0.0"
+ flutter_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ fuchsia_remote_debug_protocol:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ integration_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ leak_tracker:
+ dependency: transitive
+ description:
+ name: leak_tracker
+ sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "11.0.2"
+ leak_tracker_flutter_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_flutter_testing
+ sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.0.10"
+ leak_tracker_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_testing
+ sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.0.2"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "6.1.0"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.12.19"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.13.0"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.17.0"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.9.1"
+ platform:
+ dependency: transitive
+ description:
+ name: platform
+ sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.1.6"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.1.8"
+ printer:
+ dependency: "direct main"
+ description:
+ path: ".."
+ relative: true
+ source: path
+ version: "0.0.1"
+ process:
+ dependency: transitive
+ description:
+ name: process
+ sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "5.0.5"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.10.2"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.12.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.1.4"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.4.1"
+ sync_http:
+ dependency: transitive
+ description:
+ name: sync_http
+ sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.3.1"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.2.2"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.7.10"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.2.0"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: "046d3928e16fa4dc46e8350415661755ab759d9fc97fc21b5ab295f71e4f0499"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "15.1.0"
+ webdriver:
+ dependency: transitive
+ description:
+ name: webdriver
+ sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.1.0"
+sdks:
+ dart: ">=3.11.4 <4.0.0"
+ flutter: ">=3.18.0-18.0.pre.54"
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
new file mode 100644
index 0000000..a727ad1
--- /dev/null
+++ b/example/pubspec.yaml
@@ -0,0 +1,85 @@
+name: printer_example
+description: "Demonstrates how to use the printer plugin."
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+environment:
+ sdk: ^3.11.4
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+
+ printer:
+ # When depending on this package from a real application you should use:
+ # printer: ^x.y.z
+ # See https://dart.dev/tools/pub/dependencies#version-constraints
+ # The example app is bundled with the plugin so we use a path dependency on
+ # the parent directory to use the current plugin's version.
+ path: ../
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.8
+
+dev_dependencies:
+ integration_test:
+ sdk: flutter
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^6.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/to/resolution-aware-images
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/to/asset-from-package
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/to/font-from-package
diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart
new file mode 100644
index 0000000..612fc38
--- /dev/null
+++ b/example/test/widget_test.dart
@@ -0,0 +1,27 @@
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility in the flutter_test package. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:printer_example/main.dart';
+
+void main() {
+ testWidgets('Verify Platform version', (WidgetTester tester) async {
+ // Build our app and trigger a frame.
+ await tester.pumpWidget(const MyApp());
+
+ // Verify that platform version is retrieved.
+ expect(
+ find.byWidgetPredicate(
+ (Widget widget) =>
+ widget is Text && widget.data!.startsWith('Running on:'),
+ ),
+ findsOneWidget,
+ );
+ });
+}
diff --git a/lib/enums/multi_byte_encoding.dart b/lib/enums/multi_byte_encoding.dart
new file mode 100644
index 0000000..358482a
--- /dev/null
+++ b/lib/enums/multi_byte_encoding.dart
@@ -0,0 +1,29 @@
+/// Multi-byte character encoding for ticket printing.
+///
+/// Maps to the autoreplyprint AAR SDK CP_MultiByteEncoding constants.
+/// The printer uses the specified encoding to interpret received data.
+///
+/// Note: value 2 is reserved/unused per SDK specification. The sequence
+/// jumps from UTF8(1) to BIG5(3).
+enum MultiByteEncoding {
+ /// GBK encoding (Simplified Chinese)
+ gbk(0),
+
+ /// UTF-8 encoding (Unicode)
+ utf8(1),
+
+ // Note: value 2 is reserved/unused per SDK specification
+
+ /// BIG5 encoding (Traditional Chinese)
+ big5(3),
+
+ /// Shift-JIS encoding (Japanese)
+ shiftJis(4),
+
+ /// EUC-KR encoding (Korean)
+ eucKr(5);
+
+ /// The integer value matching the SDK constant.
+ final int value;
+ const MultiByteEncoding(this.value);
+}
diff --git a/lib/enums/printer_alignment.dart b/lib/enums/printer_alignment.dart
new file mode 100644
index 0000000..c38eb9a
--- /dev/null
+++ b/lib/enums/printer_alignment.dart
@@ -0,0 +1,17 @@
+/// Alignment for ticket printing.
+///
+/// Maps to the autoreplyprint AAR SDK CP_Pos_Alignment constants.
+enum PrinterAlignment {
+ /// Left alignment
+ left(0),
+
+ /// Center alignment
+ center(1),
+
+ /// Right alignment
+ right(2);
+
+ /// The integer value matching the SDK constant.
+ final int value;
+ const PrinterAlignment(this.value);
+}
diff --git a/lib/enums/serial_flow_control.dart b/lib/enums/serial_flow_control.dart
new file mode 100644
index 0000000..888f5f3
--- /dev/null
+++ b/lib/enums/serial_flow_control.dart
@@ -0,0 +1,20 @@
+/// Flow control setting for serial port communication.
+///
+/// Maps to the autoreplyprint AAR SDK flow control constants.
+enum SerialFlowControl {
+ /// No flow control
+ none(0),
+
+ /// XON/XOFF software flow control
+ xonXoff(1),
+
+ /// RTS/CTS hardware flow control
+ rtsCts(2),
+
+ /// DTR/DSR hardware flow control
+ dtrDsr(3);
+
+ /// The integer value matching the AAR SDK constant.
+ final int value;
+ const SerialFlowControl(this.value);
+}
diff --git a/lib/enums/serial_parity.dart b/lib/enums/serial_parity.dart
new file mode 100644
index 0000000..fc97fa8
--- /dev/null
+++ b/lib/enums/serial_parity.dart
@@ -0,0 +1,23 @@
+/// Parity setting for serial port communication.
+///
+/// Maps to the autoreplyprint AAR SDK parity constants.
+enum SerialParity {
+ /// No parity
+ none(0),
+
+ /// Odd parity
+ odd(1),
+
+ /// Even parity
+ even(2),
+
+ /// Mark parity
+ mark(3),
+
+ /// Space parity
+ space(4);
+
+ /// The integer value matching the AAR SDK constant.
+ final int value;
+ const SerialParity(this.value);
+}
diff --git a/lib/enums/serial_stop_bits.dart b/lib/enums/serial_stop_bits.dart
new file mode 100644
index 0000000..3548968
--- /dev/null
+++ b/lib/enums/serial_stop_bits.dart
@@ -0,0 +1,17 @@
+/// Stop bits setting for serial port communication.
+///
+/// Maps to the autoreplyprint AAR SDK stop bits constants.
+enum SerialStopBits {
+ /// 1 stop bit
+ one(0),
+
+ /// 1.5 stop bits
+ onePointFive(1),
+
+ /// 2 stop bits
+ two(2);
+
+ /// The integer value matching the AAR SDK constant.
+ final int value;
+ const SerialStopBits(this.value);
+}
diff --git a/lib/models/printer_exception.dart b/lib/models/printer_exception.dart
new file mode 100644
index 0000000..bafb252
--- /dev/null
+++ b/lib/models/printer_exception.dart
@@ -0,0 +1,24 @@
+/// Custom exception for printer operations.
+///
+/// Encapsulates structured error information from the native layer,
+/// including error code, message, and optional details.
+class PrinterException implements Exception {
+ /// Machine-readable error code (e.g., 'INVALID_ARGUMENT', 'PORT_OPEN_FAILED').
+ final String code;
+
+ /// Human-readable error message.
+ final String message;
+
+ /// Additional error details (may be null).
+ final dynamic details;
+
+ /// Creates a [PrinterException] with the given [code] and [message].
+ const PrinterException({
+ required this.code,
+ required this.message,
+ this.details,
+ });
+
+ @override
+ String toString() => 'PrinterException($code): $message';
+}
diff --git a/lib/models/printer_port_handle.dart b/lib/models/printer_port_handle.dart
new file mode 100644
index 0000000..dc40fec
--- /dev/null
+++ b/lib/models/printer_port_handle.dart
@@ -0,0 +1,44 @@
+/// Close callback type for [PrinterPortHandle].
+typedef ClosePortCallback = Future Function(int handle);
+
+/// Represents an open printer port handle.
+///
+/// Wraps an integer handle and provides a [close] method to release
+/// the underlying native port resource. Once closed, the handle
+/// becomes invalid.
+class PrinterPortHandle {
+ /// The integer handle returned by the native layer.
+ final int handle;
+
+ /// Callback to close the port. If null, close() is a no-op.
+ final ClosePortCallback? _closeCallback;
+
+ /// Whether the port is still valid (not closed).
+ bool _isValid;
+
+ /// Creates a [PrinterPortHandle] with the given [handle] and optional [closeCallback].
+ PrinterPortHandle({
+ required this.handle,
+ ClosePortCallback? closeCallback,
+ }) : _closeCallback = closeCallback,
+ _isValid = true;
+
+ /// Returns true if the port is still open and not closed.
+ bool get isValid => _isValid;
+
+ /// Closes the port and marks the handle as invalid.
+ ///
+ /// Subsequent calls to [close] are no-ops if the port is already closed.
+ Future close() async {
+ if (!_isValid) {
+ return;
+ }
+ _isValid = false;
+ if (_closeCallback != null) {
+ await _closeCallback(handle);
+ }
+ }
+
+ @override
+ String toString() => 'PrinterPortHandle(handle: $handle, valid: $_isValid)';
+}
diff --git a/lib/printer.dart b/lib/printer.dart
new file mode 100644
index 0000000..81d7754
--- /dev/null
+++ b/lib/printer.dart
@@ -0,0 +1,227 @@
+import 'enums/multi_byte_encoding.dart';
+import 'enums/printer_alignment.dart';
+import 'enums/serial_flow_control.dart';
+import 'enums/serial_parity.dart';
+import 'enums/serial_stop_bits.dart';
+import 'models/printer_port_handle.dart';
+import 'printer_platform_interface.dart';
+
+/// Main entry point for the printer plugin.
+///
+/// Provides a thin wrapper around [PrinterPlatform] for port management
+/// operations. All methods delegate to the platform interface.
+class Printer {
+ /// Returns the platform version string.
+ Future getPlatformVersion() {
+ return PrinterPlatform.instance.getPlatformVersion();
+ }
+
+ /// Opens a serial (COM) port with the specified parameters.
+ ///
+ /// Returns an integer handle on success.
+ /// Throws [PrinterException] on failure.
+ ///
+ /// Example:
+ /// ```dart
+ /// final printer = Printer();
+ /// final handle = await printer.openComPort(
+ /// portName: '/dev/ttyS0',
+ /// baudRate: 115200,
+ /// );
+ /// ```
+ Future openComPort({
+ required String portName,
+ required int baudRate,
+ int dataBits = 8,
+ SerialParity parity = SerialParity.none,
+ SerialStopBits stopBits = SerialStopBits.one,
+ SerialFlowControl flowControl = SerialFlowControl.none,
+ bool autoReplyMode = true,
+ }) {
+ return PrinterPlatform.instance.openComPort(
+ portName: portName,
+ baudRate: baudRate,
+ dataBits: dataBits,
+ parity: parity,
+ stopBits: stopBits,
+ flowControl: flowControl,
+ autoReplyMode: autoReplyMode,
+ );
+ }
+
+ /// Opens a USB port with the specified parameters.
+ ///
+ /// Returns an integer handle on success.
+ /// Throws [PrinterException] on failure.
+ Future openUsbPort({
+ required String portName,
+ bool autoReplyMode = true,
+ }) {
+ return PrinterPlatform.instance.openUsbPort(
+ portName: portName,
+ autoReplyMode: autoReplyMode,
+ );
+ }
+
+ /// Closes a port by its integer handle.
+ ///
+ /// Returns true if successfully closed, false otherwise.
+ Future closePort(int handle) {
+ return PrinterPlatform.instance.closePort(handle);
+ }
+
+ /// Checks if a port is currently opened.
+ ///
+ /// Returns true if the port is open, false otherwise.
+ Future isPortOpened(int handle) {
+ return PrinterPlatform.instance.isPortOpened(handle);
+ }
+
+ /// Enumerates available serial (COM) ports.
+ ///
+ /// Returns a list of port name strings.
+ Future> enumComPorts() {
+ return PrinterPlatform.instance.enumComPorts();
+ }
+
+ /// Enumerates available USB ports.
+ ///
+ /// Returns a list of port name strings.
+ Future> enumUsbPorts() {
+ return PrinterPlatform.instance.enumUsbPorts();
+ }
+
+ /// Opens a serial port and returns a [PrinterPortHandle] for safe resource management.
+ ///
+ /// The returned handle can be closed via [PrinterPortHandle.close].
+ Future openComPortWithHandle({
+ required String portName,
+ required int baudRate,
+ int dataBits = 8,
+ SerialParity parity = SerialParity.none,
+ SerialStopBits stopBits = SerialStopBits.one,
+ SerialFlowControl flowControl = SerialFlowControl.none,
+ bool autoReplyMode = true,
+ }) async {
+ final handle = await openComPort(
+ portName: portName,
+ baudRate: baudRate,
+ dataBits: dataBits,
+ parity: parity,
+ stopBits: stopBits,
+ flowControl: flowControl,
+ autoReplyMode: autoReplyMode,
+ );
+ return PrinterPortHandle(
+ handle: handle,
+ closeCallback: closePort,
+ );
+ }
+
+ /// Opens a USB port and returns a [PrinterPortHandle] for safe resource management.
+ ///
+ /// The returned handle can be closed via [PrinterPortHandle.close].
+ Future openUsbPortWithHandle({
+ required String portName,
+ bool autoReplyMode = true,
+ }) async {
+ final handle = await openUsbPort(
+ portName: portName,
+ autoReplyMode: autoReplyMode,
+ );
+ return PrinterPortHandle(
+ handle: handle,
+ closeCallback: closePort,
+ );
+ }
+
+ /// Sets the printer to multi-byte encoding mode.
+ ///
+ /// Returns true on success.
+ Future setMultiByteMode(int handle) {
+ return PrinterPlatform.instance.setMultiByteMode(handle);
+ }
+
+ /// Sets the multi-byte character encoding.
+ ///
+ /// Returns true on success.
+ Future setMultiByteEncoding(int handle, MultiByteEncoding encoding) {
+ return PrinterPlatform.instance.setMultiByteEncoding(handle, encoding);
+ }
+
+ /// Prints text using UTF-8 encoding.
+ ///
+ /// The caller should ensure multi-byte mode is set to UTF-8 before calling:
+ /// ```dart
+ /// await printer.setMultiByteMode(handle);
+ /// await printer.setMultiByteEncoding(handle, MultiByteEncoding.utf8);
+ /// await printer.printText(handle, 'Hello 中文');
+ /// ```
+ ///
+ /// Returns true on success.
+ Future printText(int handle, String text) {
+ return PrinterPlatform.instance.printText(handle, text);
+ }
+
+ /// Sets text alignment.
+ ///
+ /// Returns true on success.
+ Future setAlignment(int handle, PrinterAlignment alignment) {
+ return PrinterPlatform.instance.setAlignment(handle, alignment);
+ }
+
+ /// Sets text scale (width and height magnification).
+ ///
+ /// Both scales must be between 1 and 8.
+ /// Returns true on success.
+ Future setTextScale(int handle, {required int widthScale, required int heightScale}) {
+ return PrinterPlatform.instance.setTextScale(
+ handle,
+ widthScale: widthScale,
+ heightScale: heightScale,
+ );
+ }
+
+ /// Sets text bold on or off.
+ ///
+ /// Returns true on success.
+ Future setTextBold(int handle, bool bold) {
+ return PrinterPlatform.instance.setTextBold(handle, bold);
+ }
+
+ /// Sets text underline level.
+ ///
+ /// 0 = no underline, 1 = 1-dot underline, 2 = 2-dot underline.
+ /// Returns true on success.
+ Future setTextUnderline(int handle, int underline) {
+ return PrinterPlatform.instance.setTextUnderline(handle, underline);
+ }
+
+ /// Feeds paper by specified number of lines.
+ ///
+ /// Returns true on success.
+ Future feedLine(int handle, int numLines) {
+ return PrinterPlatform.instance.feedLine(handle, numLines);
+ }
+
+ /// Feeds paper by specified number of dots.
+ ///
+ /// Returns true on success.
+ Future feedDot(int handle, int numDots) {
+ return PrinterPlatform.instance.feedDot(handle, numDots);
+ }
+
+ /// Performs a half cut of the paper.
+ ///
+ /// Returns true on success.
+ Future halfCutPaper(int handle) {
+ return PrinterPlatform.instance.halfCutPaper(handle);
+ }
+
+ /// Performs a full cut of the paper.
+ ///
+ /// Returns true on success.
+ Future fullCutPaper(int handle) {
+ return PrinterPlatform.instance.fullCutPaper(handle);
+ }
+}
diff --git a/lib/printer_method_channel.dart b/lib/printer_method_channel.dart
new file mode 100644
index 0000000..35b9282
--- /dev/null
+++ b/lib/printer_method_channel.dart
@@ -0,0 +1,339 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+
+import 'enums/multi_byte_encoding.dart';
+import 'enums/printer_alignment.dart';
+import 'enums/serial_flow_control.dart';
+import 'enums/serial_parity.dart';
+import 'enums/serial_stop_bits.dart';
+import 'models/printer_exception.dart';
+import 'printer_platform_interface.dart';
+
+/// An implementation of [PrinterPlatform] that uses method channels.
+class MethodChannelPrinter extends PrinterPlatform {
+ /// The method channel used to interact with the native platform.
+ @visibleForTesting
+ final methodChannel = const MethodChannel('printer');
+
+ @override
+ Future getPlatformVersion() async {
+ final version = await methodChannel.invokeMethod(
+ 'getPlatformVersion',
+ );
+ return version;
+ }
+
+ @override
+ Future openComPort({
+ required String portName,
+ required int baudRate,
+ int dataBits = 8,
+ SerialParity parity = SerialParity.none,
+ SerialStopBits stopBits = SerialStopBits.one,
+ SerialFlowControl flowControl = SerialFlowControl.none,
+ bool autoReplyMode = true,
+ }) async {
+ try {
+ final result = await methodChannel.invokeMethod('openComPort', {
+ 'portName': portName,
+ 'baudRate': baudRate,
+ 'dataBits': dataBits,
+ 'parity': parity.value,
+ 'stopBits': stopBits.value,
+ 'flowControl': flowControl.value,
+ 'autoReplyMode': autoReplyMode ? 1 : 0,
+ });
+ return result!;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to open COM port',
+ details: e.details,
+ );
+ }
+ }
+
+ @override
+ Future openUsbPort({
+ required String portName,
+ bool autoReplyMode = true,
+ }) async {
+ try {
+ final result = await methodChannel.invokeMethod('openUsbPort', {
+ 'portName': portName,
+ 'autoReplyMode': autoReplyMode ? 1 : 0,
+ });
+ return result!;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to open USB port',
+ details: e.details,
+ );
+ }
+ }
+
+ @override
+ Future closePort(int handle) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'closePort',
+ {'handle': handle},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to close port',
+ details: e.details,
+ );
+ }
+ }
+
+ @override
+ Future isPortOpened(int handle) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'isPortOpened',
+ {'handle': handle},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to check port status',
+ details: e.details,
+ );
+ }
+ }
+
+ @override
+ Future> enumComPorts() async {
+ try {
+ final result = await methodChannel.invokeMethod('enumComPorts');
+ return (result ?? []).map((e) => e.toString()).toList();
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to enumerate COM ports',
+ details: e.details,
+ );
+ }
+ }
+
+ @override
+ Future> enumUsbPorts() async {
+ try {
+ final result = await methodChannel.invokeMethod('enumUsbPorts');
+ return (result ?? []).map((e) => e.toString()).toList();
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to enumerate USB ports',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Sets the printer to multi-byte encoding mode.
+ @override
+ Future setMultiByteMode(int handle) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'setMultiByteMode',
+ {'handle': handle},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to set multi-byte mode',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Sets the multi-byte character encoding.
+ @override
+ Future setMultiByteEncoding(int handle, MultiByteEncoding encoding) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'setMultiByteEncoding',
+ {'handle': handle, 'encoding': encoding.value},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to set multi-byte encoding',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Prints text using UTF-8 encoding.
+ @override
+ Future printText(int handle, String text) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'printText',
+ {'handle': handle, 'text': text},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to print text',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Sets text alignment.
+ @override
+ Future setAlignment(int handle, PrinterAlignment alignment) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'setAlignment',
+ {'handle': handle, 'alignment': alignment.value},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to set alignment',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Sets text scale (width and height magnification).
+ @override
+ Future setTextScale(int handle, {required int widthScale, required int heightScale}) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'setTextScale',
+ {
+ 'handle': handle,
+ 'widthScale': widthScale,
+ 'heightScale': heightScale,
+ },
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to set text scale',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Sets text bold on or off.
+ @override
+ Future setTextBold(int handle, bool bold) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'setTextBold',
+ {'handle': handle, 'bold': bold ? 1 : 0},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to set text bold',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Sets text underline level.
+ @override
+ Future setTextUnderline(int handle, int underline) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'setTextUnderline',
+ {'handle': handle, 'underline': underline},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to set text underline',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Feeds paper by specified number of lines.
+ @override
+ Future feedLine(int handle, int numLines) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'feedLine',
+ {'handle': handle, 'numLines': numLines},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to feed line',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Feeds paper by specified number of dots.
+ @override
+ Future feedDot(int handle, int numDots) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'feedDot',
+ {'handle': handle, 'numDots': numDots},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to feed dot',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Performs a half cut of the paper.
+ @override
+ Future halfCutPaper(int handle) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'halfCutPaper',
+ {'handle': handle},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to half cut paper',
+ details: e.details,
+ );
+ }
+ }
+
+ /// Performs a full cut of the paper.
+ @override
+ Future fullCutPaper(int handle) async {
+ try {
+ final result = await methodChannel.invokeMethod(
+ 'fullCutPaper',
+ {'handle': handle},
+ );
+ return result ?? false;
+ } on PlatformException catch (e) {
+ throw PrinterException(
+ code: e.code,
+ message: e.message ?? 'Failed to full cut paper',
+ details: e.details,
+ );
+ }
+ }
+}
diff --git a/lib/printer_platform_interface.dart b/lib/printer_platform_interface.dart
new file mode 100644
index 0000000..62b7e54
--- /dev/null
+++ b/lib/printer_platform_interface.dart
@@ -0,0 +1,173 @@
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+import 'enums/multi_byte_encoding.dart';
+import 'enums/printer_alignment.dart';
+import 'enums/serial_flow_control.dart';
+import 'enums/serial_parity.dart';
+import 'enums/serial_stop_bits.dart';
+import 'printer_method_channel.dart';
+
+/// Platform interface for printer operations.
+///
+/// Concrete implementations (e.g., [MethodChannelPrinter]) provide
+/// the actual platform-specific behavior.
+abstract class PrinterPlatform extends PlatformInterface {
+ /// Constructs a PrinterPlatform.
+ PrinterPlatform() : super(token: _token);
+
+ static final Object _token = Object();
+
+ static PrinterPlatform _instance = MethodChannelPrinter();
+
+ /// The default instance of [PrinterPlatform] to use.
+ ///
+ /// Defaults to [MethodChannelPrinter].
+ static PrinterPlatform get instance => _instance;
+
+ /// Platform-specific implementations should set this with their own
+ /// platform-specific class that extends [PrinterPlatform] when
+ /// they register themselves.
+ static set instance(PrinterPlatform instance) {
+ PlatformInterface.verifyToken(instance, _token);
+ _instance = instance;
+ }
+
+ /// Returns the platform version string.
+ Future getPlatformVersion() {
+ throw UnimplementedError('getPlatformVersion() has not been implemented.');
+ }
+
+ /// Opens a serial (COM) port with the specified parameters.
+ ///
+ /// Returns an integer handle on success.
+ /// Throws [PrinterException] on failure.
+ Future openComPort({
+ required String portName,
+ required int baudRate,
+ int dataBits = 8,
+ SerialParity parity = SerialParity.none,
+ SerialStopBits stopBits = SerialStopBits.one,
+ SerialFlowControl flowControl = SerialFlowControl.none,
+ bool autoReplyMode = true,
+ }) {
+ throw UnimplementedError('openComPort() has not been implemented.');
+ }
+
+ /// Opens a USB port with the specified parameters.
+ ///
+ /// Returns an integer handle on success.
+ /// Throws [PrinterException] on failure.
+ Future openUsbPort({
+ required String portName,
+ bool autoReplyMode = true,
+ }) {
+ throw UnimplementedError('openUsbPort() has not been implemented.');
+ }
+
+ /// Closes a port by its integer handle.
+ ///
+ /// Returns true if successfully closed, false otherwise.
+ Future closePort(int handle) {
+ throw UnimplementedError('closePort() has not been implemented.');
+ }
+
+ /// Checks if a port is currently opened.
+ ///
+ /// Returns true if the port is open, false otherwise.
+ Future isPortOpened(int handle) {
+ throw UnimplementedError('isPortOpened() has not been implemented.');
+ }
+
+ /// Enumerates available serial (COM) ports.
+ ///
+ /// Returns a list of port name strings.
+ Future> enumComPorts() {
+ throw UnimplementedError('enumComPorts() has not been implemented.');
+ }
+
+ /// Enumerates available USB ports.
+ ///
+ /// Returns a list of port name strings.
+ Future> enumUsbPorts() {
+ throw UnimplementedError('enumUsbPorts() has not been implemented.');
+ }
+
+ /// Sets the printer to multi-byte encoding mode.
+ ///
+ /// Returns true on success.
+ Future setMultiByteMode(int handle) {
+ throw UnimplementedError('setMultiByteMode() has not been implemented.');
+ }
+
+ /// Sets the multi-byte character encoding.
+ ///
+ /// Returns true on success.
+ Future setMultiByteEncoding(int handle, MultiByteEncoding encoding) {
+ throw UnimplementedError('setMultiByteEncoding() has not been implemented.');
+ }
+
+ /// Prints text using UTF-8 encoding.
+ ///
+ /// Returns true on success.
+ Future printText(int handle, String text) {
+ throw UnimplementedError('printText() has not been implemented.');
+ }
+
+ /// Sets text alignment.
+ ///
+ /// Returns true on success.
+ Future setAlignment(int handle, PrinterAlignment alignment) {
+ throw UnimplementedError('setAlignment() has not been implemented.');
+ }
+
+ /// Sets text scale (width and height magnification).
+ ///
+ /// Both scales must be between 1 and 8.
+ /// Returns true on success.
+ Future setTextScale(int handle, {required int widthScale, required int heightScale}) {
+ throw UnimplementedError('setTextScale() has not been implemented.');
+ }
+
+ /// Sets text bold on or off.
+ ///
+ /// Returns true on success.
+ Future setTextBold(int handle, bool bold) {
+ throw UnimplementedError('setTextBold() has not been implemented.');
+ }
+
+ /// Sets text underline level.
+ ///
+ /// 0 = no underline, 1 = 1-dot underline, 2 = 2-dot underline.
+ /// Returns true on success.
+ Future setTextUnderline(int handle, int underline) {
+ throw UnimplementedError('setTextUnderline() has not been implemented.');
+ }
+
+ /// Feeds paper by specified number of lines.
+ ///
+ /// Returns true on success.
+ Future feedLine(int handle, int numLines) {
+ throw UnimplementedError('feedLine() has not been implemented.');
+ }
+
+ /// Feeds paper by specified number of dots.
+ ///
+ /// Returns true on success.
+ Future feedDot(int handle, int numDots) {
+ throw UnimplementedError('feedDot() has not been implemented.');
+ }
+
+ /// Performs a half cut of the paper.
+ ///
+ /// Returns true on success.
+ Future halfCutPaper(int handle) {
+ throw UnimplementedError('halfCutPaper() has not been implemented.');
+ }
+
+ /// Performs a full cut of the paper.
+ ///
+ /// Returns true on success.
+ Future fullCutPaper(int handle) {
+ throw UnimplementedError('fullCutPaper() has not been implemented.');
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..34f94ef
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,70 @@
+name: printer
+description: "A new Flutter project."
+version: 0.0.1
+homepage:
+
+environment:
+ sdk: ^3.11.4
+ flutter: '>=3.3.0'
+
+dependencies:
+ flutter:
+ sdk: flutter
+ plugin_platform_interface: ^2.0.2
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ flutter_lints: ^6.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+ # This section identifies this Flutter project as a plugin project.
+ # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
+ # which should be registered in the plugin registry. This is required for
+ # using method channels.
+ # The Android 'package' specifies package in which the registered class is.
+ # This is required for using method channels on Android.
+ # The 'ffiPlugin' specifies that native code should be built and bundled.
+ # This is required for using `dart:ffi`.
+ # All these are used by the tooling to maintain consistency when
+ # adding or updating assets for this project.
+ plugin:
+ platforms:
+ android:
+ package: com.xiarui.printer
+ pluginClass: PrinterPlugin
+
+ # To add assets to your plugin package, add an assets section, like this:
+ # assets:
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+ #
+ # For details regarding assets in packages, see
+ # https://flutter.dev/to/asset-from-package
+ #
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/to/resolution-aware-images
+
+ # To add custom fonts to your plugin package, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts in packages, see
+ # https://flutter.dev/to/font-from-package
diff --git a/test/printer_method_channel_test.dart b/test/printer_method_channel_test.dart
new file mode 100644
index 0000000..e6e35e9
--- /dev/null
+++ b/test/printer_method_channel_test.dart
@@ -0,0 +1,297 @@
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:printer/printer_method_channel.dart';
+import 'package:printer/enums/multi_byte_encoding.dart';
+import 'package:printer/enums/printer_alignment.dart';
+import 'package:printer/enums/serial_flow_control.dart';
+import 'package:printer/enums/serial_parity.dart';
+import 'package:printer/enums/serial_stop_bits.dart';
+import 'package:printer/models/printer_exception.dart';
+
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ MethodChannelPrinter platform = MethodChannelPrinter();
+ const MethodChannel channel = MethodChannel('printer');
+
+ setUp(() {
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'getPlatformVersion') {
+ return '42';
+ }
+ if (methodCall.method == 'openComPort') {
+ return 1;
+ }
+ if (methodCall.method == 'openUsbPort') {
+ return 2;
+ }
+ if (methodCall.method == 'closePort') {
+ return true;
+ }
+ if (methodCall.method == 'isPortOpened') {
+ return true;
+ }
+ if (methodCall.method == 'enumComPorts') {
+ return ['/dev/ttyS0', '/dev/ttyS1'];
+ }
+ if (methodCall.method == 'enumUsbPorts') {
+ return ['USB_Printer_0'];
+ }
+ if (methodCall.method == 'setMultiByteMode') return true;
+ if (methodCall.method == 'setMultiByteEncoding') return true;
+ if (methodCall.method == 'printText') return true;
+ if (methodCall.method == 'setAlignment') return true;
+ if (methodCall.method == 'setTextScale') return true;
+ if (methodCall.method == 'setTextBold') return true;
+ if (methodCall.method == 'setTextUnderline') return true;
+ if (methodCall.method == 'feedLine') return true;
+ if (methodCall.method == 'feedDot') return true;
+ if (methodCall.method == 'halfCutPaper') return true;
+ if (methodCall.method == 'fullCutPaper') return true;
+ return null;
+ });
+ });
+
+ tearDown(() {
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, null);
+ });
+
+ test('getPlatformVersion', () async {
+ expect(await platform.getPlatformVersion(), '42');
+ });
+
+ test('openComPort returns handle', () async {
+ final handle = await platform.openComPort(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+ parity: SerialParity.none,
+ stopBits: SerialStopBits.one,
+ flowControl: SerialFlowControl.none,
+ );
+
+ expect(handle, 1);
+ });
+
+ test('openComPort passes correct parameters', () async {
+ late Map capturedArgs;
+
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'openComPort') {
+ capturedArgs = methodCall.arguments as Map;
+ return 42;
+ }
+ return null;
+ });
+
+ await platform.openComPort(
+ portName: '/dev/ttyS0',
+ baudRate: 9600,
+ dataBits: 7,
+ parity: SerialParity.even,
+ stopBits: SerialStopBits.two,
+ flowControl: SerialFlowControl.rtsCts,
+ autoReplyMode: false,
+ );
+
+ expect(capturedArgs['portName'], '/dev/ttyS0');
+ expect(capturedArgs['baudRate'], 9600);
+ expect(capturedArgs['dataBits'], 7);
+ expect(capturedArgs['parity'], 2); // SerialParity.even
+ expect(capturedArgs['stopBits'], 2); // SerialStopBits.two
+ expect(capturedArgs['flowControl'], 2); // SerialFlowControl.rtsCts
+ expect(capturedArgs['autoReplyMode'], 0); // false
+ });
+
+ test('openUsbPort returns handle', () async {
+ final handle = await platform.openUsbPort(portName: 'USB_Printer_0');
+
+ expect(handle, 2);
+ });
+
+ test('closePort returns true', () async {
+ final result = await platform.closePort(1);
+
+ expect(result, true);
+ });
+
+ test('isPortOpened returns true', () async {
+ final result = await platform.isPortOpened(1);
+
+ expect(result, true);
+ });
+
+ test('enumComPorts returns list of strings', () async {
+ final ports = await platform.enumComPorts();
+
+ expect(ports, isA>());
+ expect(ports, contains('/dev/ttyS0'));
+ expect(ports, contains('/dev/ttyS1'));
+ });
+
+ test('enumUsbPorts returns list of strings', () async {
+ final ports = await platform.enumUsbPorts();
+
+ expect(ports, isA>());
+ expect(ports, contains('USB_Printer_0'));
+ });
+
+ test('PlatformException converts to PrinterException on openComPort', () async {
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'openComPort') {
+ throw PlatformException(
+ code: 'PORT_OPEN_FAILED',
+ message: 'Failed to open port',
+ details: {'port': '/dev/ttyS0'},
+ );
+ }
+ return null;
+ });
+
+ expect(
+ () async => platform.openComPort(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+ ),
+ throwsA(isA()
+ .having((e) => e.code, 'code', 'PORT_OPEN_FAILED')
+ .having((e) => e.message, 'message', 'Failed to open port')),
+ );
+ });
+
+ test('PlatformException converts to PrinterException on closePort', () async {
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'closePort') {
+ throw PlatformException(
+ code: 'PORT_CLOSE_FAILED',
+ message: 'Failed to close port',
+ );
+ }
+ return null;
+ });
+
+ expect(
+ () async => platform.closePort(1),
+ throwsA(isA()
+ .having((e) => e.code, 'code', 'PORT_CLOSE_FAILED')),
+ );
+ });
+
+ test('printText passes text parameter', () async {
+ late Map capturedArgs;
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'printText') {
+ capturedArgs = methodCall.arguments as Map;
+ return true;
+ }
+ return null;
+ });
+
+ await platform.printText(1, 'Hello 中文');
+ expect(capturedArgs['handle'], 1);
+ expect(capturedArgs['text'], 'Hello 中文');
+ });
+
+ test('setAlignment passes alignment.value', () async {
+ late Map capturedArgs;
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'setAlignment') {
+ capturedArgs = methodCall.arguments as Map;
+ return true;
+ }
+ return null;
+ });
+
+ await platform.setAlignment(1, PrinterAlignment.center);
+ expect(capturedArgs['alignment'], 1); // PrinterAlignment.center.value
+ });
+
+ test('setMultiByteEncoding passes encoding.value', () async {
+ late Map capturedArgs;
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'setMultiByteEncoding') {
+ capturedArgs = methodCall.arguments as Map;
+ return true;
+ }
+ return null;
+ });
+
+ await platform.setMultiByteEncoding(1, MultiByteEncoding.utf8);
+ expect(capturedArgs['encoding'], 1); // MultiByteEncoding.utf8.value
+ });
+
+ test('setTextBold converts bool to int 0/1', () async {
+ late Map capturedArgs;
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'setTextBold') {
+ capturedArgs = methodCall.arguments as Map;
+ return true;
+ }
+ return null;
+ });
+
+ await platform.setTextBold(1, true);
+ expect(capturedArgs['bold'], 1);
+
+ await platform.setTextBold(1, false);
+ expect(capturedArgs['bold'], 0);
+ });
+
+ test('feedDot passes numDots parameter', () async {
+ late Map capturedArgs;
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'feedDot') {
+ capturedArgs = methodCall.arguments as Map;
+ return true;
+ }
+ return null;
+ });
+
+ await platform.feedDot(1, 100);
+ expect(capturedArgs['handle'], 1);
+ expect(capturedArgs['numDots'], 100);
+ });
+
+ test('fullCutPaper passes handle parameter', () async {
+ late Map capturedArgs;
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'fullCutPaper') {
+ capturedArgs = methodCall.arguments as Map;
+ return true;
+ }
+ return null;
+ });
+
+ await platform.fullCutPaper(1);
+ expect(capturedArgs['handle'], 1);
+ });
+
+ test('PlatformException converts to PrinterException on printText', () async {
+ TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
+ .setMockMethodCallHandler(channel, (MethodCall methodCall) async {
+ if (methodCall.method == 'printText') {
+ throw PlatformException(
+ code: 'PRINT_FAILED',
+ message: 'Failed to print text',
+ );
+ }
+ return null;
+ });
+
+ expect(
+ () async => platform.printText(1, 'test'),
+ throwsA(isA()
+ .having((e) => e.code, 'code', 'PRINT_FAILED')),
+ );
+ });
+}
diff --git a/test/printer_test.dart b/test/printer_test.dart
new file mode 100644
index 0000000..3a6cddc
--- /dev/null
+++ b/test/printer_test.dart
@@ -0,0 +1,264 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:printer/printer.dart';
+import 'package:printer/printer_platform_interface.dart';
+import 'package:printer/printer_method_channel.dart';
+import 'package:printer/enums/multi_byte_encoding.dart';
+import 'package:printer/enums/printer_alignment.dart';
+import 'package:printer/enums/serial_flow_control.dart';
+import 'package:printer/enums/serial_parity.dart';
+import 'package:printer/enums/serial_stop_bits.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+class MockPrinterPlatform
+ with MockPlatformInterfaceMixin
+ implements PrinterPlatform {
+ @override
+ Future getPlatformVersion() => Future.value('42');
+
+ @override
+ Future openComPort({
+ required String portName,
+ required int baudRate,
+ int dataBits = 8,
+ SerialParity parity = SerialParity.none,
+ SerialStopBits stopBits = SerialStopBits.one,
+ SerialFlowControl flowControl = SerialFlowControl.none,
+ bool autoReplyMode = true,
+ }) => Future.value(1);
+
+ @override
+ Future openUsbPort({
+ required String portName,
+ bool autoReplyMode = true,
+ }) => Future.value(2);
+
+ @override
+ Future closePort(int handle) => Future.value(true);
+
+ @override
+ Future isPortOpened(int handle) => Future.value(true);
+
+ @override
+ Future> enumComPorts() => Future.value(['/dev/ttyS0']);
+
+ @override
+ Future> enumUsbPorts() => Future.value(['USB_Printer_0']);
+
+ @override
+ Future setMultiByteMode(int handle) => Future.value(true);
+
+ @override
+ Future setMultiByteEncoding(int handle, MultiByteEncoding encoding) => Future.value(true);
+
+ @override
+ Future printText(int handle, String text) => Future.value(true);
+
+ @override
+ Future setAlignment(int handle, PrinterAlignment alignment) => Future.value(true);
+
+ @override
+ Future setTextScale(int handle, {required int widthScale, required int heightScale}) => Future.value(true);
+
+ @override
+ Future setTextBold(int handle, bool bold) => Future.value(true);
+
+ @override
+ Future setTextUnderline(int handle, int underline) => Future.value(true);
+
+ @override
+ Future feedLine(int handle, int numLines) => Future.value(true);
+
+ @override
+ Future feedDot(int handle, int numDots) => Future.value(true);
+
+ @override
+ Future halfCutPaper(int handle) => Future.value(true);
+
+ @override
+ Future fullCutPaper(int handle) => Future.value(true);
+}
+
+void main() {
+ final PrinterPlatform initialPlatform = PrinterPlatform.instance;
+
+ test('$MethodChannelPrinter is the default instance', () {
+ expect(initialPlatform, isInstanceOf());
+ });
+
+ test('getPlatformVersion', () async {
+ Printer printerPlugin = Printer();
+ MockPrinterPlatform fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ expect(await printerPlugin.getPlatformVersion(), '42');
+ });
+
+ test('openComPort delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final handle = await printer.openComPort(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+ );
+
+ expect(handle, 1);
+ });
+
+ test('openUsbPort delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final handle = await printer.openUsbPort(portName: 'USB_Printer_0');
+
+ expect(handle, 2);
+ });
+
+ test('closePort delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final result = await printer.closePort(1);
+
+ expect(result, true);
+ });
+
+ test('isPortOpened delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final result = await printer.isPortOpened(1);
+
+ expect(result, true);
+ });
+
+ test('enumComPorts delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final ports = await printer.enumComPorts();
+
+ expect(ports, ['/dev/ttyS0']);
+ });
+
+ test('enumUsbPorts delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final ports = await printer.enumUsbPorts();
+
+ expect(ports, ['USB_Printer_0']);
+ });
+
+ test('openComPortWithHandle returns valid PrinterPortHandle', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final portHandle = await printer.openComPortWithHandle(
+ portName: '/dev/ttyS0',
+ baudRate: 115200,
+ );
+
+ expect(portHandle.handle, 1);
+ expect(portHandle.isValid, true);
+ await portHandle.close();
+ expect(portHandle.isValid, false);
+ });
+
+ test('openUsbPortWithHandle returns valid PrinterPortHandle', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+
+ final portHandle = await printer.openUsbPortWithHandle(
+ portName: 'USB_Printer_0',
+ );
+
+ expect(portHandle.handle, 2);
+ expect(portHandle.isValid, true);
+ });
+
+ test('setMultiByteMode delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.setMultiByteMode(1), true);
+ });
+
+ test('setMultiByteEncoding delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.setMultiByteEncoding(1, MultiByteEncoding.utf8), true);
+ });
+
+ test('printText delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.printText(1, 'Hello 中文'), true);
+ });
+
+ test('setAlignment delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.setAlignment(1, PrinterAlignment.center), true);
+ });
+
+ test('setTextScale delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.setTextScale(1, widthScale: 2, heightScale: 2), true);
+ });
+
+ test('setTextBold delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.setTextBold(1, true), true);
+ });
+
+ test('setTextUnderline delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.setTextUnderline(1, 1), true);
+ });
+
+ test('feedLine delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.feedLine(1, 5), true);
+ });
+
+ test('feedDot delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.feedDot(1, 100), true);
+ });
+
+ test('halfCutPaper delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.halfCutPaper(1), true);
+ });
+
+ test('fullCutPaper delegates to platform interface', () async {
+ final printer = Printer();
+ final fakePlatform = MockPrinterPlatform();
+ PrinterPlatform.instance = fakePlatform;
+ expect(await printer.fullCutPaper(1), true);
+ });
+}