Android TV无法识别安卓APP通过蓝牙Socket发送的命令
问题:蓝牙Socket发送命令至Android TV无响应
我已通过蓝牙Socket实现Android TV与安卓手机APP的连接,完成以下步骤:
- 搜索设备——完成
- 使用
createBond配对设备——完成 - 在通道4获取到Android TV的UUID(用于RF_COMM)
但尝试通过bluetoothsocket?.outputStream?.write("VolumeUp".toByteArray())发送音量加命令时,Android TV无任何反应。
附上相关代码:
if ( ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED ) { return } Toast.makeText(this, deviceToPair.name, Toast.LENGTH_LONG).show() bluetoothAdapter.cancelDiscovery() try { val paringRequired = deviceToPair.createBond() val value = if (paringRequired) "Haa" else "Na" Log.d("Log", "Device name " + deviceToPair.name) Log.d("Log", "Device deviceAddress " + deviceToPair.address) Log.d("Log", "Device deviceClass " + deviceToPair.bluetoothClass) Log.d("Log", "Device bondState " + deviceToPair.bondState) Log.d("Log", "Device deviceType " + deviceToPair.type) Log.d("Log", deviceToPair.name + " ke Paring ke jarurat hai ho? " + value) } catch (e: Exception) { Log.d("Log", "Exception while using socket connection : " + e.message) } try { val uuid = getWorkingUUIDFromDevice(deviceToPair) if (uuid != null) { val socket = deviceToPair.createRfcommSocketToServiceRecord(UUID.fromString(uuid)) val thread = Thread { Thread.sleep(5000) // 5 seconds delay socket.connect() Log.d("Log", "Socket connect done : ") // socket?.outputStream?.write(KeyEvent.KEYCODE_HOME) val commandByte = AnymoteCommand.VOLUME_UP.commandName.toByteArray(Charsets.UTF_8) Log.d("Log", "Volume up sent : ") socket?.outputStream?.write("powerOff".toByteArray()) Log.d("Log", "Data sending to tv : ") val inputStream = socket?.inputStream socket?.outputStream?.flush() Log.d("Log", "Got data from tv " + inputStream?.read()) socket.close() } thread.start() }
可能的原因及解决办法
1. 命令格式不匹配
Android TV的蓝牙控制服务通常不识别自定义字符串命令(如"VolumeUp"、"powerOff"),需遵循对应协议的编码规则:
- 若使用HID协议(多数电视蓝牙控制基于此),需发送标准HID报告格式的按键数据,而非直接转字符串字节。比如音量加对应特定的HID报告数组,还要发送按键释放的报告。
- 若代码中用到
AnymoteCommand,说明目标服务基于Anymote协议,该协议使用Protocol Buffers序列化命令,不能直接将命令名转UTF-8字节发送,需按PB规范构建数据包。
2. 连接时机不可靠
代码中用固定5秒延迟等待配对完成,容易出现配对未完成就发起连接的情况:
- 移除
Thread.sleep(5000),改为注册BroadcastReceiver监听BluetoothDevice.ACTION_BOND_STATE_CHANGED事件,当设备状态变为BOND_BONDED时再发起Socket连接。
3. 权限与状态检查
- 在Socket连接、流读写操作中捕获
IOException,打印详细错误日志,排查是否存在连接失败、流写入异常的问题。 - 确认
getWorkingUUIDFromDevice获取的UUID对应电视上的蓝牙控制服务,比如HID服务的标准UUID为00001124-0000-1000-8000-00805f9b34fb。
4. 流操作逻辑问题
- 避免连续发送多个命令,先单独测试一个命令(如仅发送音量加),确认有效性后再扩展。
- 发送命令后需确保
flush()调用,但部分服务要求特定的数据包结束符,需按协议规范补充。
修正后的关键代码示例
// 注册广播接收器监听配对状态 private val bondStateReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { intent ?: return if (BluetoothDevice.ACTION_BOND_STATE_CHANGED == intent.action) { val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) if (device?.address == deviceToPair.address) { if (device.bondState == BluetoothDevice.BOND_BONDED) { // 配对完成,发起连接 connectToTv(device) } } } } } // 连接电视并发送HID格式的音量加命令 private fun connectToTv(device: BluetoothDevice) { try { val hidUuid = UUID.fromString("00001124-0000-1000-8000-00805f9b34fb") val socket = device.createRfcommSocketToServiceRecord(hidUuid) Thread { try { socket.connect() Log.d("Log", "Socket连接成功") // 发送音量按下的HID报告 val pressReport = byteArrayOf(0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00) socket.outputStream.write(pressReport) socket.outputStream.flush() // 延迟100ms后发送按键释放报告 Thread.sleep(100) val releaseReport = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) socket.outputStream.write(releaseReport) socket.outputStream.flush() socket.close() } catch (e: IOException) { Log.e("Log", "Socket操作异常: ${e.message}") } }.start() } catch (e: Exception) { Log.e("Log", "连接初始化异常: ${e.message}") } }
内容的提问来源于stack exchange,提问作者Honey Kumar
相关产品推荐
相关产品推荐

