最近公司项目要通过手机蓝牙连接硬件设备,硬件设备的通讯方式采用的是BLE低功耗蓝牙,低功耗蓝牙与传统用蓝牙的区别现在不做赘述,BLE在Android4.3以上系统开始提供支持,且目前大部分的蓝牙通讯模式采用的都是低功耗蓝牙,下面是我再开发中了解到额一些知识,在这里做基础总结,如果有不对和欠妥的地方请指正。原谅小弟的学疏才浅

 

 

1、权限声明

特别注意蓝牙搜索需要位置权限

<!--声明蓝牙权限-->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

1 获取蓝牙是适配器

蓝牙适配器 BluetoothAdapter在此可以看做是搜索蓝牙设备的工具获得方式:


BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();


3开始搜索蓝牙设备

设计到一个搜索回调


BluetoothAdapter.LeScanCallback leScanCallback;
 
 
 
//蓝牙连接返回的对象
BluetoothGatt bluetoothGatt;
 
//搜索回调
leScanCallback = new BluetoothAdapter.LeScanCallback() {
  @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
  @Override
  public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
   //停止搜索到条件 比如我们搜索到名字叫xx的设备就停止搜索
    if (!TextUtils.isEmpty(device.getName()) && "xx".equals(device.getName().trim())) {
      if (adapter.isDiscovering()) {
        adapter.stopLeScan(leScanCallback);
      }
//蓝牙连接
      bluetoothGatt = device.connectGatt(ConnectActivivty.this, false, bluetoothGattCallback);
    }
  }
};


 

BluetoothGatt 是个非常重要的类,它由蓝牙连接成功后返回,连接成功的后得读写操作都要靠他来完成,所以一般把他定义成全局变量

我们连接获取BluetoothGatt 之后就要进行服务端连接,我在这里是这么认为的,蓝牙设备连接成功之后现在还不能进行通讯,BluetoothGatt 下包含很多服务也就是 BluetoothGattService,而每个BluetoothGattService下面又有很多蓝牙通道BluetoothGattCharacteristic,我们只有确定了蓝牙传输通道,在这个通道内才可以进行通讯。

上面的


bluetoothGattCallback就是设备连接时候要设置的回调


//连接的回调
    bluetoothGattCallback = new BluetoothGattCallback() {
      @Override
      public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
          if (newState == BluetoothProfile.STATE_CONNECTED) {
            //这里是子线程你不要做UI操作,否侧程序无法继续执行
            //连接成功
            //Toast.makeText(ConnectActivivty.this, "连接成功", Toast.LENGTH_LONG).show();
            //去发现服务
            bluetoothGatt.discoverServices();

          }
      }

   //发现服务
      @Override
      public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        super.onServicesDiscovered(gatt, status);
//我们通过服务id来获取唯一服务,这个一般由硬件厂商指定,当然它也有一个默认值
        BluetoothGattService bluetoothGattService = bluetoothGatt.getService(UUID.fromString("00001000-0000-1000-8000-00805f9b34fb"));
//我们通过特征(也就是我们说的通道)id来获取唯一读取特征,这个一般由硬件厂商指定,当然它也有一个默认值
        BluetoothGattCharacteristic characteristic = bluetoothGattService.getCharacteristic(UUID.fromString("00001002-0000-1000-8000-00805f9b34fb"));
拿到通道后我们设置监听此通道
        gatt.setCharacteristicNotification(characteristic, true);
      }

      @Override
      public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicRead(gatt, characteristic, status);
        Log.e("hhh", new String(characteristic.getValue()));
      }

      @Override
      public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
      }


//特征值发生变化,我们认为有新的消息发来
      @Override
      public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
        super.onCharacteristicChanged(gatt, characteristic);
        Log.e("hhh", new String(characteristic.getValue()));
      }

      @Override
      public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorRead(gatt, descriptor, status);
      }

      @Override
      public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        super.onDescriptorWrite(gatt, descriptor, status);
      }

      @Override
      public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
        super.onReliableWriteCompleted(gatt, status);
      }

      @Override
      public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        super.onReadRemoteRssi(gatt, rssi, status);
      }

      @Override
      public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
        super.onMtuChanged(gatt, mtu, status);
      }
    };


 

 

以下是在真正进入蓝牙连接之前索要做的零基础判断,包括是否支持BLE,蓝牙和定位是否开启,权限是否开启


if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
      ToastUtils.showShort("您的手机不支持此功能");
      return;
    }
    boolean isBlueToothEnable = isBlueToothEnable();
    boolean isLocalEnable = isLocationEnabled();
    if (!isBlueToothEnable && isLocalEnable) {
      ToastUtils.showShort("请打开蓝牙功能");
      return;
    }
    if (isBlueToothEnable && !isLocalEnable) {
      ToastUtils.showShort("请打开定位功能");
      return;
    }
    if (!isBlueToothEnable && !isLocalEnable) {
      ToastUtils.showShort("请打开蓝牙和定位功能");
      return;
    }

      XXPermissions.with(ChooseCheckItemActivity.this)
        .constantRequest()
        .permission(new ArrayList(){{
          add(Manifest.permission.ACCESS_COARSE_LOCATION);
          add(Manifest.permission.BLUETOOTH);
          add(Manifest.permission.ACCESS_FINE_LOCATION);
          add(Manifest.permission.BLUETOOTH_ADMIN);}})
        .request(new OnPermission() {
          @Override
          public void hasPermission(List<String> granted, boolean isAll) {
            if (isAll) {
              if (ChooseCheckItemActivity.this != null) {
                //前往蓝牙连接
                Intent intent = new Intent(ChooseCheckItemActivity.this, CheckBloodActivity.class);   
                startActivity(intent);
                finish();
              }
              ALog.dTag("", "获取权限成功");
            } else {
              ALog.dTag("", "获取权限成功,部分权限未正常授予");
            }
          }

          @Override
          public void noPermission(List<String> denied, boolean quick) {
            if (quick) {
              ALog.dTag("", "被永久拒绝授权,请手动授予权限");
              //如果是被永久拒绝就跳转到应用权限系统设置页面
              XXPermissions.gotoPermissionSettings(ChooseCheckItemActivity.this);
            } else {
              ALog.dTag("", "获取权限失败");
            }
          }
        });
  }
});

//蓝牙是否打开
  public boolean isBlueToothEnable() {
     BluetoothAdapter mBluetoothAdapter = BluetoothAdapter
      .getDefaultAdapter();
    if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
      return true;
    }
    return false;
  }

  //定位手机定位功能是否打开
  public boolean isLocationEnabled() {
    int locationMode = 0;
    String locationProviders;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
      try {
        locationMode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE);
      } catch (Settings.SettingNotFoundException e) {
        e.printStackTrace();
        return false;
      }
      return locationMode != Settings.Secure.LOCATION_MODE_OFF;
    } else {
      locationProviders = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
      return !TextUtils.isEmpty(locationProviders);
    }
  }