You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio中Kotlin连接蓝牙设备失败,UUID是否为问题根源?

解决蓝牙连接的RuntimeException问题及UUID获取方案

一、先修复两个明显的错误

1. 替换错误的UUID

你当前使用的00000000-0000-1000-8000-00805F9B34FB是无效的占位UUID,绝大多数蓝牙串口设备采用SPP(串口协议)标准UUID,替换成以下值:

val my_uuidpar = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")

2. 正确启动连接线程

你现在调用connectedDevice?.run()只是在UI线程同步执行代码,会阻塞主线程引发ANR或异常,必须调用start()开启独立线程:

connectedDevice?.start()

二、排查真实异常原因

InvocationTargetException只是底层错误的包装类,你需要打印异常的cause才能找到真正问题,修改ConnectThread的run方法:

@SuppressLint("MissingPermission")
public override fun run() {
    bluetoothAdapter?.cancelDiscovery()

    mmSocket?.let { socket ->
        try {
            socket.connect()
            // manageMyConnectedSocket(socket)
        } catch (e: Exception) {
            // 打印真实异常根源
            Log.e("BluetoothConnect", "连接失败", e.cause ?: e)
            cancel()
        }
    }
}

常见真实原因包括:权限未授予、设备不支持目标UUID、设备已断开、连接超时等。

三、获取设备正确UUID的方法

如果替换SPP UUID后仍无法连接,可通过以下方式获取设备真实服务UUID:

1. 通过SDP扫描获取UUID

调用fetchUuidsWithSdp()触发服务发现,通过广播接收结果:

// 1. 注册广播接收器(记得在onDestroy时注销)
private val uuidReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (BluetoothDevice.ACTION_UUID == intent?.action) {
            val uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID)
            uuids?.forEach { uuid ->
                val targetUuid = (uuid as ParcelableUuid).uuid
                Log.d("DeviceUUID", "扫描到UUID: $targetUuid")
                // 可直接用此UUID尝试连接
            }
        }
    }
}

// 2. 点击设备时启动SDP扫描
scannedDevices.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
    val device = devicemap[position] ?: return@OnItemClickListener
    registerReceiver(uuidReceiver, IntentFilter(BluetoothDevice.ACTION_UUID))
    device.fetchUuidsWithSdp()
}

2. 查询设备手册或厂商文档

如果是自定义蓝牙设备,厂商通常会在产品文档中提供服务UUID,这是最可靠的方式。

3. 反射获取RFCOMM通道(备用方案)

当SDP扫描失败时,可尝试通过反射直接指定RFCOMM通道创建socket:

private fun createRfcommSocket(device: BluetoothDevice, channel: Int = 1): BluetoothSocket? {
    return try {
        val method = device.javaClass.getMethod("createRfcommSocket", Int::class.java)
        method.invoke(device, channel) as BluetoothSocket
    } catch (e: Exception) {
        Log.e("Bluetooth", "反射创建socket失败", e)
        null
    }
}

使用时替换原有的createRfcommSocketToServiceRecord调用即可,通道通常从1开始尝试。

四、Android 12+权限检查

确保已动态申请并获得BLUETOOTH_CONNECT和BLUETOOTH_SCAN权限:

val permissions = arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, permissions, 1001)
}

内容的提问来源于stack exchange,提问作者stair case to heaven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:45:17