当前位置:   article > 正文

Android硬件通信之 蓝牙通信_android蓝牙通信

android蓝牙通信

一,简介

1.1 现在的手机设备基本上都支持蓝牙模块,蓝牙与蓝牙之前可以相互通信,所以只要物联网机器上配有蓝牙模块,就可以用手机蓝牙连接机器蓝牙,从而和机器通信

1.2 蓝牙按协议常见可以分为经典蓝牙和低功耗蓝牙,下面是主要区别:

对比经典蓝牙低功耗蓝牙
协议4.0以下4.0以上
   传输速度慢,100ms

快,3ms

传输大小大,可以传大文件小,大文件需要分包 
网络拓扑点对点点对点,广播,Mesh组网
应用领域无线耳机,无线音箱鼠标,单车,智能家居,监控系统,灯光组网


 

二,经典蓝牙

2.1 开启蓝牙

获取BluetoothAdapter对象

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

2.2 判断设备是否支持蓝牙 

  1. /**
  2. * 设备是否支持蓝牙 true为支持
  3. * @return
  4. */
  5. public boolean isSupportBlue(){
  6. return mBluetoothAdapter != null;
  7. }

 2.3 判断蓝牙是否开启

  1. /**
  2. * 蓝牙是否打开
  3. * @return
  4. */
  5. public boolean isBlueEnable(){
  6. return mBluetoothAdapter.isEnabled();
  7. }

2.4 添加权限

  1. <!-- 使用蓝牙的权限 -->
  2. <uses-permission android:name="android.permission.BLUETOOTH" />
  3. <!-- 扫描蓝牙设备或者操作蓝牙设置 -->
  4. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  5. <!--模糊定位权限,仅作用于6.0+-->
  6. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  7. <!--精准定位权限,仅作用于6.0+-->
  8. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2.5 动态请求权限

  1. /**
  2. * 检查权限
  3. */
  4. private void checkPermissions() {
  5. String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION};
  6. List<String> permissionDeniedList = new ArrayList<>();
  7. for (String permission : permissions) {
  8. int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
  9. if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
  10. onPermissionGranted(permission);
  11. } else {
  12. permissionDeniedList.add(permission);
  13. }
  14. }
  15. if (!permissionDeniedList.isEmpty()) {
  16. String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
  17. ActivityCompat.requestPermissions(this, deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);
  18. }
  19. }
  20. /**
  21. * 权限回调
  22. * @param requestCode
  23. * @param permissions
  24. * @param grantResults
  25. */
  26. @Override
  27. public final void onRequestPermissionsResult(int requestCode,
  28. @NonNull String[] permissions,
  29. @NonNull int[] grantResults) {
  30. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  31. switch (requestCode) {
  32. case REQUEST_CODE_PERMISSION_LOCATION:
  33. if (grantResults.length > 0) {
  34. //权限成功做其它任务
  35. }
  36. break;
  37. }
  38. }

 2.6 检查GPS是否打开

  1. /**
  2. * 检查GPS是否打开
  3. * @return
  4. */
  5. private boolean checkGPSIsOpen() {
  6. LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
  7. if (locationManager == null)
  8. return false;
  9. return locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER);
  10. }

 2.7 前往设置里面开启GPS

  1. Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
  2. startActivityForResult(intent, REQUEST_CODE_OPEN_GPS);

2.8 扫描蓝牙

  1. //发现蓝牙
  2. public void startBluetoothDiscovery() {
  3. //当前是否在扫描,如果是就取消当前的扫描,重新扫描
  4. if (mBluetoothAdapter.isDiscovering()){
  5. mBluetoothAdapter.cancelDiscovery();
  6. }
  7. mBluetoothAdapter.startDiscovery();
  8. }

