简单的蓝牙通信

作者: 海晨忆 | 来源:发表于2018-03-05 15:39 被阅读10次

    个人博客:haichenyi.com。感谢关注

      之前公司做智能家居类型,其中做了一个智能衣柜项目,与衣柜通信就是用的蓝牙通信。一些操作一些简单的开关指令,蓝牙通信与socket是类似的。

    步骤

    1. 清单文件注册权限
    2. 启动蓝牙服务(记得在清单文件中静态注册服务)
    3. 注册蓝牙广播(在蓝牙服务中动态注册蓝牙广播)
    4. 搜索,绑定,完成
    5. 退出app,停止服务,并在蓝牙服务的onDestory方法中取消注册蓝牙广播

    不想写说明,只想贴代码

    第一步:注册权限

        <!--获取蓝牙信息状态权限-->
        <uses-permission android:name="android.permission.BLUETOOTH"/>
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    

    第二步、第三步、第五步:启动蓝牙服务,注册蓝牙广播,停止服务

    
    /**
     * Author: 海晨忆.
     * Date: 2018/1/4
     * Desc:
     */
    public class BluetoothService extends Service {
      //得到蓝牙适配器
      private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      private BluetoothReceiver mReceiver;
    
      @Override
      public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
        if (mBluetoothAdapter != null) {
          mReceiver = new BluetoothReceiver().setBluetoothAdapter(mBluetoothAdapter);
          //注册设备被发现时的广播
          IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
          registerReceiver(mReceiver, filter);
          //注册一个搜索结束时的广播
          IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
          registerReceiver(mReceiver, filter2);
          startLinkBluetooth();
        }
      }
    
      @Nullable
      @Override
      public IBinder onBind(Intent intent) {
        return null;
      }
    
      /**
       * 开始连接蓝牙设备.
       */
      private void startLinkBluetooth() {
        if (null != mBluetoothAdapter) {
          //判断蓝牙是否打开
          if (!mBluetoothAdapter.isEnabled()) {
            //若没打开则打开蓝牙
            mBluetoothAdapter.enable();
          }
          mBluetoothAdapter.startDiscovery();
          Log.v(Constants.HTTP_WZ, "正在扫描");
        }
      }
    
      @Subscribe
      @SuppressWarnings("unused")
      public void handleMsg(BluetoothInfo bluetoothInfo) {
        if (bluetoothInfo.isLink) {
          startLinkBluetooth();
        }
      }
    
      public static class BluetoothInfo {
        private boolean isLink = false;
    
        public BluetoothInfo setLink(boolean link) {
          this.isLink = link;
          return this;
        }
      }
    
      @Override
      public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        if (mReceiver != null) {
          mReceiver.unRegister();
          unregisterReceiver(mReceiver);
        }
      }
    }
    

    这个就是我的蓝牙服务类,这个类的逻辑怎么走的呢?

    1. EventBus的东西我就不说了

    2. 首先获取蓝牙适配器

    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    
    1. 初始化蓝牙广播,注册蓝牙广播
    if (mBluetoothAdapter != null) {
          mReceiver = new BluetoothReceiver().setBluetoothAdapter(mBluetoothAdapter);
          //注册设备被发现时的广播
          IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
          registerReceiver(mReceiver, filter);
          //注册一个搜索结束时的广播
          IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
          registerReceiver(mReceiver, filter2);
          startLinkBluetooth();
        }
    
    1. 开始准备连接蓝牙设备
    /**
       * 开始连接蓝牙设备.
       */
      private void startLinkBluetooth() {
        if (null != mBluetoothAdapter) {
          //判断蓝牙是否打开
          if (!mBluetoothAdapter.isEnabled()) {
            //若没打开则打开蓝牙
            mBluetoothAdapter.enable();
          }
          mBluetoothAdapter.startDiscovery();
          Log.v(Constants.HTTP_WZ, "正在扫描");
        }
      }
    
    1. 上面4步蓝牙扫描就完成了,这里我还要说的是,在服务的onDestory方法里面,记得停止服务
    @Override
      public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        if (mReceiver != null) {
          mReceiver.unRegister();
          unregisterReceiver(mReceiver);
        }
      }
    
    1. 再就是在清单文件里面静态注册蓝牙服务
    <service android:name=".service.BluetoothService"/>
    
    1. 启动服务的方式,我用的是非绑定的方式,同样,记得停止服务。
    Intent bluetoothService = new Intent(this, BluetoothService.class);
    startService(bluetoothService);//启动蓝牙服务
    
    stopService(bluetoothService);
    
    @Nullable
      @Override
      public IBinder onBind(Intent intent) {
      //非绑定方式,返回值为null
        return null;
      }
    

    第四步:搜索,绑定,完成搜索

    
    /**
     * Author: 海晨忆.
     * Date: 2018/1/4
     * Desc: 蓝牙广播监听
     */
    public class BluetoothReceiver extends BroadcastReceiver {
      //衣柜的蓝牙名称
      private static final String WARDROBE_NAME = "WARDROBE";
      // 固定的UUID
      private static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
      private BluetoothSocket bluetoothSocket;
      private BluetoothAdapter bluetoothAdapter;
      private InputStream mInputStream;
      private OutputStream outputStream;
      private boolean isRunning = false;
    
      @Override
      public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action != null) {
          if (action.equals(BluetoothDevice.ACTION_FOUND)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            Log.v(Constants.HTTP_WZ, device.getName() + device.getAddress());
            if (device.getBondState() == BluetoothDevice.BOND_BONDED
                && device.getName().equals(WARDROBE_NAME)) {
              UUID uuid = UUID.fromString(SPP_UUID);
              try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(uuid);
                Log.v(Constants.HTTP_WZ, "准备连接");
                connect();
              } catch (IOException e) {
                e.printStackTrace();
              }
            }
          } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            if (!EventBus.getDefault().isRegistered(this))
              EventBus.getDefault().register(this);
            Observable.timer(2, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(aLong -> {
                  if (null == bluetoothSocket || !bluetoothSocket.isConnected())
                    ToastUtils.showTipMsg(R.string.no_wardrobe);
                });
          }
        }
      }
    
      private void connect() {
        new Thread(() -> {
          if (bluetoothSocket != null) {
            bluetoothAdapter.cancelDiscovery();
            try {
              bluetoothSocket.connect();
              Observable.just(1)
                  .observeOn(AndroidSchedulers.mainThread())
                  .subscribe(integer -> ToastUtils.showTipMsg(R.string.link_wardrobe));
              Log.v(Constants.HTTP_WZ, "连接成功");
              mInputStream = bluetoothSocket.getInputStream();
              Log.v(Constants.HTTP_WZ, "mInputSream:" + mInputStream.toString());
              isRunning = true;
              outputStream = bluetoothSocket.getOutputStream();
              Log.v(Constants.HTTP_WZ, "outputStream:" + outputStream.toString());
              BufferedReader br;
              while (isRunning) {
                br = new BufferedReader(new InputStreamReader(mInputStream, "utf-8"));
                String s = br.readLine();
                //acceptReply(s);
                Log.v(Constants.HTTP_WZ, "收到的数据:" + s);
              }
            } catch (IOException e) {
              e.printStackTrace();
              try {
                if (mInputStream != null) {
                  mInputStream.close();
                  Log.v(Constants.HTTP_WZ, "mInputSream.close()");
                }
                if (outputStream != null) {
                  outputStream.close();
                  Log.v(Constants.HTTP_WZ, "outputStream.close()");
                }
                if (bluetoothSocket != null) {
                  bluetoothSocket.close();
                  Log.v(Constants.HTTP_WZ, "socket.close()");
                  bluetoothSocket = null;
                }
                isRunning = false;
              } catch (Exception e2) {
                // TODO: handle exception
              }
            }
          }
        }).start();
      }
    
      public BluetoothReceiver setBluetoothAdapter(BluetoothAdapter adapter) {
        this.bluetoothAdapter = adapter;
        return this;
      }
      
      /**
       * 反注册eventBus.
       */
      public void unRegister() {
        EventBus.getDefault().unregister(this);
      }
    
    }
    

    这个就是我的蓝牙广播类,这个逻辑又是怎么走的呢?

    1. 前面服务里面注册的两个action,一个BluetoothDevice.ACTION_FOUND,还有一个BluetoothAdapter.ACTION_DISCOVERY_FINISHED,做了一个if判断,是发现了设备还是已经完成了扫描设备
    2. 发现设备之后,获取蓝牙信息,他这里是获取到一个蓝牙信息就会走一遍这个方法,并不是说一次获取一个列表
    3. 找到了蓝牙设备之后就是连接了,伪代码讲解:
    // 固定的UUID连接的时候需要uuid
      private static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
      
    //获取socket
    BluetoothSocket bluetoothSocket =device.createRfcommSocketToServiceRecord(uuid);
    
    //连接之前取消扫描,注意非空判断。adapter是在服务里面申明的,通过setBluetoothAdapter方法传过来的
    bluetoothAdapter.cancelDiscovery();
    
    //连接,这里是阻塞的方式,注意要新开线程连接
    bluetoothSocket.connect();
    
    //获取输入流对象和输出流对象
    InputStream mInputStream = bluetoothSocket.getInputStream();
    OutputStream outputStream = bluetoothSocket.getOutputStream();
    
    //发送消息
    private void sendInstruct(String msg) {
        try {
          if (null == bluetoothSocket || !bluetoothSocket.isConnected()) {
            SocketUtils.reLinkBluetooth();
            return;
          }
          Log.v(Constants.HTTP_WZ, "发送的数据-->" + msg + BluetoothInstruct.FINISH);
          outputStream.write(msg.getBytes());
          outputStream.flush();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    
    //接收消息,一次读一行,简单的蓝牙通信换行符作为结束标记
    BufferedReader br;
    while (isRunning) {
                br = new BufferedReader(new InputStreamReader(mInputStream, "utf-8"));
                String s = br.readLine();
                acceptReply(s);
                Log.v(Constants.HTTP_WZ, "收到的数据:" + s);
              }
              
    //异常的时候释放资源
    try {
                if (mInputStream != null) {
                  mInputStream.close();
                  Log.v(Constants.HTTP_WZ, "mInputSream.close()");
                }
                if (outputStream != null) {
                  outputStream.close();
                  Log.v(Constants.HTTP_WZ, "outputStream.close()");
                }
                if (bluetoothSocket != null) {
                  bluetoothSocket.close();
                  Log.v(Constants.HTTP_WZ, "socket.close()");
                  bluetoothSocket = null;
                }
                isRunning = false;
              } catch (Exception e2) {
                // TODO: handle exception
              }
    

    相关文章

      网友评论

        本文标题:简单的蓝牙通信

        本文链接:https://www.haomeiwen.com/subject/xzehfftx.html