美文网首页
蓝牙开发《基础篇二》

蓝牙开发《基础篇二》

作者: 安仔夏天勤奋 | 来源:发表于2020-04-15 13:59 被阅读0次

最近项目中使用到蓝牙打印机,通过蓝牙连接蓝牙打印机进行打印功能。在此对蓝牙知识进行归纳输出一波,达到巩固之效果。蓝牙开发《基础篇一》

蓝牙开发

Android 的蓝牙开发主要分为两种:

  • 经典蓝牙开发
  • BLE蓝牙开发

经典蓝牙开发

英文: Classic Bluetooth

用处

用于多个 Android 端流媒体传输和通讯。

使用步骤

通过使用蓝牙 API 开发需要完成以下 4 个主要的任务:

  • 设置蓝牙 API
  • 查找设备
  • 连接设备
  • 设备间数据传输

准备工作

配对和绑定过程

配对过程 在发现对应需要传输数据的设备之后,就可以进行设备间的配对。

绑定过程 在配对完成后,交换了「安全码」之后就完成了绑定过程。

在配对和绑定完成之后 Android 设备间才可以进行数据的传输。在数据传输会话结束后,设备之间会释放连接,使其重新变成可发现状态。但是他们没有解除绑定关系,下次只要两台设备在合理的范围内,它们就会自动地进行连接。

权限分配

  • android.permission.BLUETOOTH

    请求连接,接受连接,传输数据

  • LOCATON

    获取设备定位权限,用于确定设备的距离

  • BLUETOOTH_ADMIN

    用于设备发起查找附近蓝牙设备

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    

无线接口规范 Profiles

基于蓝牙的设备通讯的无线接口通讯规范。

使用 profiles

  • 得到一个 BluetoothAdapter 这个对应于使用蓝牙的设置步骤
  • 注册 BluetoothProfile.ServiceListener 事件,监听蓝牙的连接与断开连接
  • getProfileProxy() 和具体的代理对象建立连接,例如 BluetoothHeadset,BluetoothGatt等
  • onServiceConnected() 接收通过 getProfileProxy 进行的连接的代理对象
  • 在获取到代理对象 profiles 之后就可以进行通过它进行监听连接的状态和操作该profile相关的功能。

设置 Bluetool

  • 判断设备是否支持蓝牙

      BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      if (mBluetoothAdapter == null) {
      // Device does not support Bluetooth
      }
    
  • 开启蓝牙

    通过下面这种方式优雅地开启蓝牙,并且可以在当前应用接收蓝牙开关状态,也就是在 onActivityResult 接受 RESULT_OK result code 即可。

      if (!mBluetoothAdapter.isEnabled()) {
          Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
          startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
      }
    

查找设备

通过 BluetoolAdapter 可以扫描附近的蓝牙设备或者从已配对的蓝牙列表中查找。

  • 查找已配对设备

    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
    if (pairedDevices.size() > 0) {
          // There are paired devices. Get the name and address of each paired device.
          for (BluetoothDevice device : pairedDevices) {
                  String deviceName = device.getName();
              String deviceHardwareAddress = device.getAddress(); // MAC address
          }
      }
    
  • 扫描设备

    在扫描到设备之后,系统是通过广播的方式来通知的,因此需要注册一个广播接受者

    扫描设备这个过程是比较消耗资源的,在你进行连接之后,就要停止扫描操作。当已经和设备进行建立连接了,就不要进行扫描操作,不然会渐低已连接设备的可用带宽的。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
              ...
              // Register for broadcasts when a device is discovered.
              IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
              registerReceiver(mReceiver, filter);
              //开始扫描
              adapter.startDiscovery();
      }
    // Create a BroadcastReceiver for ACTION_FOUND.
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
          public void onReceive(Context context, Intent intent) {
              String action = intent.getAction();
              if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                  // Discovery has found a device. Get the BluetoothDevice
                  // object and its info from the Intent.
                  //获取扫描的设备对象
                  BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                  String deviceName = device.getName();
                  String deviceHardwareAddress = device.getAddress(); // MAC address
               }
              }
      };
    @Override
    protected void onDestroy() {
              super.onDestroy();
              ...
              // Don't forget to unregister the ACTION_FOUND receiver.
              unregisterReceiver(mReceiver);
              //在需要的时候停止扫描
              adapter. cancelDiscovery();
      }
    
  • 让设备可见

    想要让其他蓝牙蓝牙设备扫描到自己,那么就必须让当前设备可见。Android 通过发送意图的方式来设置蓝牙设备可见性。
    通过注册 intent = ACTION_SCAN_MODE_CHANGED 的广播可以监听设备的可见状态,该广播intent有2个 extra field 分别是

    • EXTRA_SCAN_MODE 新的状态
    • EXTRA_PREVIOUS_SCAN_MODE 旧的状态

    该intent这两个额外的属性的取值分别如下:

    • BloothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE 设备处于可见状态
    • BloothAdapter.SCAN_MODE_CONNECTABLE 设备不处于可见状态,但是可以接受连接
    • BloothAdapter.SCAN_MODE_NONE 设备处于不可见状态,并且不可以连接
          Intent discoverableIntent =
          new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
          //设备可见300s。
          //如果这个值为0表示设备一直可见不过google不推荐这样做。
          discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
          startActivity(discoverableIntent);
          IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_SCAN_MODE_CHANGED);
          registerReceiver(mReceiver, filter);
          private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
              public void onReceive(Context context, Intent intent) {
                  String action = intent.getAction();
                  if (BluetoothDevice.ACTION_SCAN_MODE_CHANGED.equals(action)){
                  //取出action的属性即可
                  }
          }
    