2.9 监听蓝牙扫描状态

  1. IntentFilter filter = new IntentFilter();
  2. filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙开关状态
  3. filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//蓝牙开始搜索
  4. filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//蓝牙搜索结束
  5. filter.addAction(BluetoothDevice.ACTION_FOUND);//蓝牙发现新设备(未配对的设备)
  6. registerReceiver(scanBlueReceiver, filter);
  1. /**
  2. * 扫描广播接收类
  3. */
  4. public class ScanBlueReceiver extends BroadcastReceiver {
  5. private static final String TAG = ScanBlueReceiver.class.getName();
  6. private ScanBlueCallBack callBack;
  7. public ScanBlueReceiver(ScanBlueCallBack callBack){
  8. this.callBack = callBack;
  9. }
  10. //广播接收器,当远程蓝牙设备被发现时,回调函数onReceiver()会被执行
  11. @Override
  12. public void onReceive(Context context, Intent intent) {
  13. String action = intent.getAction();
  14. Log.d(TAG, "action:" + action);
  15. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  16. switch (action){
  17. case BluetoothAdapter.ACTION_STATE_CHANGED:
  18. int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
  19. switch (blueState) {
  20. case BluetoothAdapter.STATE_TURNING_ON:
  21. Log.e(TAG,"蓝牙正在打开中");
  22. break;
  23. case BluetoothAdapter.STATE_ON:
  24. Log.e(TAG,"蓝牙已经打开");
  25. mListener.stateOn();
  26. break;
  27. case BluetoothAdapter.STATE_TURNING_OFF:
  28. Log.e(TAG,"蓝牙正在关闭中");
  29. break;
  30. case BluetoothAdapter.STATE_OFF:
  31. Log.e(TAG,"蓝牙已经关闭");
  32. mListener.stateOff();
  33. break;
  34. }
  35. break;
  36. case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
  37. Log.d(TAG, "开始扫描...");
  38. callBack.onScanStarted();
  39. break;
  40. case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
  41. Log.d(TAG, "结束扫描...");
  42. callBack.onScanFinished();
  43. break;
  44. case BluetoothDevice.ACTION_FOUND:
  45. Log.d(TAG, "发现设备...");
  46. callBack.onScanning(device);
  47. break;
  48. }
  49. }
  50. }

2.10 连接蓝牙

  1. /*
  2. * 连接蓝牙线程
  3. */
  4. public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {
  5. private static final String TAG = ConnectBlueTask.class.getName();
  6. private BluetoothDevice bluetoothDevice;
  7. private ConnectBlueCallBack callBack;
  8. public ConnectBlueTask(ConnectBlueCallBack callBack){
  9. this.callBack = callBack;
  10. }
  11. @Override
  12. protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
  13. bluetoothDevice = bluetoothDevices[0];
  14. BluetoothSocket socket = null;
  15. try{
  16. Log.d(TAG,"开始连接socket,uuid:" + ClassicsBluetooth.UUID);
  17. socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(ClassicsBluetooth.UUID));
  18. if (socket != null && !socket.isConnected()){
  19. socket.connect();
  20. }
  21. mOutputStream = socket.getOutputStream();
  22. mInputStream = socket.getInputStream();
  23. }catch (IOException e){
  24. Log.e(TAG,"socket连接失败");
  25. try {
  26. socket.close();
  27. } catch (IOException e1) {
  28. e1.printStackTrace();
  29. Log.e(TAG,"socket关闭失败");
  30. }
  31. }
  32. return socket;
  33. }
  34. @Override
  35. protected void onPreExecute() {
  36. Log.d(TAG,"开始连接");
  37. if (callBack != null) callBack.onStartConnect();
  38. }
  39. @Override
  40. protected void onPostExecute(BluetoothSocket bluetoothSocket) {
  41. if (bluetoothSocket != null && bluetoothSocket.isConnected()){
  42. Log.d(TAG,"连接成功");
  43. if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
  44. }else {
  45. Log.d(TAG,"连接失败");
  46. if (callBack != null) callBack.onConnectFail(bluetoothDevice, "连接失败");
  47. }
  48. }
  49. }

2.11 判断蓝牙是否连接

  1. /**
  2. * 当前设备与指定设备是否连接
  3. */
  4. public boolean isBlueToothConnected() {
  5. boolean connected = (bluetoothSocket != null && bluetoothSocket.isConnected());
  6. if (bluetoothDevice == null)
  7. return connected;
  8. return connected && bluetoothSocket.getRemoteDevice().equals(bluetoothDevice);
  9. }

2.12 读取蓝牙消息

  1. private class ReadThread extends Thread {
  2. @Override
  3. public void run() {
  4. super.run();
  5. while (!isInterrupted()) {
  6. int size;
  7. try {
  8. byte[] buffer = new byte[512];
  9. if (mInputStream == null) return;
  10. size = mInputStream.read(buffer);
  11. if (size > 0) {
  12. String mReception=new String(buffer, 0, size);
  13. String msg = mReception.toString().trim();
  14. Log.e(TAG, "接收短消息:" + msg);
  15. }
  16. } catch (IOException e) {
  17. e.printStackTrace();
  18. return;
  19. }
  20. }
  21. }
  22. }

 2.13 发送蓝牙指令

  1. private class WriteRunnable implements Runnable {
  2. @Override
  3. public void run() {
  4. try {
  5. String cmd="KZMT;";
  6. Log.e(TAG, "发送短消息:" + cmd);
  7. mOutputStream.write(cmd.getBytes());
  8. mOutputStream.flush();
  9. } catch (IOException e) {
  10. }
  11. }
  12. }

