栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android蓝牙通信

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android蓝牙通信

Android蓝牙通信的两种方式
  • 添加权限
  • 获取蓝牙设备列表
    • 通过广播方式获取蓝牙设备
    • 5.0以下代码方式获取蓝牙设备
    • 5.0以上代码获取蓝牙设备
  • 蓝牙配对
    • 配对
    • 取消配对
    • 删除配对信息
    • 监听配对结果
  • 作为中央BluetoothGatt的实现
    • 建立连接
    • 发送数据
  • 双向服务通信
    • 建立服务端
    • 建立客户端
  • 参考文档

添加权限
   
    
    
    
获取蓝牙设备列表 通过广播方式获取蓝牙设备
val broadcastReceiver:BroadcastReceiver =object: BroadcastReceiver(){
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action
        //获取设备
        val device  =intent.getParcelableExtra
                            (BluetoothDevice.EXTRA_DEVICE)
        //获取信号强度
        int rssi = intent.extras.getShort(BluetoothDevice.EXTRA_RSSI).toInt()
        if(action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)){
            //todo 开始扫描
        }else if(action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)){
            //结束扫描            
        }else if(action.equals(BluetoothDevice.ACTION_FOUND)){
            //找到蓝牙设备
        }
    }
}

private fun startScan(){
    BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()
    if(adapter.isEnabled){
        adapter.starterDisconvery()
    }
}

private fun stopScan(){
    BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()
    if(adapter.isEnabled){
        adapter.cancelDiscovery()
    }
}
5.0以下代码方式获取蓝牙设备
private fun startScan(){
    BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()
    if(adapter.isEnabled){
        adapter.startLeScan(mScanCallback)
    }
}

private fun stopScan(){
      BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()
    if(adapter.isEnabled){
        adapter.stopLeScan(mScanCallback )
    }
}

private val mScanCallback = BluetoothAdapter.LeScanCallback {
    device,rssi,scanRecord ->
    //device 蓝牙设备信息
    //rssi 信号强度
    //scanRecord  远程蓝牙设备官博数据
}
5.0以上代码获取蓝牙设备
private fun starScan(){
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()
    if(adapter.isEnabled){
        val setting    ScanSettings.Builder()
        //扫描模式设置
        .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
        .setMatchMode(ScanSettings.MATCH_MODE_STICKY)
        .build()
        adapter.startScan(null,setting ,mScanCallback )
    }
}

private val mLeScanCallback = object : ScanCallback(){
    override fun onBatchScanResults(results: MutableList?) {
    super.onBatchScanResults(results)
    results?.forEach { result ->
        Log.e(
            TAG, "${result.device?.name},${result.device?.address},${result.rssi},"
        )
    }
}

    override fun onScanFailed(errorCode: Int) {
        super.onScanFailed(errorCode)
        Toast.makeText(requireContext(), getText(R.string.scan_falied), Toast.LENGTH_LONG)
            .show()
    }
    
    override fun onScanResult(callbackType: Int, result: ScanResult?) {
        super.onScanResult(callbackType, result)
        if (result != null) {
            Log.e(TAG, "${result.device?.name},${result.device?.address},${result.rssi},")
            //所有结果定义在ScanResult中
            // result.device
            // result.rssi
            // result.scanRecord
        }
    }
}

private fun stopScan(){
      BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter()
    if(adapter.isEnabled)
    mBLEScanner?.stopScan(mLeScanCallback)
}
蓝牙配对 配对
private fun pair(device: BluetoothDevice) {
    val method = device.javaClass.getMethod("createBond")
    method.invoke(device)
}
取消配对
//取消配对
private fun cancelPair(device:BluetoothDevcie):Boolean?{
    val method = device.javaClass.getMethod("cancelBondProcess")
    return    method.invoke(device)
}
删除配对信息
private fun deletePair(device:BluetoothDevice){
     val method = device.javaClass.getMethod("removeBond")
    return    method.invoke(device)
}
监听配对结果
//监听蓝牙配对广播
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        //蓝牙配对广播
        if (intent.action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
            val device =
                intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
            when (device?.bondState) {
                //配对失败
                BluetoothDevice.BOND_NONE -> {
                    alertDialog!!.setMessage(getString(R.string.pair_cancel))
                    alertDialog!!.getButton(DialogInterface.BUTTON_POSITIVE).isEnabled = true
                }
                //配对中...
                BluetoothDevice.BOND_BonDING -> {
                    alertDialog!!.setMessage(getString(R.string.pairing))
                    alertDialog!!.getButton(DialogInterface.BUTTON_POSITIVE).isEnabled = false
                }
                // 配对成功
                BluetoothDevice.BOND_BonDED -> {
                    alertDialog?.setMessage(getString(R.string.pair_success))
                    alertDialog?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = true
                    homeViewModel.updateDeviceStatus(device.address)
                }
            }
    }
 }
作为中央BluetoothGatt的实现

低功耗蓝牙的基本概念:
在BLE协议中,有两个角色,周边(Periphery)和中央(Central)。周边是数据的提供者,中央是数据的使用和处理者。在Android SDK里面,Android4.3以后手机可以作为中央使用;Android5.0以后手机才可以作为周边使用,即此时的手机可以作为BLE设备(如可穿戴设备、手环、智能锁、心率测量仪等)来为中央提供数据。
一个中央可以同时连接多个周边,但一个周边某一时刻只能连接一个中央。

建立连接
//建立连接
fun connectGatt(var address:String) {
    val device = bluetoothAdapter.getRemoteDevice(address)
    if (bluetoothAdapter.isEnabled) {
        device.connectGatt(requireContext(), false, bluetoothGattCallback)
    }
}