连接设备

当之前几步操作都完毕之后,现在就可以准备进行蓝牙设备的连接了。

连接的标记

当客户端和服务端在同一个 RFCOMM 通道都有一个已连接的 BlueSocket 就表示已建立连接,此时双方设备都可以获取输入输出流对象,就可以进行数据通讯了。

服务端连接

基本操作流程:

  • 获取 BluetoolServerSocket 对象。
  • accept() 接受客户端连接,该方法是一个阻塞式方法,当接收到连接或者是出现异常才会返回。当成功接受连接之后会返回一个已连接的 BluetoolSocket 对象。注意:此时返回的 BluetoolSocket 不需要调用 connect 方法进行连接。
  • 除非你想要接受额外的客户端连接,否则你可以调用 close 方法去释放 BluetoolServerSocket 的相关资源。但是并不关闭通过accept()方法获取到的 BluetoolSocket 资源,和 TCP/IP 不一样的是,RFCOMM 允许在在某个时间存在一个已连接的client。所以说一般情况,当accept 获取到连接就后就可以将 BluetoolServerSocket 进行关闭。

客户端连接

作为客户端而言,当远程设备在一个打开的 ServerSocket 上接受连接时,客户端首先需要获取一个代表远程设备的 BluetoolDevice ,然后根据这个 BluetoolDevice 去获取一个 BluetoolSocket 对象,并且建立连接。

基本的操作流程:

  • 获取远程设备的 BluetoolDevice

  • 根据BluetoolDevice 获取 BluetoolSocket createRfcommSocketToServiceRecord(UUID)

  • connect() 发起连接,注意该方法是阻塞方法,应该将其放到子线程中去处理。

  • 当 connect() 方法被调用之后,系统就会去和远程设备进行连接,当连接成功,那么两个蓝牙设备就共同一个 RFCOMM channel 。如果 connect 方法失败或者超时(about 12s)那么该方法就会抛出 IOException 异常。

  • 当使用完之后需要将 socket进行close。

    上面我们讲过,在扫描设备之后,我们调用 connect 方法进行设备连接之前一定要记得cancelDiscover() ,因为在已连接的设备如果还在扫描的话,会占用设备的通讯带宽。判断方法:isDiscovering().

管理连接

获取输入输出流,注意这两个方法都是阻塞式方法,需要放在子线程中执行。

总结

  • BluetoolAdapter

    表示本地蓝牙适配器,它是所有蓝牙通讯交互的入口点。
    扫描设备。
    列出已绑定的设备。
    根据 mac 地址初始化一个 BluetoolDevice 。
    创建 BluetoolServerSocket 监听来自其他设备的连接。

  • BluetoolDevice

    代表远程设备
    通过 bluetoolDevice 可以获取与远程建立连接的 BluetoolSocket
    查询远程设备的信息,name,mac和绑定状态。

  • BluetoolSocket

    允许当前设备通过输入输出流与其他设备进行数据交换

  • BluetoolServerSocket

    用于服务端,监听所有的客户端的连接,当接受到远程设备的连接之后就返回一个已连接的 BluetoolSocket 。

相关文章

网友评论

      本文标题:蓝牙开发《基础篇二》

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