# MinewKit说明文档

本套SDK仅支持Minew公司出品的蓝牙传感器设备。通过SDK可以帮助开发者处理手机和传感器之间的一切工作,包括:扫描设备,广播数据、连接设备,向设备写入数据,从设备接收数据等。

目前SDK仅支持可连接资产标签的使用。

# 前期工作

整体框架:MBT02ConnectableAssetTagBleManager为设备管理类,在APP运行时始终是单例。MBT02ConnectableAssetTagEntity是设备实例类,此套件会为每一个设备生成一个实例,在扫描和连接后都会使用,内部包含设备广播数据,在扫描期间该数据会随着设备不停广播而更新。

MBT02ConnectableAssetTagBleManager:设备管理类,可以扫描周围的设备,并且可以连接它们,校验它们等;

MBT02ConnectableAssetTagEntity:扫描时获取到的可连接资产标签设备实例,继承自BaseBleDeviceEntity

# 导入到工程

  1. 开发环境

    sdk最低支持Android 5.0,对应API Level为21。在module的build.gradle中设置minSdkVersion为21或21以上

    android {
    
        defaultConfig {
            applicationId "com.xxx.xxx"
            minSdkVersion 21
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
  2. 将 jar包添加到module的libs文件夹下,并在该modulebuild.gradle中添加如下语句(直接添加依赖):

    implementation files('libs/base_ble_library.jar')
    implementation files('libs/minew_mbt02_connectable_asset_tag.jar')
    implementation 'org.lucee:bcprov-jdk15on:1.52.0'
    
    1
    2
    3

    或者右键该jar文件,选择Add as Library,添加到当前module。

    android {
        defaultConfig {
      
            ndk {
                abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
            }
    
        }
        sourceSets {
            main {
                jniLibs.srcDirs = ['libs']
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  3. AndroidManifest.xml需要以下权限,如果targetSdkVersion大于23,则需要做权限管理以获取权限:

        <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" tools:node="replace" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" tools:node="replace" />
        <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
        <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    
        <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
        <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
        <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
        <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"/>
        <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
    
        <!-- Required to maintain app compatibility. -->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
            android:maxSdkVersion="32" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
            android:maxSdkVersion="32"
            />
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

# 使用

sdk分为扫描、连接和读写三个阶段。

# 扫描部分

# 开始扫描

Android6.0系统以上,进行BLE扫描时,需要先申请到蓝牙权限后并且打开定位开关才能进行。

开启蓝牙扫描需要首先打开蓝牙,如果未打开蓝牙就去扫描,APP会闪退。可通过BLETool.checkBluetooth(this)来判断蓝牙是否已经打开。如果没有打开,可以先打开蓝牙。

val mBleManager = MBT02ConnectableAssetTagBleManager.getInstance()

        when (BLETool.checkBluetooth(this@MainActivity)) {
            BluetoothState.BLE_NOT_SUPPORT -> {
                Toast.makeText(this@MainActivity, "Not Support BLE", Toast.LENGTH_SHORT).show()
            }
            BluetoothState.BLUETOOTH_OFF -> {
                val enableIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
                launcherActivityResultForBle.launch(enableIntent)
            }
            BluetoothState.BLUETOOTH_ON -> {

               manager.startScan(App.getApplication().mApplication, 5*60*1000,object :                 					OnScanDevicesResultListener<MBT02ConnectableAssetTagEntity> {
            override fun onScanResult(scanList: MutableList<MBT02ConnectableAssetTagEntity>?) {
                
            }


            override fun onStopScan(scanList: MutableList<MBT02ConnectableAssetTagEntity>?) {
                
            }
        })

            }
            else -> {
            }
        }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

sdk内部并没有对蓝牙扫描时长进行处理,但是扫描是耗电操作,SDK默认5分钟就停止扫描了,如果还需要继续扫描,可以提供定时器或者刷新等操作以便继续调用扫描方法继续扫描设备。

# 取出数据

在扫描期间,APP能够通过sdk获取到设备当前的一部分数据。如下所示通过MBT02ConnectableAssetTagEntity获取设备资产中继标签数据,该数据保存在广播帧对象中。

sdk提供了BaseBleDeviceEntity作为MBT02ConnectableAssetTagEntity的基类,用于存储设备的公有数据,如下表所示:

名称 类型 说明
macAddress String 设备mac
name String 设备名称
rssi int 信号强度

BaseBleDeviceEntity还保存了一个Map,内部用于存储其在扫描期间获取到的设备广播数据帧,可通过如下方式取出:

val module:MBT02ConnectableAssetTagEntity
        val deviceStaticInfoFrame : DeviceStaticInfoFrame? = module.getMinewFrame(FrameType.DEVICE_INFORMATION_FRAME)?.let {
            it as DeviceStaticInfoFrame
        }
if (deviceInforFrame != null) {
    //设备mac地址
    String macAddress = deviceInforFrame.macAddress
    //电量百分比
    val battery = deviceInforFrame.battery
    //固件版本
    val firmwareVersion = deviceInforFrame.firmwareVersion
}
1
2
3
4
5
6
7
8
9
10
11
12

可连接资产标签设备有多种广播帧类型。

  1. 设备静态信息帧

    • DeviceStaticInfoFrame

      名称 类型 说明
      frameVersion int 设备类型
      firmwareVersion String 固件版本
      batteryLevel int 电池电量百分比
      macAddress String 固件mac
      peripheralSupportInfo PeripheralSupportInfo 外设支持描述,包含设备产品id
  2. 其他自定义

# 连接

连接前一般需要先停止扫描。sdk提供了连接和断开连接方法。

val manager = MBT02ConnectableAssetTagBleManager.getInstance()

//停止扫描
manager.stopScan(context)
//设置设备秘钥
val key="3141592653589793"
manager.setSecretKey(key)
//连接,module为准备连接的设备 
val module:MBT02ConnectableAssetTagEntity
manager.connect(context,module)
//断开连接。macAddress为设备mac
manager.disConnect(macAddress)
1
2
3
4
5
6
7
8
9
10
11
12

注意:连接设备前,请确认是否扫描到设备,如果没扫描到设备广播,调用连接方法,将连接失败。

在调用connect()后,sdk中会对连接过程会有状态监听。

//设置监听器
mBleManager.setOnConnStateListener(new OnConnStateListener() {
    
    /*
     * 连接过程中的状态回调
     *
     * @param macAddress      设备mac
     * @param connectionState 状态
     */
    @Override
    public void onUpdateConnState(String address, BleConnectionState state) {
        switch (state) {
            case Disconnect:
				//连接失败或者设备断开连接会回调,主动断开不会回调该状态
                break;

            case Connecting:
				//调用connect()后就会回调该状态
                break;
            case Connected:
                //初步连接成功,作为一个过渡阶段,此时并未真正成功
                break;
            case AuthenticateFail:
				//秘钥检验失败。
                break;
            case AuthenticateSuccess:
				//秘钥检验成功,
                break;
            case ConnectComplete:
				//连接完成,此时设备可进行读写操作
                break;
            default:
                break;
        }
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

在连接过程中,sdk会返回多个连接状态到app中,app需要做好处理。

  • BleConnectionState.ConnectingBleConnectionState.Connected: 连接设备中,在这里状态下不要做耗时操作,因为此时在连接设备发现服务,并发送认证数据等。
  • BleConnectionState.ConnectComplete: 此时传感器设备已经连接成功,可以进行读写操作,比如配置广播参数、传感器配置、读取历史数据等。
  • BleConnectionState.AuthenticateFail:认证过程中校验秘钥,输入的秘钥不正确,将回调这个状态并且设备主动断开连接。
  • BleConnectionState.AuthenticateSuccess:认证过程中校验秘钥,输入的秘钥正确,将回调这个状态。
  • BleConnectionState.Disconnect: 连接失败或者设备断开连接会回调。

# 读写

读写API如下:

    /**
     * 设置设备秘钥
     * @param macAddress 设备mac
     * @param secretKey 秘钥key
     * @param listener
     */
    public void setSecretKey(String macAddress, String secretKey);


    /**
     * 查询设备版本信息
     * @param macAddress 设备mac
     * @param listener   监听器
     */
    public void getFirmwareVersion(String macAddress, OnQueryResultListener<FirmwareVersionModel>  listener);

	/**
     * 固件升级
     *
     * @param macAddress  设备mac
     * @param isLinkUpgrade true url升级,false 固件包升级。默认值false,不支持url升级方式
     * @param dfuTarget isLinkUpgrade =true, dfuTarget = 0,isLinkUpgrade =true,通过ZipUtil.getDfuTargets(zipFilePath)
     * @param upgradeData 升级包数据
     * @param listener    监听器
     */
    public void firmwareUpgrade(String macAddress,boolean isLinkUpgrade,int dfuTarget,byte[] upgradeData, 		 OnFirmwareUpgradeListener listener);


    /**String macAddress
     * 恢复出厂设置
     *
     * @param macAddress 设备mac
     * @param listener   监听器
     */
    public void reset(String macAddress, OnModifyConfigurationListener listener);

    /**
     * 关机
     * @param macAddress 设备mac
     * @param listener   监听器
     */
    public void powerOff(String macAddress, OnModifyConfigurationListener listener);


    /**
     * 校验OTA升级文件的正确性
     * @param zipFilePath ota升级文件路径
     * @return true=升级文件,false= 不是升级文件
     */
    boolean verifyOtaFile(@NonNull String zipFilePath);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

对部分方法进行补充说明:

  1. 设置设备秘钥,此方法调用必须在connect()方法前设置。

    val manager = MBT02ConnectableAssetTagBleManager.getInstance()
    val secretKey = "3141592653589793"
    manager.setSecretKey(mAddress,secretKey)
    
    
    1
    2
    3
    4
  2. 查询设备版本信息。

        suspend fun queryFirmwareInfo(): FirmwareVersionModel? = withContext(Dispatchers.Default) {
            if (connectMacAddress == null) {
                return@withContext null
            }
            return@withContext suspendCancellableCoroutine<FirmwareVersionModel?> { continuation ->
                manager.queryDeviceFirmwareInfo(connectMacAddress!!) { isSuccessful, version ->
                    continuation.resume(
                        when (isSuccessful) {
                            true -> version
                            else -> null
                        }, null
                    )
                }
            }
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  3. 设置设备LED

        suspend fun setLEDConfig(
            color: Int,
            workTotalTime: Int,
            singleCycleLightingTime: Int,
            singleCycleLightOffTime: Int,
            brightness: Int
        ): Boolean =
            withContext(Dispatchers.Default) {
                if (connectMacAddress == null) {
                    return@withContext false
                }
                return@withContext suspendCancellableCoroutine<Boolean> { continuation ->
                    manager.setLEDConfiguration(
                        connectMacAddress!!,
                        color,
                        workTotalTime,
                        singleCycleLightingTime,
                        singleCycleLightOffTime,
                        brightness
                    ) { isSuccess ->
                        continuation.resume(isSuccess, null)
                    }
                }
            }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
  4. 设置设备蜂鸣器

        suspend fun setBuzzerConfig(
            workingCyclesTime: Int,
            singleCycleWorkTime: Int,
            singleCycleIdleTime: Int,
            gear: Int
        ): Boolean =
            withContext(Dispatchers.Default) {
                if (connectMacAddress == null) {
                    return@withContext false
                }
                return@withContext suspendCancellableCoroutine<Boolean> { continuation ->
                    manager.setBuzzerConfiguration(
                        connectMacAddress!!,
                        workingCyclesTime,
                        singleCycleWorkTime,
                        singleCycleIdleTime,
                        gear
                    ) { isSuccess ->
                        continuation.resume(isSuccess, null)
                    }
                }
            }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
  5. 固件升级。

        private fun firmwareUpgrade(
            fileByte: ByteArray,
            dfuTarget: Int
        ) {
            mConnectViewModel.firmwareUpgrade(dfuTarget, fileByte,
                progressCallBack = { progress ->
                    WaitDialog.show(getString(R.string.common_upgrading), (progress / 100f))
                    binding.progressBarSimpleCustom.progress = progress.toFloat()
                },
                successCallBack = {
                    WaitDialog.dismiss()
                    ToastUtils.showShort(R.string.common_firmware_upgrade_successfully)
                    finishPageForResult()
                },
                failCallBack = {
                    WaitDialog.dismiss()
                    ToastUtils.showShort(R.string.common_firmware_upgrade_failure2)
                }
            )
        }
    
        fun firmwareUpgrade(
            dfuTarget: Int,
            fileByte: ByteArray,
            progressCallBack:(progress:Int) -> Unit,
            successCallBack:() -> Unit,
            failCallBack:() -> Unit,
        ){
            manager.firmwareUpgrade(connectMacAddress!!,false,dfuTarget,fileByte,
                object : OnFirmwareUpgradeListener {
                    override fun updateProgress(progress: Int) {
                        progressCallBack(progress)
                    }
    
                    override fun upgradeSuccess() {
                        successCallBack()
                    }
    
                    override fun upgradeFailed() {
                        failCallBack()
                    }
                })
    
    
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
  6. 恢复出厂设置

     suspend fun reset(): Boolean = withContext(Dispatchers.Default) {
         if (connectMacAddress == null) {
             return@withContext false
         }
         return@withContext suspendCancellableCoroutine<Boolean> { continuation ->
             manager.reset(connectMacAddress!!) {
                 continuation.resume(it, null)
             }
         }
     }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  7. 关机。

        suspend fun shutdown(): Boolean = withContext(Dispatchers.Default) {
            if (connectMacAddress == null) {
                return@withContext false
            }
            return@withContext suspendCancellableCoroutine<Boolean> { continuation ->
                manager.powerOff(connectMacAddress!!) {
                    continuation.resume(it, null)
                }
            }
        }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

# 历史记录

  • **2024/10/30 添加编辑文档;
上次更新:: 2025/2/27 20:59:23