2.14 断开连接

  1. /**
  2. * 关闭蓝牙Socket连接
  3. */
  4. public void closeBluetoothStream() {
  5. try {
  6. if (mOutputStream != null) {
  7. mOutputStream.close();
  8. mOutputStream = null;
  9. }
  10. if (mInputStream != null) {
  11. mInputStream.close();
  12. mInputStream = null;
  13. }
  14. if (bluetoothSocket != null) {
  15. if (bluetoothSocket.isConnected()) {
  16. bluetoothSocket.close();
  17. }
  18. bluetoothSocket = null;
  19. }
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }

三,低功耗蓝牙

3.1 低功耗蓝牙扫描之前的步骤都一样,开启,请求权限等,从扫描开始有变化,所以扫描之前步骤可以参考经典蓝牙,下面是扫描的操作:

  1. private BluetoothAdapter mBluetoothAdapter;
  2. private boolean isScanning;//是否正在搜索
  3. private Handler mHandler;
  4. //15秒搜索时间
  5. private static final long SCAN_PERIOD = 15000;
  6. private void scanLeDevice(final boolean enable) {
  7. if (enable) {//true
  8. //15秒后停止搜索
  9. mHandler.postDelayed(new Runnable() {
  10. @Override
  11. public void run() {
  12. isScanning = false;
  13. mBluetoothAdapter.stopLeScan(mLeScanCallback);
  14. }
  15. }, SCAN_PERIOD);
  16. isScanning = true;
  17. mBluetoothAdapter.startLeScan(mLeScanCallback); //开始搜索
  18. } else {//false
  19. isScanning = false;
  20. mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止搜索
  21. }
  22. }
  23. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
  24. @Override
  25. public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
  26. //这里是个子线程,下面把它转换成主线程处理
  27. runOnUiThread(new Runnable() {
  28. @Override
  29. public void run() {
  30. //在这里可以把搜索到的设备保存起来
  31. //device.getName();获取蓝牙设备名字
  32. //device.getAddress();获取蓝牙设备mac地址
  33. //这里的rssi即信号强度,即手机与设备之间的信号强度。
  34. }
  35. });
  36. }
  37. };

3.2 停止扫描

mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止搜索

3.3 连接蓝牙

  1. //这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接它),和BluetoothGattCallback调用。
  2. BluetoothGatt mBluetoothGatt = device.connectGatt(this, false, mBluetoothGattCallback);
  3. BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
  4. @Override
  5. public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
  6. super.onPhyUpdate(gatt, txPhy, rxPhy, status);
  7. }
  8. @Override
  9. public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
  10. super.onPhyRead(gatt, txPhy, rxPhy, status);
  11. }
  12. //当连接状态发生改变
  13. @Override
  14. public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
  15. super.onConnectionStateChange(gatt, status, newState);
  16. }
  17. //发现新服务,即调用了mBluetoothGatt.discoverServices()后,返回的数据
  18. @Override
  19. public void onServicesDiscovered(BluetoothGatt gatt, int status) {
  20. super.onServicesDiscovered(gatt, status);
  21. }
  22. //调用mBluetoothGatt.readCharacteristic(characteristic)读取数据回调,在这里面接收数据
  23. @Override
  24. public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  25. super.onCharacteristicRead(gatt, characteristic, status);
  26. }
  27. //发送数据后的回调
  28. @Override
  29. public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  30. super.onCharacteristicWrite(gatt, characteristic, status);
  31. }
  32. @Override
  33. public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
  34. super.onCharacteristicChanged(gatt, characteristic);
  35. }
  36. @Override
  37. public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {//descriptor读
  38. super.onDescriptorRead(gatt, descriptor, status);
  39. }
  40. @Override
  41. public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {//descriptor写
  42. super.onDescriptorWrite(gatt, descriptor, status);
  43. }
  44. @Override
  45. public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
  46. super.onReliableWriteCompleted(gatt, status);
  47. }
  48. //调用mBluetoothGatt.readRemoteRssi()时的回调,rssi即信号强度
  49. @Override
  50. public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {//读Rssi
  51. super.onReadRemoteRssi(gatt, rssi, status);
  52. }
  53. @Override
  54. public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
  55. super.onMtuChanged(gatt, mtu, status);
  56. }
  57. };