//蓝牙连接实体类 回调都是在子线程中,不可做更新 UI 操作
private val bluetoothGattCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
        override fun onPhyUpdate(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) {
            super.onPhyUpdate(gatt, txPhy, rxPhy, status)
            Log.e(TAG, "onPhyUpdate")
        }

        override fun onPhyRead(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) {
            super.onPhyRead(gatt, txPhy, rxPhy, status)
            Log.e(TAG, "onPhyRead")
        }
        
        //监听连接状态
        override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
            Log.e(TAG, "$status , $newState")
            //连接状态
            if (status == BluetoothGatt.GATT_SUCCESS) {
                when (newState) {
                    BluetoothProfile.STATE_DISConNECTED -> {
                        gatt.close()
                        //连接状态,断开连接后的操作
                    }
                    BluetoothProfile.STATE_ConNECTED ->                 
                        //发现服务
                        gatt.discoverServices()
                }
            } else {
                val msg = mHandler.obtainMessage(SHOW_TIPS)
                mHandler.sendMessage(msg)
                mHandler.sendEmptyMessage(CLOSE_LOADING)
            }
            
            //当 status === 133时需要清楚缓存,断开连接,然后重新开始连接
            super.onConnectionStateChange(gatt, status, newState)
        }
        //蓝牙连接上后,查看对方可用的服务信息
        override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
            super.onServicesDiscovered(gatt, status)
            mGatt = gatt
             //todo 查找服务列表
             //根据服务UUID 查找对应服务信息
             // 通过UUID查询指定服务下的 功能列表 characteristic
val gattService = gatt.getService(UUID.fromString(mServiceUUID))
if (gattService == null) {
    Log.e(
        TAG,
        "onServicesDiscovered-->" + "获取服务指定uuid:" + mServiceUUID + "的BluetoothGattService为空,请联系外设设备开发商确认uuid是否正确"
    )
}
    //根据指定特征值uuid获取指定的特征值二
    //根据指定特征值uuid获取指定的特征值二
    mWriteGattCharacteristic1 =
        gattService.getCharacteristic(UUID.fromString(mWriteCharacteristicUUID1))
    mWriteGattCharacteristic2 =
        gattService.getCharacteristic(UUID.fromString(mWriteCharacteristicUUID2))
                          // 发送数据
        }

        override fun onCharacteristicChanged(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?
        ) {
            super.onCharacteristicChanged(gatt, characteristic)
            Log.d(
                TAG,
                "onCharacteristicChanged-->" + characteristic!!.uuid + "," + characteristic.value.toString()
            )
            //过滤,判断是否是目标特征值
        }

        //发送数据后的回调,可以在此检测发送的数据包是否有异常
        override fun onCharacteristicWrite(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic,
            status: Int
        ) {
            super.onCharacteristicWrite(gatt, characteristic, status)
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d(
                    TAG,
                    "onCharacteristicWrite:发送数据成功:" + BleHelp.binaryToHexString(characteristic.value)
                )
            } else Log.e(TAG, "onCharacteristicWrite:发送数据失败")
        }
    }
发送数据
// 每次发送数据大小不能超过20字节
private fun sendData(gatt: BluetoothGatt) {
    Thread {
        Log.e(TAG, "发送数据开始")
        val data = DataUtils.getData()
        //写入控制开始
        mWriteGattCharacteristic1.value = byteArrayOf(0x00)
        gatt.writeCharacteristic(mWriteGattCharacteristic1)
        for (cmd in data) {
            Log.e(TAG, BleHelp.binaryToHexString(cmd))
            sendData2(cmd, gatt)
            Thread.sleep(200)
        }

        //写入控制结束
        mWriteGattCharacteristic1.value = byteArrayOf(0x01)
        gatt.writeCharacteristic(mWriteGattCharacteristic1)
        Log.e(TAG, "发送数据完成")
    }.start()
}
双向服务通信

为了在两台设备上创建一个连接,你必须实现服务器端和客户端两头的机制,因为一个设备必须打开一个服务器socket,而另一个设备初始化创建(使用服务器设备的MAC地址来初始化一个连接)。当他们在相同的RFCOMM通道上有一个已连接的 BluetoothSocket 时,服务器和客户被认为是互相连接了。

注意:如果两台设备之前没有配对过,那么Android框架将会自动显示一个请求配对的通知或对话框,正如图3中显示的那样。因此,当尝试连接设备时,你的应用不需要考虑设备是否配对过。你的RFCOMM连接尝试将会阻塞,知道用户成功配对,或者用户拒绝失败时,或者配对失败,或者超时。

建立服务端
private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;
 
    public AcceptThread() {
        // Use a temporary object that is later assigned to mmServerSocket,
        // because mmServerSocket is final
        BluetoothServerSocket tmp = null;
        try {
            // MY_UUID is the app's UUID string, also used by the client code
            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) { }
        mmServerSocket = tmp;
    }
 
    public void run() {
        BluetoothSocket socket = null;
        // Keep listening until exception occurs or a socket is returned
        while (true) {
            try {
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                manageConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }
 
    
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) { }
    }
}
建立客户端
private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
 
    public ConnectThread(BluetoothDevice device) {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        BluetoothSocket tmp = null;
        mmDevice = device;
 
        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) { }
        mmSocket = tmp;
    }
 
    public void run() {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();
 
        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }
 
        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }
 
    
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}
参考文档

【1】手机作为周边BluetoothGattServer的实现
【2】Android中文社区(Bluetooth)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/325409.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号