KMP 代码范例 - 通过 OP-BT / OP-BTS 蓝牙光电头发送命令并显示响应


KMP BLE Demo(iOS & Android):通过 OP-BT / OP-BTS 蓝牙光电头发送命令并显示响应

本页面依据最新的 KMP BLE Demo-251222-ios-android.md 示例整理,演示如何使用 Kotlin Multiplatform (KMP) + Android BLE GATT + iOS CoreBluetooth 与 OP-BT / OP-BTS 设备通信,在 Android 和 iOS 上发送命令 BaudTran,9600,N,8,1,并在界面上显示设备返回结果(例如:OK,VER=01.00)。两个平台通过 KMP 输出的 shared 模块共享核心逻辑。

1. 构建要求与环境准备

  • 开发工具:Android Studio
  • Kotlin Multiplatform (KMP) 模板必须在 File → New → New Project 下可用
  • JDK:Gradle/AGP 运行在 JDK 17 上。项目编译目标为 Java 11
  • 新建项目参数:
    • 项目名称:OPManagerDemo
    • 模板:Kotlin Multiplatform (KMP)
    • 语言:Kotlin
    • 最低 SDK:Android 5.0 (API 21) 及以上

源代码

本示例的完整源代码可在 GitHub 上获取:

您可以直接克隆仓库并在 Android Studio 中打开:

git clone https://github.com/zenovate-team/OPManagerDemo-KMP.git
cd OPManagerDemo-KMP

2. Demo 功能说明

2.1 主要功能

  1. 扫描附近的 BLE 蓝牙设备
  2. 列表展示设备名称和 MAC 地址
  3. 选择目标设备并建立 BLE GATT 连接
  4. 发送命令:BaudTran,9600,N,8,1
  5. 通过通知特征接收设备返回,例如:OK,VER=01.00
  6. 在界面上以日志方式显示连接状态 / 发送命令 / 接收数据

2.2 使用到的 API / 库

  • 蓝牙通信(BLE GATT)
    • BluetoothLeScanner
    • BluetoothGatt / BluetoothGattCallback
    • BluetoothGattCharacteristic / BluetoothGattDescriptor
  • 运行时权限
    • AndroidX Activity Result API:ActivityResultContracts.RequestMultiplePermissions
  • Kotlin Multiplatform
    • 包含 commonMainandroidMain 源集的共享模块
    • 用于跨平台兼容性的共享模型和工具

2.3 通信协议与 UUID

  • 文本命令:

    • 发送:BaudTran,9600,N,8,1
    • 典型响应:OK,VER=01.00
  • GATT UUID 配置(支持 16-bit / 32-bit / 128-bit 写法):

    • Service UUID:18F0
    • Notification Characteristic UUID:2AF0
    • Write Characteristic UUID:2AF1

3. 界面截图

设备扫描界面:展示附近 BLE 设备并提供连接按钮

设备扫描列表界面示意图

连接详情界面:输入命令并显示设备响应日志

命令发送与响应日志界面示意图

4. 修改 Android 权限(AndroidManifest.xml)

编辑:app/src/main/AndroidManifest.xml,参考配置如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- 蓝牙权限(兼容 Android 12 前后) -->
    <!-- Android 11 及以下使用的传统蓝牙 / 位置权限 -->
    <uses-permission
        android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission
        android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
    <uses-permission
        android:name="android.permission.ACCESS_COARSE_LOCATION"
        android:maxSdkVersion="30" />
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION"
        android:maxSdkVersion="30" />

    <!-- Android 12+ 新增蓝牙运行时权限 -->
    <uses-permission
        android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- 蓝牙 / BLE 硬件特性(可选,推荐设为 false,方便非 BLE 设备安装) -->
    <uses-feature
        android:name="android.hardware.bluetooth"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="false" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.OPManagerDemo">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.OPManagerDemo">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

运行时权限申请逻辑在 Kotlin 代码中通过 ActivityResultContracts.RequestMultiplePermissions 实现(见下节)。

5. 同步项目(Gradle)

打开项目后,点击 Sync Now(或 File → Sync Project with Gradle Files)。

  • Gradle 会自动下载此仓库定义的所需依赖和 Android 组件。
  • 同步成功后,项目应该能够在设备上构建和运行。

在此阶段,您不需要手动添加依赖。接下来的步骤专注于权限和 BLE 逻辑。

6. 关键 Kotlin 代码结构

完整源码请参考同目录下的 KMP BLE Demo-251218.md。此 KMP 项目使用共享模块结构:

6.1 主 Activity(Android 应用模块)

  • app/src/main/java/com/example/opmanager/opmanager/demo/MainActivity.kt
    • 包含 UI(Jetpack Compose)、BluetoothController、BleConnectionManager
    • 使用来自 com.example.opmanager.shared 包的共享模型

6.2 共享模块(KMP)

共享模块包含被 Android 和 iOS 共同使用的平台无关代码:

  • shared/src/commonMain/kotlin/com/example/opmanager/shared/BleConfigStrings.kt

    • UUID 字符串常量(支持 16-bit / 32-bit / 128-bit)
    • Service UUID: 18f0,Write UUID: 2af1,Notify UUID: 2af0
  • shared/src/androidMain/kotlin/com/example/opmanager/shared/BleConfig.kt

    • Android 特定的 UUID 解析(从字符串转换为 UUID 对象)
  • shared/src/commonMain/kotlin/com/example/opmanager/shared/SharedModels.kt

    • BluetoothDeviceUiConnectionLogLogTypeConnectionState
  • shared/src/commonMain/kotlin/com/example/opmanager/shared/BleTextCommandFormatter.kt

    • 命令格式化工具(转义处理、追加 CRLF)
  • shared/src/commonMain/kotlin/com/example/opmanager/shared/BleIncomingProcessor.kt

    • 处理传入的 BLE 通知文本并生成日志

更完整的 Android / iOS 实现示例(包括 MainActivity.ktBleConnectionManagerBleCentralManager.swift 以及共享工具类)请参考 KMP BLE Demo-251222-ios-android.md 以及对应的 GitHub 仓库源码。

7. 运行步骤(Android & iOS)

7.1 Android

  1. 用 USB 数据线连接手机与电脑,您会看到调试权限请求。
  2. 在 Android Studio 中点击 Run ▶ 并选择你的设备
  3. App 启动后:
    • 点击 Scan
    • 如果 Android 请求蓝牙/位置权限,请授予它们
    • 在列表中点击设备进行连接
  4. 发送命令 BaudTran,9600,N,8,1
  5. 显示结果 OK,VER=01.00

7.2 iOS

iOS Demo 使用 Xcode 构建,并依赖由 Gradle 生成的 KMP 共享模块 (shared.framework),具体配置请参考 KMP BLE Demo-251222-ios-android.md

  1. 确保已安装 Xcode 16.4+,并在 PATH 中可以找到 Java(JDK 17)(例如执行 java -version 验证)
  2. 在 Xcode 中打开 iOS App 工程(例如 iosApp/OPManagerIOSDemo.xcodeproj
  3. 编译工程:Xcode 会调用 Gradle 任务(如 :shared:packForXcode)生成/更新 shared.framework
  4. 真实的 iPhone 上运行 OPManagerIOSDemo scheme,在系统提示时授予蓝牙权限
  5. 在 App 中:
    • 点击 Scan 扫描附近 BLE 设备
    • 在列表中选择 OP-BT/BTS 设备并点击 Connect
    • 在输入框中输入命令(如 BaudTran,9600,N,8,1)并点击 Send
    • 在日志列表中可以看到设备返回的通知数据(例如 OK,VER=01.00