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

Android(Kotlin)实现BLE设备选中后自动连接方案求助

解决方案

1. 自动启用蓝牙(无需手动开关)

首先在AndroidManifest.xml中声明必要的蓝牙权限:

<!-- Android 11及以下 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

在Activity/Fragment初始化时自动检查蓝牙状态,未开启则请求用户启用:

private val bluetoothAdapter: BluetoothAdapter? by lazy {
    val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothManager.adapter
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    // 先请求必要权限,再处理蓝牙逻辑
    requestPermissions()
}

private fun checkBluetoothAndStartScan() {
    bluetoothAdapter?.let { adapter ->
        if (!adapter.isEnabled) {
            val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
        } else {
            startBleScan()
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_ENABLE_BT && resultCode == RESULT_OK) {
        startBleScan()
    }
}

companion object {
    private const val REQUEST_ENABLE_BT = 1
    private const val REQUEST_PERMISSIONS = 2
}

2. 自动启动BLE扫描(无需手动点击扫描按钮)

将扫描逻辑绑定到蓝牙启用后的回调,无需扫描按钮触发:

private var bleScanner: BluetoothLeScanner? = null
private val deviceList = mutableListOf<BluetoothDevice>()
private val scanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        super.onScanResult(callbackType, result)
        val device = result.device
        // 避免重复添加设备
        if (!deviceList.any { it.address == device.address }) {
            deviceList.add(device)
            deviceAdapter.notifyDataSetChanged()
        }
    }

    override fun onScanFailed(errorCode: Int) {
        super.onScanFailed(errorCode)
        Toast.makeText(this@MainActivity, "扫描失败,错误码:$errorCode", Toast.LENGTH_SHORT).show()
    }
}

private fun startBleScan() {
    bleScanner = bluetoothAdapter?.bluetoothLeScanner
    val scanSettings = ScanSettings.Builder()
        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
        .build()
    bleScanner?.startScan(emptyList(), scanSettings, scanCallback)
}

// 生命周期中停止扫描,避免资源浪费
override fun onPause() {
    super.onPause()
    bleScanner?.stopScan(scanCallback)
}

3. 选中设备后自动连接(无需手动点击连接按钮)

修改设备列表的点击事件,直接触发连接逻辑,移除单独的连接按钮:

// 假设用RecyclerView展示设备列表
private val deviceAdapter = object : RecyclerView.Adapter<DeviceViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_device, parent, false)
        return DeviceViewHolder(view)
    }

    override fun getItemCount() = deviceList.size

    override fun onBindViewHolder(holder: DeviceViewHolder, position: Int) {
        val device = deviceList[position]
        holder.tvName.text = device.name ?: "未知设备"
        holder.tvAddress.text = device.address
        
        // 点击列表项直接连接
        holder.itemView.setOnClickListener {
            bleScanner?.stopScan(scanCallback)
            connectToDevice(device)
        }
    }
}

class DeviceViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val tvName: TextView = itemView.findViewById(R.id.tv_device_name)
    val tvAddress: TextView = itemView.findViewById(R.id.tv_device_address)
}

// BLE连接核心逻辑
private var gatt: BluetoothGatt? = null
private fun connectToDevice(device: BluetoothDevice) {
    gatt = device.connectGatt(this, false, gattCallback)
}

private val gattCallback = object : BluetoothGattCallback() {
    override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
        super.onConnectionStateChange(gatt, status, newState)
        runOnUiThread {
            when (newState) {
                BluetoothProfile.STATE_CONNECTED -> {
                    Toast.makeText(this@MainActivity, "已连接到${gatt.device.name}", Toast.LENGTH_SHORT).show()
                    gatt.discoverServices()
                }
                BluetoothProfile.STATE_DISCONNECTED -> {
                    Toast.makeText(this@MainActivity, "连接断开", Toast.LENGTH_SHORT).show()
                    gatt.close()
                }
            }
        }
    }

    override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
        super.onServicesDiscovered(gatt, status)
        if (status == BluetoothGatt.GATT_SUCCESS) {
            // 服务发现成功,可进行特征读写操作
            val services = gatt.services
            // 这里处理你的业务逻辑,比如读取特征值
        }
    }
}

// 销毁时关闭Gatt连接
override fun onDestroy() {
    super.onDestroy()
    gatt?.close()
}

权限补充处理

Android 6.0+需要动态申请权限,添加以下代码:

private fun requestPermissions() {
    val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
    } else {
        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_ADMIN)
    }
    ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS)
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_PERMISSIONS && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
        checkBluetoothAndStartScan()
    } else {
        Toast.makeText(this, "需要授予权限才能使用BLE功能", Toast.LENGTH_SHORT).show()
    }
}

内容的提问来源于stack exchange,提问作者박종준

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:47:32