3.4 断开连接

mBluetoothGatt.disconnect(); //主动断开连接

3.5 写入数据,通过mBluetoothGatt.writeCharacteristic(characteristic)

写入的数据长度是有限制的,如果要改变这个限制,可以通过MTU来改变

  1. /**
  2. * 向蓝牙发送数据
  3. */
  4. public void dataSend(){
  5. //byte[] send={(byte) 0xaa,0x01,0x01,(byte)0x81,(byte) 0xff};
  6. byte[] send = new byte[20];
  7. send = hexStringToBytes(et_send.getText().toString());
  8. byte[] sendData=new byte[send.length+2];
  9. sendData[0]=(byte) 0xaa;
  10. sendData[sendData.length-1]=(byte) 0xff;
  11. for(int i=1;i<sendData.length-1;i++){
  12. sendData[i]=send[i-1];
  13. }
  14. mCharacteristic.setValue(sendData);
  15. boolean status = mBluetoothGatt.writeCharacteristic(mCharacteristic);
  16. }

3.6 读取数据,通过mBluetoothGatt.readCharacteristic(characteristic),在BluetoothGattCallback 回调方法onCharacteristicRead中获取到数据。

  1. //读取数据时调用这个方法,数据会在回调接口中(BluetoothGattCallback )获取到
  2. mBluetoothGatt.readCharacteristic(characteristic)
  3. BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {
  4. //调用mBluetoothGatt.readCharacteristic(characteristic)读取数据回调,在这里面接收数据
  5. @Override
  6. public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  7. super.onCharacteristicRead(gatt, characteristic, status);
  8. //这里面就是数据
  9. characteristic.getValue();
  10. }
  11. }

3.7 总结

第一步:我们要判断手机是否支持BLE,并且获得各种权限,才能让我们之后的程序能正常运行。 
然后,我们去搜索BLE设备,得到它的MAC地址。 
第二步:我们通过这个MAC地址去连接,连接成功后,去遍历得到Characteristic的uuid。 
在我们需要发送数据的时候,通过这个uuid找到Characteristic,去设置其值,最后通过writeCharacteristic(characteristic)方法发送数据。 
如果我们想知道手机与BLE设备的距离,则可以通过readRemoteRssi()去得到rssi值,通过这个信号强度,就可以换算得到距离。 
第三步:连接上后,我们就可以用BluetoothGatt的各种方法进行数据的读取等操作

3.8 相关api

1、BluetoothManager

通过BluetoothManager来获取BluetoothAdapter。 

2、BluetoothAdapter

代表了移动设备的本地的蓝牙适配器, 通过该蓝牙适配器可以对蓝牙进行基本操作,一个Android系统只有一个BluetoothAdapter,通过BluetoothManager获取。 

3、BluetoothDevice

扫描后发现可连接的设备,获取已经连接的设备,通过它可以获取到BluetoothGatt。

4、BluetoothGatt

继承BluetoothProfile,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback,可以看成蓝牙设备从连接到断开的生命周期。

5、BluetoothGattService

服务,Characteristic的集合。

6、BluetoothGattCharacteristic

相当于一个数据类型,可以看成一个特征或能力,它包括一个value和0~n个value的描述(BluetoothGattDescriptor)。

7、BluetoothGattDescriptor

描述符,对Characteristic的描述,包括范围、计量单位等。

8、BluetoothProfile

一个通用的规范,按照这个规范来收发数据。 

9、BluetoothGattCallback

已经连接上设备,对设备的某些操作后返回的结果。

10、总结:当我们扫描后发现多个设备BluetoothDevice,每个设备下会有很多服务BluetoothGattService,这些服务通过service_uuid(唯一标识符)来区分,每个服务下又会有很多特征BluetoothGattCharacteristic,这些特征通过uuid来区分的,它是手机与BLE终端设备交换数据的关键。而BluetoothGatt可以看成手机与BLE终端设备建立通信的一个管道,只有有了这个管道,才有了通信的前提

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/549225
推荐阅读
相关标签
  

闽ICP备14008679号