From de270fe1ac7b6d1fb36b6467226f35f9cbacfe94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E9=97=BB=E9=A3=8E?= Date: Wed, 24 Jun 2026 18:50:26 +0800 Subject: [PATCH] up --- BUILD_INFO.md | 88 ++++ README.md | 214 ++++++++++ README_PRINTER_TEST.md | 157 +++++++ app/build.gradle.kts | 34 +- .../main/aidl/android/bld/IPrintManager.aidl | 21 + .../com/example/ops_android/MainActivity.kt | 391 ++++++++++++++++-- .../ops_android/printer/PrinterManager.kt | 136 ++++++ build_release.sh | 66 +++ 8 files changed, 1082 insertions(+), 25 deletions(-) create mode 100644 BUILD_INFO.md create mode 100644 README.md create mode 100644 README_PRINTER_TEST.md create mode 100644 app/src/main/aidl/android/bld/IPrintManager.aidl create mode 100644 app/src/main/java/com/example/ops_android/printer/PrinterManager.kt create mode 100755 build_release.sh diff --git a/BUILD_INFO.md b/BUILD_INFO.md new file mode 100644 index 0000000..1169eed --- /dev/null +++ b/BUILD_INFO.md @@ -0,0 +1,88 @@ +# 构建信息 + +## APK 信息 + +- **文件名**: `PDA_Printer_Test_v1.1_2_release_20260624.apk` +- **版本名称**: 1.1 +- **版本号**: 2 +- **构建类型**: Release +- **构建日期**: 2026-06-24 +- **作者**: 无闻风 + +## 文件位置 + +``` +app/build/outputs/apk/release/PDA_Printer_Test_v1.1_2_release_20260624.apk +``` + +## 版本历史 + +### v1.1 (Build 2) - 2026-06-24 +- ✨ 新增完整的打印机测试界面 +- ✨ 支持所有打印功能测试(文本、二维码、条形码) +- ✨ 支持样式设置(字体、粗体、下划线、浓度) +- ✨ 添加走纸控制功能 +- ✨ 实时状态显示 +- ✨ 综合测试功能 +- 📦 集成 android.bld.PrintManager AIDL 接口 +- 👤 作者信息集成到应用中 + +### v1.0 (Build 1) - 初始版本 +- 基础项目框架 + +## 应用特性 + +### 核心功能 +- 打印机服务绑定与管理 +- 文本打印(printText / printText2) +- 二维码打印 +- 条形码打印 +- 样式控制(字体大小、粗体、下划线、浓度) +- 走纸控制 +- 标签纸支持 + +### 测试功能 +- 快速打印测试 +- 单项功能测试 +- 完整综合测试 +- 实时状态反馈 + +## 技术栈 + +- **语言**: Kotlin +- **UI 框架**: Jetpack Compose +- **最低 SDK**: 24 (Android 7.0) +- **目标 SDK**: 36 +- **构建工具**: Gradle 9.4.1 +- **AIDL**: android.bld.PrintManager + +## 安装说明 + +1. 将 APK 文件传输到 PDA 设备 +2. 在设备上安装 APK +3. 确保设备已预装 `android.bld.PrintManager` 系统服务 +4. 打开应用开始测试 + +## 使用流程 + +1. 点击 **"绑定服务"** 连接打印服务 +2. 点击 **"初始化"** 初始化打印机 +3. 使用各项测试按钮进行功能测试 +4. 或直接点击 **"运行完整测试"** 执行所有功能 +5. 完成后点击 **"关闭打印机"** 和 **"解绑服务"** + +## 注意事项 + +⚠️ 此应用仅适用于预装 `android.bld.PrintManager` 系统服务的 PDA 设备 +⚠️ 所有打印内容添加后必须调用 `start()` 才会实际出纸 +⚠️ 使用完毕后应释放打印机资源 + +## 下次构建 + +下次构建时版本号将自动递增到 v1.2 (Build 3) + +--- + +**构建者**: 无闻风 +**构建时间**: 2026-06-24 +**项目路径**: `/Users/wuwenfeng/Documents/prj/ops_android` diff --git a/README.md b/README.md new file mode 100644 index 0000000..90d3804 --- /dev/null +++ b/README.md @@ -0,0 +1,214 @@ +# PDA 打印机测试应用 + +一个用于测试内置 PDA 终端打印机的 Android 应用,基于 Jetpack Compose 构建。 + +![版本](https://img.shields.io/badge/版本-1.1-blue) +![SDK](https://img.shields.io/badge/MinSDK-24-green) +![构建](https://img.shields.io/badge/构建-成功-brightgreen) + +## 📱 应用截图 + +应用提供完整的打印机测试界面,包含: +- 实时连接状态显示 +- 完整的打印功能测试 +- 样式设置控制 +- 二维码/条形码打印 +- 走纸控制 +- 一键综合测试 + +## ✨ 功能特性 + +### 🔌 连接管理 +- 绑定/解绑打印服务 +- 初始化/关闭打印机 +- 实时状态监控 + +### 📄 打印功能 +- 文本打印 (printText / printText2) +- 二维码生成与打印 +- 条形码生成与打印 +- 图片打印支持 + +### 🎨 样式控制 +- 字体大小调整 +- 粗体设置 +- 下划线设置 +- 打印浓度控制 + +### 📏 走纸控制 +- 打印空行 +- 走纸间距设置 +- 标签纸支持 + +### 🧪 测试工具 +- 快速打印测试 +- 单项功能测试 +- 完整综合测试 + +## 🚀 快速开始 + +### 环境要求 + +- Android Studio Hedgehog 或更高版本 +- JDK 11 +- Android SDK 24+ +- 目标设备需预装 `android.bld.PrintManager` 系统服务 + +### 编译安装 + +#### 方法一:使用自动构建脚本(推荐) + +```bash +./build_release.sh +``` + +该脚本会自动: +- 增加版本号 +- 清理并编译 Release APK +- 复制 APK 到项目根目录 + +#### 方法二:手动编译 + +```bash +./gradlew clean assembleRelease +``` + +生成的 APK 位于: +``` +app/build/outputs/apk/release/PDA_Printer_Test_v{版本号}_release_{日期}.apk +``` + +### 安装到设备 + +```bash +adb install -r app/build/outputs/apk/release/PDA_Printer_Test_v1.1_2_release_20260624.apk +``` + +## 📖 使用说明 + +### 基本流程 + +1. **启动应用** → 打开 PDA 打印机测试应用 +2. **绑定服务** → 点击"绑定服务"按钮连接打印服务 +3. **初始化** → 点击"初始化"按钮初始化打印机 +4. **测试打印** → 使用各项测试按钮或运行完整测试 +5. **关闭释放** → 完成后点击"关闭打印机"和"解绑服务" + +### 快速测试 + +点击 **"快速打印测试"** 按钮可一键完成: +``` +初始化 → 打印测试文本 → 提交打印 → 关闭打印机 +``` + +### 综合测试 + +点击 **"运行完整测试"** 按钮将打印包含以下内容的测试单: +- 标题(大字体、粗体) +- 普通文本示例 +- 粗体文本示例 +- 下划线文本示例 +- 二维码(https://example.com) +- 条形码(123456789012) +- 分隔线 + +## 🏗️ 项目结构 + +``` +ops_android/ +├── app/ +│ └── src/ +│ └── main/ +│ ├── aidl/android/bld/ +│ │ └── IPrintManager.aidl # 打印服务接口定义 +│ ├── java/com/example/ops_android/ +│ │ ├── MainActivity.kt # 主界面 +│ │ └── printer/ +│ │ └── PrinterManager.kt # 打印机管理器 +│ └── AndroidManifest.xml +├── build_release.sh # 自动构建脚本 +├── BUILD_INFO.md # 构建信息 +└── README_PRINTER_TEST.md # 详细文档 +``` + +## 🔧 API 参考 + +### PrinterManager 主要方法 + +```kotlin +// 连接控制 +fun bindService(): Boolean +fun unbindService() +fun initPrinter(): Result +fun closePrinter(): Result + +// 打印内容 +fun printText(text: String): Result +fun printText2(text: String): Result +fun printQR(content: String, size: Int = 6): Result +fun printBarcode(content: String, type: Int = 0, width: Int = 2, height: Int = 60): Result +fun printLine(lineCount: Int = 1): Result +fun start(): Result // ⚠️ 必须调用才会实际打印 + +// 样式设置 +fun setFontSize(size: Int): Result +fun setTextBold(bold: Boolean): Result +fun setUnderLine(underline: Boolean): Result +fun setConcentration(level: Int): Result +``` + +### 使用示例 + +```kotlin +val printerManager = PrinterManager(context) + +// 打印文本 +printerManager.bindService() +printerManager.initPrinter() +printerManager.printText2("Hello World\n") +printerManager.start() // ⚠️ 重要:提交打印 +printerManager.closePrinter() +printerManager.unbindService() + +// 打印二维码 +printerManager.initPrinter() +printerManager.printQR("https://example.com", 6) +printerManager.start() +printerManager.closePrinter() +``` + +## ⚠️ 注意事项 + +1. **必须调用 start()**: 所有打印内容添加后,必须调用 `start()` 方法才会实际出纸 +2. **服务依赖**: 应用依赖设备预装的 `android.bld.PrintManager` 系统服务 +3. **资源管理**: 使用完毕后应及时释放打印机资源 +4. **错误处理**: 所有方法返回 `Result`,需要正确处理成功/失败情况 + +## 📝 版本历史 + +### v1.1 (Build 2) - 2026-06-24 +- ✨ 完整的打印机测试界面 +- ✨ 所有打印功能支持 +- ✨ 实时状态显示 +- ✨ 综合测试功能 +- 📦 AIDL 接口集成 +- 👤 作者信息显示 + +### v1.0 (Build 1) +- 🎉 初始版本 + +## 👤 作者 + +**无闻风** + +## 📄 许可证 + +本项目仅供内部测试使用 + +## 🤝 技术支持 + +如有问题或建议,请联系开发团队。 + +--- + +**最后更新**: 2026-06-24 diff --git a/README_PRINTER_TEST.md b/README_PRINTER_TEST.md new file mode 100644 index 0000000..b8428df --- /dev/null +++ b/README_PRINTER_TEST.md @@ -0,0 +1,157 @@ +# PDA 打印机测试应用 + +这是一个用于测试内置 PDA 终端打印机的 Android 应用,通过 `android.bld.PrintManager` 系统服务进行打印控制。 + +## 功能特性 + +### 连接控制 +- **绑定服务**:连接到系统的打印服务 +- **初始化打印机**:初始化打印设备 +- **关闭打印机**:释放打印设备 +- **解绑服务**:断开打印服务连接 + +### 基础打印 +- **快速打印测试**:一键完成初始化→打印→提交→关闭的完整流程 +- **printText**:标准文本打印方法 +- **printText2**:增强文本打印方法 +- **start()**:提交打印队列,开始实际出纸 + +### 样式设置 +- **字体大小**:调整打印文字大小 +- **粗体**:设置文字粗体 +- **下划线**:添加文字下划线 +- **浓度**:调整打印浓度 + +### 二维码与条形码 +- **打印二维码**:生成并打印 QR 码 +- **打印条形码**:生成并打印一维条形码 + +### 走纸控制 +- **打印空行**:添加空白行 +- **走纸间距**:设置纸张走纸距离 + +### 综合测试 +- **运行完整测试**:自动执行完整的功能测试流程,包含所有打印特性 + +## 使用方法 + +### 基本流程 + +1. **绑定服务** → 连接到打印服务 +2. **初始化** → 初始化打印机硬件 +3. **设置样式**(可选)→ 设置字体、粗体等 +4. **添加内容** → 调用 printText/printQR 等方法 +5. **提交打印** → 调用 start() 开始实际打印 +6. **关闭打印机** → 完成后释放资源 + +### 快速测试 + +点击 **"快速打印测试"** 按钮可以一键完成整个流程,打印 "Hello Printer!" 测试文本。 + +### 完整测试 + +点击 **"运行完整测试"** 按钮将执行包含以下内容的完整测试: +- 标题(大字体、粗体) +- 普通文本 +- 粗体文本 +- 下划线文本 +- 二维码 +- 条形码 +- 分隔线 + +## 代码结构 + +``` +app/src/main/ +├── aidl/android/bld/ +│ └── IPrintManager.aidl # AIDL 接口定义 +├── java/com/example/ops_android/ +│ ├── MainActivity.kt # 主界面和测试 UI +│ └── printer/ +│ └── PrinterManager.kt # 打印机封装类 +``` + +## AIDL 接口 + +系统服务 `android.bld.PrintManager` 提供的主要方法: + +| 方法 | 说明 | +|------|------| +| `initPrinter()` | 初始化打印机 | +| `closePrinter()` | 关闭打印机 | +| `printText(text)` | 打印文本 | +| `printText2(text)` | 打印文本(增强版) | +| `printQR(content, size)` | 打印二维码 | +| `printBarcode(content, type, width, height)` | 打印条形码 | +| `printLine(count)` | 打印空行 | +| `start()` | **重要:提交打印,开始出纸** | +| `setFontSize(size)` | 设置字体大小 | +| `setTextBold(bold)` | 设置粗体 | +| `setUnderLine(underline)` | 设置下划线 | +| `setConcentration(level)` | 设置浓度 | + +## 注意事项 + +1. **必须调用 start()**:所有打印内容添加到队列后,必须调用 `start()` 才会实际打印出纸 +2. **服务绑定**:需要先绑定服务并初始化打印机才能使用打印功能 +3. **资源释放**:使用完毕后应调用 `closePrinter()` 和 `unbindService()` 释放资源 +4. **错误处理**:所有方法返回 `Result` 类型,使用 `fold` 或 `onSuccess`/`onFailure` 处理结果 +5. **系统服务**:此应用依赖于设备预装的 `android.bld.PrintManager` 系统服务,普通 Android 设备无此服务 + +## 编译要求 + +- Android SDK 24+ +- Kotlin +- Jetpack Compose +- AIDL 支持(已在 build.gradle.kts 中启用) + +## 测试环境 + +此应用专为内置 PDA 打印机的定制 Android 设备设计,需要设备厂商在 `/system/framework/` 下预装 `android.bld.PrintManager` 服务。 + +## 状态显示 + +应用顶部的状态卡片会实时显示: +- 连接状态(绿色:已连接,红色:未连接) +- 操作结果 +- 错误信息 + +## 示例代码 + +### 基础使用 + +```kotlin +val printerManager = PrinterManager(context) + +// 绑定服务 +printerManager.bindService() + +// 打印 +printerManager.initPrinter() +printerManager.printText2("Hello World\n") +printerManager.start() +printerManager.closePrinter() + +// 解绑 +printerManager.unbindService() +``` + +### 样式控制 + +```kotlin +printerManager.setFontSize(32) +printerManager.setTextBold(true) +printerManager.printText2("标题\n") +printerManager.setTextBold(false) +printerManager.printText2("内容\n") +printerManager.start() +``` + +### 打印二维码 + +```kotlin +printerManager.initPrinter() +printerManager.printQR("https://example.com", 6) +printerManager.start() +printerManager.closePrinter() +``` diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b857652..abda6f1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,6 @@ +import java.text.SimpleDateFormat +import java.util.Date + plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.compose) @@ -15,10 +18,14 @@ android { applicationId = "com.example.ops_android" minSdk = 24 targetSdk = 36 - versionCode = 1 - versionName = "1.0" + versionCode = 2 + versionName = "1.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + // 作者信息 + buildConfigField("String", "AUTHOR", "\"无闻风\"") + buildConfigField("String", "BUILD_DATE", "\"${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}\"") } buildTypes { @@ -26,6 +33,15 @@ android { optimization { enable = false } + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + debug { + applicationIdSuffix = ".debug" + versionNameSuffix = "-debug" } } compileOptions { @@ -34,6 +50,20 @@ android { } buildFeatures { compose = true + aidl = true + buildConfig = true + } +} + +androidComponents { + onVariants { variant -> + variant.outputs.forEach { output -> + val versionName = "1.1" + val versionCode = "2" + val buildType = variant.buildType + val date = SimpleDateFormat("yyyyMMdd").format(Date()) + output.outputFileName.set("PDA_Printer_Test_v${versionName}_${versionCode}_${buildType}_${date}.apk") + } } } diff --git a/app/src/main/aidl/android/bld/IPrintManager.aidl b/app/src/main/aidl/android/bld/IPrintManager.aidl new file mode 100644 index 0000000..f258853 --- /dev/null +++ b/app/src/main/aidl/android/bld/IPrintManager.aidl @@ -0,0 +1,21 @@ +package android.bld; + +interface IPrintManager { + void initPrinter(); + void closePrinter(); + void printText(String text); + void printText2(String text); + void printQR(String content, int size); + void printBarcode(String content, int type, int width, int height); + void printBitmap(in byte[] bitmap, int width, int height); + void printLine(int lineCount); + void start(); + void setFontSize(int size); + void setTextBold(boolean bold); + void setUnderLine(boolean underline); + void setConcentration(int level); + void setFeedPaperSpace(int space); + void setUnwindPaperLen(int length); + void printEnableMark(boolean enable); + void printGoToNextMark(); +} diff --git a/app/src/main/java/com/example/ops_android/MainActivity.kt b/app/src/main/java/com/example/ops_android/MainActivity.kt index 6e5152e..6f545ea 100644 --- a/app/src/main/java/com/example/ops_android/MainActivity.kt +++ b/app/src/main/java/com/example/ops_android/MainActivity.kt @@ -4,44 +4,389 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.example.ops_android.printer.PrinterManager import com.example.ops_android.ui.theme.Ops_androidTheme class MainActivity : ComponentActivity() { + private lateinit var printerManager: PrinterManager + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + printerManager = PrinterManager(this) + enableEdgeToEdge() setContent { Ops_androidTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Greeting( - name = "Android", + PrinterTestScreen( + printerManager = printerManager, modifier = Modifier.padding(innerPadding) ) } } } } -} -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - Ops_androidTheme { - Greeting("Android") + override fun onDestroy() { + super.onDestroy() + printerManager.unbindService() } -} \ No newline at end of file +} + +@Composable +fun PrinterTestScreen( + printerManager: PrinterManager, + modifier: Modifier = Modifier +) { + var statusMessage by remember { mutableStateOf("未连接打印服务") } + var isConnected by remember { mutableStateOf(false) } + + Column( + modifier = modifier + .fillMaxSize() + .padding(16.dp) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + // 标题 + Text( + text = "PDA 打印机测试", + style = MaterialTheme.typography.headlineMedium, + modifier = Modifier.padding(bottom = 8.dp) + ) + + // 版本信息 + Text( + text = "v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) - ${BuildConfig.AUTHOR}", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(bottom = 8.dp) + ) + + // 状态显示 + Card( + colors = CardDefaults.cardColors( + containerColor = if (isConnected) + MaterialTheme.colorScheme.primaryContainer + else + MaterialTheme.colorScheme.errorContainer + ) + ) { + Text( + text = statusMessage, + modifier = Modifier.padding(16.dp), + style = MaterialTheme.typography.bodyMedium + ) + } + + Divider() + + // 连接控制区 + Text("连接控制", style = MaterialTheme.typography.titleMedium) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Button( + onClick = { + val success = printerManager.bindService() + isConnected = success + statusMessage = if (success) "正在连接打印服务..." else "连接失败" + }, + modifier = Modifier.weight(1f) + ) { + Text("绑定服务") + } + + Button( + onClick = { + printerManager.initPrinter().fold( + onSuccess = { statusMessage = "打印机初始化成功" }, + onFailure = { statusMessage = "初始化失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("初始化") + } + } + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Button( + onClick = { + printerManager.closePrinter().fold( + onSuccess = { statusMessage = "打印机已关闭" }, + onFailure = { statusMessage = "关闭失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("关闭打印机") + } + + Button( + onClick = { + printerManager.unbindService() + isConnected = false + statusMessage = "服务已解绑" + }, + modifier = Modifier.weight(1f) + ) { + Text("解绑服务") + } + } + + Divider() + + // 基础打印测试 + Text("基础打印测试", style = MaterialTheme.typography.titleMedium) + + Button( + onClick = { + printerManager.quickPrintText("Hello Printer!\n测试打印\n").fold( + onSuccess = { statusMessage = "快速打印成功" }, + onFailure = { statusMessage = "打印失败: ${it.message}" } + ) + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("快速打印测试") + } + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Button( + onClick = { + printerManager.printText("使用 printText\n").fold( + onSuccess = { statusMessage = "printText 调用成功" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("printText") + } + + Button( + onClick = { + printerManager.printText2("使用 printText2\n").fold( + onSuccess = { statusMessage = "printText2 调用成功" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("printText2") + } + } + + Button( + onClick = { + printerManager.start().fold( + onSuccess = { statusMessage = "开始打印(出纸)" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("start() - 提交打印") + } + + Divider() + + // 样式测试 + Text("样式设置", style = MaterialTheme.typography.titleMedium) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Button( + onClick = { + printerManager.setFontSize(24).fold( + onSuccess = { statusMessage = "字体大小已设置" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("大字体") + } + + Button( + onClick = { + printerManager.setTextBold(true).fold( + onSuccess = { statusMessage = "已设置粗体" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("粗体") + } + } + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Button( + onClick = { + printerManager.setUnderLine(true).fold( + onSuccess = { statusMessage = "已设置下划线" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("下划线") + } + + Button( + onClick = { + printerManager.setConcentration(5).fold( + onSuccess = { statusMessage = "浓度已设置" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("浓度") + } + } + + Divider() + + // 二维码/条形码测试 + Text("二维码与条形码", style = MaterialTheme.typography.titleMedium) + + Button( + onClick = { + printerManager.printQR("https://example.com", 6).fold( + onSuccess = { statusMessage = "二维码已加入队列" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("打印二维码") + } + + Button( + onClick = { + printerManager.printBarcode("1234567890", 0, 2, 60).fold( + onSuccess = { statusMessage = "条形码已加入队列" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("打印条形码") + } + + Divider() + + // 走纸控制 + Text("走纸控制", style = MaterialTheme.typography.titleMedium) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + Button( + onClick = { + printerManager.printLine(3).fold( + onSuccess = { statusMessage = "打印空行" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("打印3空行") + } + + Button( + onClick = { + printerManager.setFeedPaperSpace(100).fold( + onSuccess = { statusMessage = "走纸间距已设置" }, + onFailure = { statusMessage = "失败: ${it.message}" } + ) + }, + modifier = Modifier.weight(1f) + ) { + Text("走纸间距") + } + } + + Divider() + + // 综合测试 + Text("综合测试", style = MaterialTheme.typography.titleMedium) + + Button( + onClick = { + runComprehensiveTest(printerManager) { msg -> statusMessage = msg } + }, + modifier = Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.secondary + ) + ) { + Text("运行完整测试") + } + } +} + +private fun runComprehensiveTest( + printerManager: PrinterManager, + onStatus: (String) -> Unit +) { + onStatus("开始综合测试...") + + printerManager.initPrinter().onFailure { + onStatus("初始化失败: ${it.message}") + return + } + + // 标题 + printerManager.setFontSize(32) + printerManager.setTextBold(true) + printerManager.printText2("=== 打印测试 ===\n") + + // 普通文本 + printerManager.setFontSize(24) + printerManager.setTextBold(false) + printerManager.printText2("普通文本测试\n") + + // 粗体文本 + printerManager.setTextBold(true) + printerManager.printText2("粗体文本测试\n") + printerManager.setTextBold(false) + + // 下划线文本 + printerManager.setUnderLine(true) + printerManager.printText2("下划线文本测试\n") + printerManager.setUnderLine(false) + + // 空行 + printerManager.printLine(1) + + // 二维码 + printerManager.printText2("二维码测试:\n") + printerManager.printQR("https://example.com", 6) + printerManager.printLine(1) + + // 条形码 + printerManager.printText2("条形码测试:\n") + printerManager.printBarcode("123456789012", 0, 2, 60) + printerManager.printLine(3) + + // 分隔线 + printerManager.printText2("--------------------------------\n") + printerManager.printText2("测试完成\n") + printerManager.printLine(2) + + // 提交打印 + printerManager.start().fold( + onSuccess = { onStatus("综合测试完成,开始打印") }, + onFailure = { onStatus("提交打印失败: ${it.message}") } + ) + + printerManager.closePrinter() +} diff --git a/app/src/main/java/com/example/ops_android/printer/PrinterManager.kt b/app/src/main/java/com/example/ops_android/printer/PrinterManager.kt new file mode 100644 index 0000000..5dd5cc2 --- /dev/null +++ b/app/src/main/java/com/example/ops_android/printer/PrinterManager.kt @@ -0,0 +1,136 @@ +package com.example.ops_android.printer + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import android.util.Log +import android.bld.IPrintManager + +class PrinterManager(private val context: Context) { + private var printService: IPrintManager? = null + private var isBound = false + + companion object { + private const val TAG = "PrinterManager" + private const val PRINT_SERVICE_ACTION = "android.bld.PrintManager" + private const val PRINT_SERVICE_PACKAGE = "android.bld" + } + + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + printService = IPrintManager.Stub.asInterface(service) + isBound = true + Log.d(TAG, "Print service connected") + } + + override fun onServiceDisconnected(name: ComponentName?) { + printService = null + isBound = false + Log.d(TAG, "Print service disconnected") + } + } + + fun bindService(): Boolean { + return try { + val intent = Intent(PRINT_SERVICE_ACTION).apply { + setPackage(PRINT_SERVICE_PACKAGE) + } + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } catch (e: Exception) { + Log.e(TAG, "Failed to bind print service", e) + false + } + } + + fun unbindService() { + if (isBound) { + context.unbindService(serviceConnection) + isBound = false + } + } + + // 基础连接方法 + fun initPrinter(): Result = runCatching { + printService?.initPrinter() ?: throw Exception("Print service not connected") + } + + fun closePrinter(): Result = runCatching { + printService?.closePrinter() ?: throw Exception("Print service not connected") + } + + // 打印方法 + fun printText(text: String): Result = runCatching { + printService?.printText(text) ?: throw Exception("Print service not connected") + } + + fun printText2(text: String): Result = runCatching { + printService?.printText2(text) ?: throw Exception("Print service not connected") + } + + fun printQR(content: String, size: Int = 6): Result = runCatching { + printService?.printQR(content, size) ?: throw Exception("Print service not connected") + } + + fun printBarcode(content: String, type: Int = 0, width: Int = 2, height: Int = 60): Result = runCatching { + printService?.printBarcode(content, type, width, height) ?: throw Exception("Print service not connected") + } + + fun printBitmap(bitmap: ByteArray, width: Int, height: Int): Result = runCatching { + printService?.printBitmap(bitmap, width, height) ?: throw Exception("Print service not connected") + } + + fun printLine(lineCount: Int = 1): Result = runCatching { + printService?.printLine(lineCount) ?: throw Exception("Print service not connected") + } + + fun start(): Result = runCatching { + printService?.start() ?: throw Exception("Print service not connected") + } + + // 样式设置方法 + fun setFontSize(size: Int): Result = runCatching { + printService?.setFontSize(size) ?: throw Exception("Print service not connected") + } + + fun setTextBold(bold: Boolean): Result = runCatching { + printService?.setTextBold(bold) ?: throw Exception("Print service not connected") + } + + fun setUnderLine(underline: Boolean): Result = runCatching { + printService?.setUnderLine(underline) ?: throw Exception("Print service not connected") + } + + fun setConcentration(level: Int): Result = runCatching { + printService?.setConcentration(level) ?: throw Exception("Print service not connected") + } + + // 走纸控制 + fun setFeedPaperSpace(space: Int): Result = runCatching { + printService?.setFeedPaperSpace(space) ?: throw Exception("Print service not connected") + } + + fun setUnwindPaperLen(length: Int): Result = runCatching { + printService?.setUnwindPaperLen(length) ?: throw Exception("Print service not connected") + } + + // 标签纸控制 + fun printEnableMark(enable: Boolean): Result = runCatching { + printService?.printEnableMark(enable) ?: throw Exception("Print service not connected") + } + + fun printGoToNextMark(): Result = runCatching { + printService?.printGoToNextMark() ?: throw Exception("Print service not connected") + } + + // 便捷组合方法 + fun quickPrintText(text: String): Result = runCatching { + initPrinter().getOrThrow() + printText2(text).getOrThrow() + start().getOrThrow() + closePrinter().getOrThrow() + } + + fun isServiceConnected(): Boolean = isBound && printService != null +} diff --git a/build_release.sh b/build_release.sh new file mode 100755 index 0000000..1173f3d --- /dev/null +++ b/build_release.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# 自动构建脚本 - 自动增加版本号并编译APK + +# 颜色定义 +GREEN='\033[0;32m' +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +echo -e "${BLUE}==================================${NC}" +echo -e "${BLUE} PDA 打印机测试应用 - 自动构建${NC}" +echo -e "${BLUE}==================================${NC}" + +# 读取当前版本 +BUILD_FILE="app/build.gradle.kts" +CURRENT_VERSION=$(grep "versionCode = " "$BUILD_FILE" | sed 's/.*versionCode = //' | sed 's/[^0-9]//g') +CURRENT_VERSION_NAME=$(grep "versionName = " "$BUILD_FILE" | sed 's/.*versionName = "//' | sed 's/".*//') + +echo -e "${GREEN}当前版本: v${CURRENT_VERSION_NAME} (Build ${CURRENT_VERSION})${NC}" + +# 计算新版本 +NEW_VERSION=$((CURRENT_VERSION + 1)) +# 计算新版本名称 (简单递增小版本号) +IFS='.' read -r major minor <<< "$CURRENT_VERSION_NAME" +NEW_MINOR=$((minor + 1)) +NEW_VERSION_NAME="${major}.${NEW_MINOR}" + +echo -e "${GREEN}新版本: v${NEW_VERSION_NAME} (Build ${NEW_VERSION})${NC}" + +# 更新版本号 +sed -i.bak "s/versionCode = $CURRENT_VERSION/versionCode = $NEW_VERSION/" "$BUILD_FILE" +sed -i.bak "s/versionName = \"$CURRENT_VERSION_NAME\"/versionName = \"$NEW_VERSION_NAME\"/" "$BUILD_FILE" +rm -f "${BUILD_FILE}.bak" + +echo -e "${GREEN}✓ 版本号已更新${NC}" + +# 清理并编译 +echo -e "${BLUE}开始编译...${NC}" +./gradlew clean assembleRelease --no-daemon + +if [ $? -eq 0 ]; then + echo -e "${GREEN}==================================${NC}" + echo -e "${GREEN} ✓ 编译成功!${NC}" + echo -e "${GREEN}==================================${NC}" + + # 查找生成的APK + APK_PATH=$(find app/build/outputs/apk/release -name "*.apk" -type f | head -n 1) + + if [ -n "$APK_PATH" ]; then + APK_SIZE=$(du -h "$APK_PATH" | cut -f1) + echo -e "${GREEN}APK 文件: ${APK_PATH}${NC}" + echo -e "${GREEN}文件大小: ${APK_SIZE}${NC}" + + # 可选:复制到项目根目录 + cp "$APK_PATH" "./PDA_Printer_Test_latest.apk" + echo -e "${GREEN}✓ 已复制到: ./PDA_Printer_Test_latest.apk${NC}" + fi +else + echo -e "${RED}✗ 编译失败${NC}" + # 恢复版本号 + sed -i.bak "s/versionCode = $NEW_VERSION/versionCode = $CURRENT_VERSION/" "$BUILD_FILE" + sed -i.bak "s/versionName = \"$NEW_VERSION_NAME\"/versionName = \"$CURRENT_VERSION_NAME\"/" "$BUILD_FILE" + rm -f "${BUILD_FILE}.bak" + echo -e "${RED}已恢复原版本号${NC}" + exit 1 +fi