This commit is contained in:
2026-06-24 18:50:26 +08:00
parent b557f8b904
commit de270fe1ac
8 changed files with 1082 additions and 25 deletions
+88
View File
@@ -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`
+214
View File
@@ -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<Unit>
fun closePrinter(): Result<Unit>
// 打印内容
fun printText(text: String): Result<Unit>
fun printText2(text: String): Result<Unit>
fun printQR(content: String, size: Int = 6): Result<Unit>
fun printBarcode(content: String, type: Int = 0, width: Int = 2, height: Int = 60): Result<Unit>
fun printLine(lineCount: Int = 1): Result<Unit>
fun start(): Result<Unit> // ⚠️ 必须调用才会实际打印
// 样式设置
fun setFontSize(size: Int): Result<Unit>
fun setTextBold(bold: Boolean): Result<Unit>
fun setUnderLine(underline: Boolean): Result<Unit>
fun setConcentration(level: Int): Result<Unit>
```
### 使用示例
```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<Unit>`,需要正确处理成功/失败情况
## 📝 版本历史
### v1.1 (Build 2) - 2026-06-24
- ✨ 完整的打印机测试界面
- ✨ 所有打印功能支持
- ✨ 实时状态显示
- ✨ 综合测试功能
- 📦 AIDL 接口集成
- 👤 作者信息显示
### v1.0 (Build 1)
- 🎉 初始版本
## 👤 作者
**无闻风**
## 📄 许可证
本项目仅供内部测试使用
## 🤝 技术支持
如有问题或建议,请联系开发团队。
---
**最后更新**: 2026-06-24
+157
View File
@@ -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<Unit>` 类型,使用 `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()
```
+32 -2
View File
@@ -1,3 +1,6 @@
import java.text.SimpleDateFormat
import java.util.Date
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.compose)
@@ -15,10 +18,14 @@ android {
applicationId = "com.example.ops_android" applicationId = "com.example.ops_android"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 1 versionCode = 2
versionName = "1.0" versionName = "1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// 作者信息
buildConfigField("String", "AUTHOR", "\"无闻风\"")
buildConfigField("String", "BUILD_DATE", "\"${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}\"")
} }
buildTypes { buildTypes {
@@ -26,6 +33,15 @@ android {
optimization { optimization {
enable = false enable = false
} }
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
} }
} }
compileOptions { compileOptions {
@@ -34,6 +50,20 @@ android {
} }
buildFeatures { buildFeatures {
compose = true 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")
}
} }
} }
@@ -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();
}
@@ -4,44 +4,389 @@ import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Scaffold import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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 import com.example.ops_android.ui.theme.Ops_androidTheme
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private lateinit var printerManager: PrinterManager
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
printerManager = PrinterManager(this)
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
Ops_androidTheme { Ops_androidTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting( PrinterTestScreen(
name = "Android", printerManager = printerManager,
modifier = Modifier.padding(innerPadding) modifier = Modifier.padding(innerPadding)
) )
} }
} }
} }
} }
}
@Composable override fun onDestroy() {
fun Greeting(name: String, modifier: Modifier = Modifier) { super.onDestroy()
Text( printerManager.unbindService()
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
Ops_androidTheme {
Greeting("Android")
} }
} }
@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()
}
@@ -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<Unit> = runCatching {
printService?.initPrinter() ?: throw Exception("Print service not connected")
}
fun closePrinter(): Result<Unit> = runCatching {
printService?.closePrinter() ?: throw Exception("Print service not connected")
}
// 打印方法
fun printText(text: String): Result<Unit> = runCatching {
printService?.printText(text) ?: throw Exception("Print service not connected")
}
fun printText2(text: String): Result<Unit> = runCatching {
printService?.printText2(text) ?: throw Exception("Print service not connected")
}
fun printQR(content: String, size: Int = 6): Result<Unit> = 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<Unit> = runCatching {
printService?.printBarcode(content, type, width, height) ?: throw Exception("Print service not connected")
}
fun printBitmap(bitmap: ByteArray, width: Int, height: Int): Result<Unit> = runCatching {
printService?.printBitmap(bitmap, width, height) ?: throw Exception("Print service not connected")
}
fun printLine(lineCount: Int = 1): Result<Unit> = runCatching {
printService?.printLine(lineCount) ?: throw Exception("Print service not connected")
}
fun start(): Result<Unit> = runCatching {
printService?.start() ?: throw Exception("Print service not connected")
}
// 样式设置方法
fun setFontSize(size: Int): Result<Unit> = runCatching {
printService?.setFontSize(size) ?: throw Exception("Print service not connected")
}
fun setTextBold(bold: Boolean): Result<Unit> = runCatching {
printService?.setTextBold(bold) ?: throw Exception("Print service not connected")
}
fun setUnderLine(underline: Boolean): Result<Unit> = runCatching {
printService?.setUnderLine(underline) ?: throw Exception("Print service not connected")
}
fun setConcentration(level: Int): Result<Unit> = runCatching {
printService?.setConcentration(level) ?: throw Exception("Print service not connected")
}
// 走纸控制
fun setFeedPaperSpace(space: Int): Result<Unit> = runCatching {
printService?.setFeedPaperSpace(space) ?: throw Exception("Print service not connected")
}
fun setUnwindPaperLen(length: Int): Result<Unit> = runCatching {
printService?.setUnwindPaperLen(length) ?: throw Exception("Print service not connected")
}
// 标签纸控制
fun printEnableMark(enable: Boolean): Result<Unit> = runCatching {
printService?.printEnableMark(enable) ?: throw Exception("Print service not connected")
}
fun printGoToNextMark(): Result<Unit> = runCatching {
printService?.printGoToNextMark() ?: throw Exception("Print service not connected")
}
// 便捷组合方法
fun quickPrintText(text: String): Result<Unit> = runCatching {
initPrinter().getOrThrow()
printText2(text).getOrThrow()
start().getOrThrow()
closePrinter().getOrThrow()
}
fun isServiceConnected(): Boolean = isBound && printService != null
}
+66
View File
@@ -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