网站建设 义乌,四川省安全社区建设网站,哈尔滨h5建站模板,福州关键词排名前言 上一篇文章给大家分享了Kotlin版的Android蓝牙的基础知识和基础用法#xff0c;不过上一篇都是一些零散碎片化的程序#xff0c;#xff0c;这一篇给大家分享Android蓝牙开发实战项目KotlinCompose的初步使用 效果演示 : Android Compose 蓝牙开发 Android蓝牙实战开发…前言 上一篇文章给大家分享了Kotlin版的Android蓝牙的基础知识和基础用法不过上一篇都是一些零散碎片化的程序这一篇给大家分享Android蓝牙开发实战项目KotlinCompose的初步使用 效果演示 : Android Compose 蓝牙开发 Android蓝牙实战开发步骤 1.新建Android项目添加蓝牙权限 下图所示MyBluetoothDemo为刚刚创建的Android空项目我们现在清单文件中把我们需要用到的权限声明一下其中定位权限还需要做动态申请 2.封装BluetoothAdapter类 BluetoothAdapter类提供了常用的蓝牙API我这里创建了一个BlueToothController类小编这里是先将这些API封装到了一个BlueToothController类中方便后续使用和操作
package com.example.bluetoothcomposeimport android.annotation.SuppressLint
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.content.Context
import android.content.Intentobject BlueToothController {val mBluetoothAdapter BluetoothAdapter.getDefaultAdapter()/*** 检查设备是否支持蓝牙*/fun isBluetoothSupport(): Boolean {return mBluetoothAdapter !null}/*** 检查该设备蓝牙是否开启*/SuppressLint(MissingPermission)fun isBluetoothEnabled(): Boolean {return mBluetoothAdapter.enable()}/*** 打开蓝牙*/SuppressLint(MissingPermission)fun turnOnBlueTooth(activity: Activity, requestCode: Int) {val intent Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)activity.startActivityForResult(intent, requestCode)}/*** 打开蓝牙可见性*/SuppressLint(MissingPermission)fun enableVisibily(context: Context) {val intent Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)context.startActivity(intent)}/*** 停止查找设备*/SuppressLint(MissingPermission)fun cancelFindDevice() {mBluetoothAdapter.cancelDiscovery()}/*** 判断当前设备是否在查找蓝牙设备*/SuppressLint(MissingPermission)fun isStartDiscovering(): Boolean {return mBluetoothAdapter.isDiscovering}/*** 判断当前设备是否未在查找蓝牙设备*/SuppressLint(MissingPermission)fun isCancelDiscovering(): Boolean {return !mBluetoothAdapter.isDiscovering}/*** 查找设备*/SuppressLint(MissingPermission)fun findDevice() {mBluetoothAdapter.startDiscovery()}/*** 获取已绑定设备*/SuppressLint(MissingPermission)fun getBondedDeviceList(): ListBluetoothDevice?? {return ArrayList(mBluetoothAdapter.bondedDevices)}/*** 判断蓝牙是否连接*/SuppressLint(MissingPermission)fun isConnectBlue(bluetoothSocket: BluetoothSocket?): Boolean {return bluetoothSocket ! null bluetoothSocket.isConnected}
} 3. 编写Compose UI页面 这里的UI样式在后面我给出了完整版的大家可以去复制一下 MainScreen这是我们MainActivity的UI放置了一个Column竖向布局和Menu Composablefun MainScreen() {var expanded remember {mutableStateOf(false)}Column(modifier Modifier.fillMaxSize()){Row(modifier Modifier.fillMaxWidth().background(Blue).padding(vertical 12.dp).height(35.dp),verticalAlignment Alignment.CenterVertically,horizontalArrangement Arrangement.Start) {Text(text 可用设备,modifier Modifier.weight(1f).offset(10.dp))if(isRefresh.value){CircularProgressIndicator(modifier Modifier.size(25.dp),color White)}Box() {Icon(painter painterResource(id R.drawable.ic_setting),contentDescription null,modifier Modifier.width(50.dp).fillMaxHeight().clickable {expanded.value true},)if(expanded.value){DropdownMenu(expanded expanded.value,onDismissRequest {expanded.value false}) {data.forEachIndexed{ index: Int, s: String -DropdownMenuItem(onClick {when (index) {0 - {if(BlueToothController.isBluetoothSupport()){Toast.makeText(thisMainActivity,本机支持蓝牙功能,Toast.LENGTH_SHORT).show()}else{Toast.makeText(thisMainActivity,本机暂不支持蓝牙功能,Toast.LENGTH_SHORT).show()}}1 - {if(BlueToothController.isBluetoothEnabled()){Toast.makeText(thisMainActivity,用户允许开启蓝牙,Toast.LENGTH_SHORT).show()}else{Toast.makeText(thisMainActivity,用户拒绝开启蓝牙,Toast.LENGTH_SHORT).show()}}2 - {selected.value 3Log.d(TAG,查看已绑定设备)if(BlueToothController.isStartDiscovering()){BlueToothController.cancelFindDevice()}deviceList.clear()for (device in BlueToothController.getBondedDeviceList()!!){deviceList.add(device!!)}}3 - {if(BlueToothController.isStartDiscovering()){Log.d(TAG,停止查找)BlueToothController.cancelFindDevice()deviceList!!.clear()}selected.value 4BlueToothController.findDevice()Log.d(TAG,开始查找)}}Log.d(TAG,selected.value.toString())expanded.value false}) {Text(text s)}}}}}}DeviceListView()}if(openDialog.value){AlterDialog()}} AlterDialog: 用来显示弹窗 Composablefun AlterDialog() {AlertDialog(onDismissRequest { openDialog.value false },title { Text(text text.value) },text {Text(text 0c 11 09 41 23 00 01 03 FF)}, confirmButton {TextButton(onClick {openDialog.value falsesendMessage()}) {Text(text 发送)}}, dismissButton {TextButton(onClick { openDialog.value false }) {Text(text 取消)}})} DeviceListView: 这是一个列表控件相当于RecycleView
Composablefun DeviceListView(){LazyColumn(Modifier.fillMaxSize(),contentPadding PaddingValues(5.dp,1.dp),verticalArrangement Arrangement.spacedBy(5.dp)){items(deviceList!!.size){ index-ListItem(index, deviceList[index])}}} ListItem这是每个LazyColumn中每个列表的UI样式
Composablefun ListItem(index: Int, blueToothDevice: BluetoothDevice){Card(shape RoundedCornerShape(4.dp),elevation 2.dp) {Row(modifier Modifier.height(50.dp).fillMaxWidth().clickable {openDialog.value trueif (blueToothDevice.name null) {text.value N/A} else {text.value blueToothDevice.name}//Gatt协议连接蓝牙var bluetoothGatt blueToothDevice.connectGatt(thisMainActivity, true, mGattCallback)bluetoothGatt.connect()Log.d(TAG, 点击了第$index 个item)},verticalAlignment Alignment.CenterVertically,) {Image(painter painterResource(R.drawable.ic_blue),contentDescription null,modifier Modifier.fillMaxHeight().padding(all 5.dp))Column(modifier Modifier.fillMaxWidth()) {if(blueToothDevice.namenull){Text(text N/A,fontWeight FontWeight.Bold)}else{Text(text blueToothDevice.name,fontWeight FontWeight.Bold)}Text(text blueToothDevice.address,)}}}} 4. 蓝牙搜索配对连接通信 小编这里为了让大家方便便将搜索配对连接都写在了MainActivity中了,Compose UI也在这里了大家可以复制直接去运行
package com.example.bluetoothcomposeimport android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.annotation.SuppressLint
import android.bluetooth.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
import com.example.bluetoothcompose.ui.theme.Blue
import com.example.bluetoothcompose.ui.theme.BlueToothComposeTheme
import com.example.bluetoothcompose.ui.theme.White
import java.util.*class MainActivity : ComponentActivity() {private val TAG yfprivate var deviceList mutableStateListOfBluetoothDevice()private var data mutableListOf(检查设备是否支持蓝牙,检查设备是否开启蓝牙,查看已配过的蓝牙设备,查找蓝牙设备)var selected mutableStateOf(0)var openDialog mutableStateOf(false)var text mutableStateOf()var mGatt: BluetoothGatt? nullvar mWriter: BluetoothGattCharacteristic? nullprivate var isRefresh mutableStateOf(false)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {BlueToothComposeTheme {// A surface container using the background color from the themeSurface(modifier Modifier.fillMaxSize(),color MaterialTheme.colors.background) {MainScreen()}}}}override fun onStart() {super.onStart()isPermission()registerBluetoothReceiver()}//处理找到蓝牙设备和搜索完成的广播消息var receiver: BroadcastReceiver object : BroadcastReceiver() {SuppressLint(MissingPermission)override fun onReceive(context: Context, intent: Intent) {val action intent.action//开始查找设备when {BluetoothAdapter.ACTION_DISCOVERY_STARTED action - {//开始搜索if(deviceList!null){deviceList!!.clear()}isRefresh.value true}BluetoothDevice.ACTION_FOUND action - {//搜到蓝牙设备val device intent.getParcelableExtraBluetoothDevice(BluetoothDevice.EXTRA_DEVICE)//把搜索到的设备添加到已找到列表中显示它的信息deviceList?.add(device!!)Log.d(TAG,找到了: ${deviceList.size})}BluetoothAdapter.ACTION_DISCOVERY_FINISHED action - {//搜索完毕isRefresh.value falsewhen (selected.value) {3 - {}4 - {Toast.makeText(thisMainActivity,选择要配对的蓝牙设备,Toast.LENGTH_SHORT).show()}}}BluetoothDevice.ACTION_BOND_STATE_CHANGED action - {val device intent.getParcelableExtraBluetoothDevice(BluetoothDevice.EXTRA_DEVICE)if (device null) {Toast.makeText(thisMainActivity,无设备,Toast.LENGTH_SHORT).show()return}val state intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0)when (state) {BluetoothDevice.BOND_BONDED - {Toast.makeText(thisMainActivity,已配对,Toast.LENGTH_SHORT).show()}BluetoothDevice.BOND_BONDING - {Toast.makeText(thisMainActivity,正在配对,Toast.LENGTH_SHORT).show()}BluetoothDevice.BOND_NONE - {Toast.makeText(thisMainActivity,未配对,Toast.LENGTH_SHORT).show()}}}}}}//动态获取位置权限SuppressLint(WrongConstant)private fun isPermission() {if (checkSelfPermission(ACCESS_COARSE_LOCATION) ! PERMISSION_GRANTED|| checkSelfPermission(ACCESS_FINE_LOCATION) ! PERMISSION_GRANTED) {requestPermissions(arrayOf(ACCESS_COARSE_LOCATION,ACCESS_FINE_LOCATION), 200)}}private fun registerBluetoothReceiver() {//filter注册广播接收器val filter IntentFilter()//蓝牙当前状态filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED)//开始扫描蓝牙设备广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)//找到蓝牙设备广播filter.addAction(BluetoothDevice.ACTION_FOUND)//扫描蓝牙设备结束广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)//蓝牙设备配对状态改变广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)//设备扫描模式改变广播filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)registerReceiver(receiver, filter)}SuppressLint(MissingPermission)Composablefun MainScreen() {var expanded remember {mutableStateOf(false)}Column(modifier Modifier.fillMaxSize()){Row(modifier Modifier.fillMaxWidth().background(Blue).padding(vertical 12.dp).height(35.dp),verticalAlignment Alignment.CenterVertically,horizontalArrangement Arrangement.Start) {Text(text 可用设备,modifier Modifier.weight(1f).offset(10.dp))if(isRefresh.value){CircularProgressIndicator(modifier Modifier.size(25.dp),color White)}Box() {Icon(painter painterResource(id R.drawable.ic_setting),contentDescription null,modifier Modifier.width(50.dp).fillMaxHeight().clickable {expanded.value true},)if(expanded.value){DropdownMenu(expanded expanded.value,onDismissRequest {expanded.value false}) {data.forEachIndexed{ index: Int, s: String -DropdownMenuItem(onClick {when (index) {0 - {if(BlueToothController.isBluetoothSupport()){Toast.makeText(thisMainActivity,本机支持蓝牙功能,Toast.LENGTH_SHORT).show()}else{Toast.makeText(thisMainActivity,本机暂不支持蓝牙功能,Toast.LENGTH_SHORT).show()}}1 - {if(BlueToothController.isBluetoothEnabled()){Toast.makeText(thisMainActivity,用户允许开启蓝牙,Toast.LENGTH_SHORT).show()}else{Toast.makeText(thisMainActivity,用户拒绝开启蓝牙,Toast.LENGTH_SHORT).show()}}2 - {selected.value 3Log.d(TAG,查看已绑定设备)if(BlueToothController.isStartDiscovering()){BlueToothController.cancelFindDevice()}deviceList.clear()for (device in BlueToothController.getBondedDeviceList()!!){deviceList.add(device!!)}}3 - {if(BlueToothController.isStartDiscovering()){Log.d(TAG,停止查找)BlueToothController.cancelFindDevice()deviceList!!.clear()}selected.value 4BlueToothController.findDevice()Log.d(TAG,开始查找)}}Log.d(TAG,selected.value.toString())expanded.value false}) {Text(text s)}}}}}}DeviceListView()}if(openDialog.value){AlterDialog()}}Preview(showBackground true,group Group1,)Composablefun DefaultPreview() {MainScreen()}SuppressLint(MissingPermission)Composablefun DeviceListView(){LazyColumn(Modifier.fillMaxSize(),contentPadding PaddingValues(5.dp,1.dp),verticalArrangement Arrangement.spacedBy(5.dp)){items(deviceList!!.size){ index-ListItem(index, deviceList[index])}}}SuppressLint(MissingPermission)Composablefun ListItem(index: Int, blueToothDevice: BluetoothDevice){Card(shape RoundedCornerShape(4.dp),elevation 2.dp) {Row(modifier Modifier.height(50.dp).fillMaxWidth().clickable {openDialog.value trueif (blueToothDevice.name null) {text.value N/A} else {text.value blueToothDevice.name}//Gatt协议连接蓝牙var bluetoothGatt blueToothDevice.connectGatt(thisMainActivity, true, mGattCallback)bluetoothGatt.connect()Log.d(TAG, 点击了第$index 个item)},verticalAlignment Alignment.CenterVertically,) {Image(painter painterResource(R.drawable.ic_blue),contentDescription null,modifier Modifier.fillMaxHeight().padding(all 5.dp))Column(modifier Modifier.fillMaxWidth()) {if(blueToothDevice.namenull){Text(text N/A,fontWeight FontWeight.Bold)}else{Text(text blueToothDevice.name,fontWeight FontWeight.Bold)}Text(text blueToothDevice.address,)}}}}SuppressLint(MissingPermission)Composablefun AlterDialog() {AlertDialog(onDismissRequest { openDialog.value false },title { Text(text text.value) },text {Text(text 0c 11 09 41 23 00 01 03 FF)}, confirmButton {TextButton(onClick {openDialog.value falsesendMessage()}) {Text(text 发送)}}, dismissButton {TextButton(onClick { openDialog.value false }) {Text(text 取消)}})}private val mGattCallback: BluetoothGattCallback object : BluetoothGattCallback() {SuppressLint(MissingPermission)override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {//连接成功if (newState BluetoothProfile.STATE_CONNECTED) {//进行服务发现gatt.discoverServices()Log.d(TAG, 连接成功)} else if (newState BluetoothProfile.STATE_DISCONNECTED) {//连接断开处理断开逻辑Log.d(TAG, 连接断开)}}SuppressLint(MissingPermission)override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {Log.d(TAG, onServicesDiscovered : $status $gatt)//发现服务成功处理服务和特征值if (status BluetoothGatt.GATT_SUCCESS) {//发送消息mGatt gattval service gatt.getService(UUID.fromString(0000180a-0000-1000-8000-00805F9B34FB))mWriter service.getCharacteristic(UUID.fromString(00002ad9-0000-1000-8000-00805F9B34FB))//打开消息通知mGatt!!.setCharacteristicNotification(mWriter, true)val descriptor: BluetoothGattDescriptor mWriter!!.getDescriptor(UUID.fromString(00002902-0000-1000-8000-00805f9b34fb))descriptor.value BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUEmGatt!!.writeDescriptor(descriptor)} else {Log.d(TAG, 发现服务失败)}}override fun onCharacteristicRead(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,status: Int) {Log.e(TAG, onCharacteristicRead $status)//读取特征成功处理特征值if (status BluetoothGatt.GATT_SUCCESS) {}}override fun onCharacteristicWrite(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic,status: Int) {Log.e(TAG, onCharacteristicWrite $status)//写入特征成功if (status BluetoothGatt.GATT_SUCCESS) {Log.d(TAG, 发送成功)} else {Log.d(TAG, 发送失败)}}override fun onCharacteristicChanged(gatt: BluetoothGatt,characteristic: BluetoothGattCharacteristic) {//接收到数据val data characteristic.value//处理接收到的数据Log.d(TAG, Received data: bytesToHexFun2(data))}override fun onDescriptorRead(gatt: BluetoothGatt,descriptor: BluetoothGattDescriptor,status: Int) {super.onDescriptorRead(gatt, descriptor, status)}override fun onDescriptorWrite(gatt: BluetoothGatt,descriptor: BluetoothGattDescriptor,status: Int) {super.onDescriptorWrite(gatt, descriptor, status)}override fun onReliableWriteCompleted(gatt: BluetoothGatt, status: Int) {super.onReliableWriteCompleted(gatt, status)}override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {super.onReadRemoteRssi(gatt, rssi, status)}override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {super.onMtuChanged(gatt, mtu, status)}override fun onServiceChanged(gatt: BluetoothGatt) {super.onServiceChanged(gatt)}override fun onPhyUpdate(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) {super.onPhyUpdate(gatt, txPhy, rxPhy, status)}override fun onPhyRead(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) {super.onPhyRead(gatt, txPhy, rxPhy, status)}}private fun bytesToHexFun2(bytes: ByteArray): String? {var result 0for (i in bytes.indices) {result bytes[i]}return byte2Hex((result.inv() and 0xFF).toByte())}fun byte2Hex(inByte: Byte?): String //1字节转2个Hex字符{return String.format(%02x, inByte).toUpperCase()}SuppressLint(MissingPermission)fun sendMessage(){if (null mWriter) {Log.e(yf123, ble发送失败null writer !!!!)} else {mWriter!!.value byteArrayOf(0x0c.toByte(),0x11.toByte(),0x09.toByte(),0x41.toByte(),0x23.toByte(),0x00.toByte(),0x01.toByte(),0x03.toByte(),0xFF.toByte())mGatt!!.writeCharacteristic(mWriter)}}} 到此为止我们的程序就到这里了蓝牙搜索配对连接通信便已经成功实现了大家可以把代码copy一下拿去运行具体效果演示图在文章最上方大家还想了解更多关于Android蓝牙开发的可以继续看我下一篇给大家的分享