Android智能设备连接大师

71 阅读4分钟

📚 故事背景:你是一位「智能设备指挥官」

你的 Android 设备是一个「万能控制中心」,而串口设备、USB 打印机、扫码枪等外设是听你指挥的「特种部队」。今天,我将带你用代码指挥这些设备完成各种任务!


🧩 第一章:串口设备(电子秤/传感器)—— 古老而可靠的「电报机」

​故事​​:串口就像一台老式电报机,通过 /dev/ttyS4 这样的「频道」发送摩尔斯电码(二进制数据)。波特率 9600 是双方约定的「发报速度」。

关键代码:

java
Copy
// 电报机初始化(串口连接)
public class SerialPort {
    private FileDescriptor mFd; // 电报机的通信管道
    private FileInputStream mInputStream; // 收报机
    private FileOutputStream mOutputStream; // 发报机

    // 打开电报频道
    public SerialPort(File device, int baudrate, int flags) throws IOException {
        mFd = open(device.getAbsolutePath(), baudrate, flags); // JNI魔法!
        mInputStream = new FileInputStream(mFd);
        mOutputStream = new FileOutputStream(mFd);
    }

    // 加载电报解码器(本地库)
    static { System.loadLibrary("serial_port"); }
    private native FileDescriptor open(String path, int baudrate, int flags);
}

使用示例:

kotlin
Copy
// 1. 连接电子秤电报机
val serialPort = SerialPort(File("/dev/ttyS4"), 9600, 0)

// 2. 读取电子秤发来的重量电报
Thread {
    val inputStream = serialPort.inputStream
    while (true) {
        val buffer = ByteArray(inputStream.available())
        inputStream.read(buffer)
        val weight = parseWeight(buffer) // 解析电报内容(如:01 23 = 123g)
        runOnUiThread { displayWeight(weight) }
    }
}.start()

// 3. 发送校准指令给电子秤
fun calibrateScale() {
    val cmd = byteArrayOf(0x55, 0xAA) // 密语:开始校准!
    serialPort.outputStream.write(cmd)
}

🖨️ 第二章:USB 打印机 —— 会吐纸的「魔法画师」

​故事​​:USB 打印机是宫廷画师,Android 是国王。国王需要先颁发「御赐令牌」(USB 权限),画师才能作画。

关键步骤:

  1. ​颁发令牌​​(权限声明):

    xml
    Copy
    <uses-permission android:name="android.permission.USB_PERMISSION" />
    <uses-feature android:name="android.hardware.usb.host" />
    
  2. ​寻找画师​​(检测打印机):

    kotlin
    Copy
    val usbManager = getSystemService(USB_SERVICE) as UsbManager
    usbManager.deviceList.values.forEach { device ->
        if (device.getInterface(0).interfaceClass == 7) { // 7=画师身份码
            requestPrinterPermission(device) // 颁发令牌
        }
    }
    
  3. ​发送绘画指令​​(ESC/POS 命令):

    kotlin
    Copy
    fun printText(text: String) {
        val cmd = text.toByteArray(charset("GBK")) // 中文需转码
        usbConnection.bulkTransfer(outEndpoint, cmd, cmd.size, 5000)
    }
    
    // 魔法指令示例
    fun printLogo() {
        val cutCommand = byteArrayOf(0x1D, 0x56, 0x41) // ✂️切纸指令
        usbConnection.bulkTransfer(outEndpoint, cutCommand, cutCommand.size, 5000)
    }
    

🔍 第三章:扫码枪/支付盒子 —— 会说话的「魔法水晶」

​故事​​:扫码枪是预言水晶,扫一下商品就能念出它的「真名」(条码)。Android 只需竖起耳朵听。

监听方式:

方法一:水晶广播(全局监听)
xml
Copy
<!-- AndroidManifest.xml -->
<receiver android:name=".ScanReceiver">
    <intent-filter>
        <action android:name="com.scanner.ACTION_BARCODE" />
    </intent-filter>
</receiver>
java
Copy
// 接收水晶预言
public class ScanReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String barcode = intent.getStringExtra("SCAN_DATA"); // 水晶念出的密码
        handleBarcode(barcode);
    }
}
方法二:国王亲耳听(Activity 监听)
kotlin
Copy
// 在Activity中监听水晶低语
val barcodeBuilder = StringBuilder()

override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
    when (keyCode) {
        KeyEvent.KEYCODE_ENTER -> { // 听到「咒语结束符」
            val barcode = barcodeBuilder.toString()
            handleBarcode(barcode)
            barcodeBuilder.clear()
            return true
        }
        else -> { // 拼接待咒语
            val char = KeyUtils.keyCodeToChar(keyCode, event.isShiftPressed)
            barcodeBuilder.append(char)
        }
    }
    return super.onKeyDown(keyCode, event)
}

​避坑指南​​:
如果不想让水晶的咒语被「魔法输入框」(EditText)偷听,记得:

xml
Copy
<EditText 
    android:focusable="false" 
    android:focusableInTouchMode="false"/>

🖱️ 第四章:键盘/鼠标 —— 忠诚的「信使鸽」

​故事​​:USB 键盘和鼠标是信使鸽,Android 城堡会自动接收它们带来的消息。

特殊技巧:

kotlin
Copy
// 监听特殊信鸽(如ESC键)
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
    if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
        finish() // ESC键关闭当前窗口
        return true
    }
    return super.onKeyDown(keyCode, event)
}

💾 第五章:U盘 —— 会飞的「魔法背包」

​故事​​:U 盘是魔法师的背包,插入 USB 接口就会自动打开空间门(挂载路径)。

监听背包出现:

kotlin
Copy
val filter = IntentFilter().apply {
    addAction(Intent.ACTION_MEDIA_MOUNTED) // 背包出现!
    addAction(Intent.ACTION_MEDIA_UNMOUNTED) // 背包消失!
    addDataScheme("file") // 重要咒语!
}
registerReceiver(usbReceiver, filter)

// 检查背包里的宝物
val usbFiles = File("/storage/usb0").listFiles() 
usbFiles?.forEach { file ->
    println("发现宝物:${file.name}") 
}

⚔️ 终极战斗手册(避坑指南)

  1. ​串口数据解析​
    不同设备有不同「方言」,需按厂商协议解析:

    kotlin
    Copy
    // 电子秤数据示例:01 23 45 = 123.45g
    fun parseWeight(data: ByteArray): Double {
        val str = String(data, Charsets.US_ASCII)
        return str.substring(2, 7).toDouble() / 100
    }
    
  2. ​USB 设备重连​
    拔出后重新插入需要重新请求权限:

    kotlin
    Copy
    private val usbReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == UsbManager.ACTION_USB_DEVICE_ATTACHED) {
                val device = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)
                requestPrinterPermission(device) // 重新颁发令牌
            }
        }
    }
    
  3. ​扫码枪冲突​
    多个输入设备时,用 event.deviceId 区分来源:

    kotlin
    Copy
    override fun onKeyEvent(event: KeyEvent): Boolean {
        if (event.deviceId == scannerDeviceId) { // 只处理水晶的消息
            // 解析条码...
        }
        return true
    }
    

​指挥官备忘录​​:

  • 串口:/dev/ttyS* + 波特率 + JNI库
  • USB设备:权限声明 + UsbManager + 端点通信
  • 输入设备:监听onKeyEvent或广播
  • ​黄金法则​​:所有外设操作都要放在子线程!

现在,举起你的「代码魔杖」,开始指挥你的智能设备军团吧! 🧙‍♂️✨