AndroidManifest中定义权限
动态申请权限
private final int REQUEST_PERMISSION_CODE = 1000;
private fun initPermission() {
val permissionList: ArrayList = ArrayList()
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
// Android 版本大于等于 Android12 时
permissionList.add(Manifest.permission.BLUETOOTH_SCAN)
permissionList.add(Manifest.permission.BLUETOOTH_ADVERTISE)
permissionList.add(Manifest.permission.BLUETOOTH_CONNECT)
} else {
// Android 版本小于 Android12 及以下版本
permissionList.add(Manifest.permission.ACCESS_COARSE_LOCATION)
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
ActivityCompat.requestPermissions(this,permissionList.toArray(emptyArray()),REQUEST_PERMISSION_CODE)
}
如果蓝牙没有开启,跳转到系统蓝牙设置界面,打开蓝牙:
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
if (!bluetoothAdapter.isEnabled()) {
val intent = Intent(Settings.ACTION_BLUETOOTH_SETTINGS)
context.startActivity(intent)
}
private var adapter: BluetoothTerminalAdapter?=null
private var list:MutableList = mutableListOf()
private var broadcastReceiver: BluetoothBroadcastReceive?=null
fun registerReceiver() {
if (broadcastReceiver == null) {
broadcastReceiver = BluetoothBroadcastReceive()
val intent = IntentFilter()
intent.addAction(BluetoothDevice.ACTION_FOUND) // 用BroadcastReceiver来取得搜索结果
intent.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)
intent.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
intent.addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
intent.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
intent.addAction(BluetoothDevice.ACTION_NAME_CHANGED)
intent.addAction("android.bluetooth.BluetoothAdapter.STATE_OFF")
intent.addAction("android.bluetooth.BluetoothAdapter.STATE_ON")
intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
requireContext().registerReceiver(broadcastReceiver, intent)
}
}
fun stopDiscovery() {
BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
}
fun onBluetoothConnect(device: BluetoothDevice) {
//连接成功后的动作,比如更新UI,开始FTP通信等
......
}
fun onBluetoothDisConnect() {
//连接失败后的动作,比如更新UI,
}
inner class BluetoothBroadcastReceive : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action
val device = intent?.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
when (action) {
BluetoothDevice.ACTION_FOUND -> {
if (device != null)){
if (!list.contains(device)) {
list.add(device)
adapter?.notifyDataSetChanged()
}
}
}
BluetoothAdapter.ACTION_DISCOVERY_FINISHED -> {
stopDiscovery()
}
BluetoothDevice.ACTION_ACL_CONNECTED -> {
//连接后还需要配对,配对成功才能通信
if (device != null){
adapter?.notifyDataSetChanged()
}
}
BluetoothDevice.ACTION_ACL_DISCONNECTED -> {
if (device != null){
//如果连接失败或者连接成功,但是没有配对,则会调用连接失败
onBluetoothDisConnect()
adapter?.notifyDataSetChanged()
}
}
BluetoothAdapter.ACTION_STATE_CHANGED -> {
val blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0)
when (blueState) {
BluetoothAdapter.STATE_OFF -> {
stopDiscovery()
onBluetoothDisConnect()
}
}
}
BluetoothDevice.ACTION_BOND_STATE_CHANGED -> {
val state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1)
when (state) {
BluetoothDevice.BOND_NONE -> {adapter?.notifyDataSetChanged()}
BluetoothDevice.BOND_BONDED -> {
if (device != null){
adapter?.notifyDataSetChanged()
//配对成功才能通讯,所以只有配对成功才表示真正的连接成功
onBluetoothConnect(device)
}
}
}
}
BluetoothDevice.ACTION_NAME_CHANGED -> {
for(i in 0 until list.size) {
if (list[i].address == device?.address) {
if (device != null) {
list[i] = device
adapter?.notifyDataSetChanged()
}
break
}
}
}
}
}
}
说明一下,原始的实现方式是在系统蓝牙设置界面进行配对,在广播收到“BluetoothDevice.ACTION_ACL_CONNECTED”后,开始调用“bluetoothDevice.createRfcommSocketToServiceRecord(SPP_UUID)”进行SPP通信,但是此方式对有的蓝牙服务端的程序不启作用,可采用的是另一种方式: 需要进行通信的bluetoothDevice,直接调用createRfcommSocketToServiceRecord函数:
companion object{
//蓝牙串口服务 (SPP) 的 UUID
val SPP_UUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
}
private var bluetoothSocket:BluetoothSocket? = null
private var inputStream: InputStream? = null // 用来收数据
private var outputStream: OutputStream? = null // 用来发数据
fun startReadyConnect():Boolean {
//需要在线程中连接,否则超时会引起ANR
val coroutineScope = CoroutineScope(Dispatchers.IO)
coroutineScope?.launch {
//有个工具类BluetoothUtils,里面保存了等待连接的蓝牙设备对象
var bluetoothDevice = BluetoothUtils.getWaitingForConnectionDevice()
bluetoothDevice?.let {
try {
//通过createRfcommSocketToServiceRecord函数调用,这会引起蓝牙底层的配对连接动作
//如果连接成功,系统会自动弹出配对对话框,需要用户在一定时间里完成配对
//如果在一定时间里配对成功,则返回true,否则不配对或者取消配对,都会引起异常
bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(SPP_UUID)
bluetoothSocket?.connect()
inputStream = bluetoothSocket?.inputStream
outputStream = bluetoothSocket?.outputStream
if (inputStream != null && outputStream != null) {
BluetoothUtils.waitingForConnectionDevice = null
BluetoothUtils.connectedDevice = it
return true
}
} catch (e:Exception) {
e.printStackTrace()
}
}
BluetoothUtils.waitingForConnectionDevice = null
BluetoothUtils.connectedDevice = null
BluetoothUtils.bluetoothDisConnect()
return false
}
}
//在子线程里运行,比如先将数据放在LinkedBlockingQueue中,子线程while循环不断从LinkedBlockingQueue中取出数据
//调用writeBytes函数发送出去
fun writeBytes(bytes: ByteArray) {
if (isRun){
try {
outputStream?.write(bytes)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
//在子线程中的while循环里运行
fun read(): ByteArray? {
val num = inputStream?.read(buffer)?:0
if (num > 0) {
val readBytes = ByteArray(num)
System.arraycopy(buffer,0,readBytes,0,num)
return readBytes
}
return null
}