在BLE协议中有两个角色,一个是周边(Periphery),另外一个是中央(Central)。一个中央可以同时连接多个周边,但一个周边某一时刻只能连接一个中央。但是不管periphery还是central都是可以实现GATT server和GATT client去传输数据,但是无法同时都是。

  先来讲一下相关术语和概念:

  GATT:Generic Attribute Profile,GATT配置文件是一个通用的规范,用于在BLE链路上发送和接收被称为"属性"的数据块。目前所有的BLE应用都基于GATT。 蓝牙SIG规定了许多低功耗设备的配置文件。配置文件是设备如何在特定的应用程序中工作的规格说明。注意一个设备可以实现多个配置文件。例如,一个设备可能包括心率监测仪和电量检测。

  ATT:Attribute Protocol,GATT在ATT协议基础上建立,也被称为GATT/ATT。ATT对在BLE设备上运行进行了优化,为此,它使用了尽可能少的字节。每个属性通过一个唯一的的统一标识符(UUID)来标识,每个String类型UUID使用bit标准格式。属性通过ATT被格式化为characteristics和services。

  Characteristic:一个characteristic包括一个单一的value(变量)和0-n个用来描述characteristic变量的descriptor,characteristic可以被认为是一个类型,类似于类

  Descriptor:用来描述characteristic变量的属性。例如。一二descriptor可以规定一个可读的描述,或者一个characteristic变量可接受的范围,或者一个characteristic变量特定的测量单位

  Service:是characteristic的集合。例如,你可能有一个叫“Heart Rate Monitor(心率监测仪)”的service,它包括了很多characteristics,如“heart rate measurement(心率测量)”等。你可以在bluetooth.org 找到一个目前支持的基于GATT的配置文件和服务列表。

  以下是Android设备与BLE设备交互时的角色和责任:

    中央 vs 外围设备。 适用于BLE连接本身。中央设备扫描,寻找广播;外围设备发出广播。

    GATT服务端 vs GATT客户端。决定了两个设备在建立连接后如何互相交流。

  系统权限

  <uses-permission android:name="android.permission.BLUETOOTH"/> 使用这个权限去执行蓝牙通讯,如请求连接,接受连接和传输数据。

  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>使用这个权限让你的app启用设备发现或者操纵蓝牙设置。
  <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>声明你的app只为具有BLE的设备提供。
  但是如果想让你的app提供给那些不支持BLE的设备,需要在manifest中包括上面代码并设置required="false",然后在运行时可以通过使用PackageManager.hasSystemFeature()确定BLE的可用性。
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
  Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
  finish();
}
  设置BLE
  如果设备支持BLE但是被禁用的话,你可以无需离开程序而要求用户启用蓝牙:
1、获取BluetoothAdapter
所有的蓝牙活动都需要蓝牙适配器。整个系统只有一个蓝牙适配器,而且你的app使用它与系统交互。

BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter= bluetoothManager.getAdapter();

2、开启蓝牙

你需要确认蓝牙是否开启。调用isEnabled()去检测蓝牙当前是否开启。如果该方法返回false,则蓝牙被禁用,需要显示错误提示用户去设置开启蓝牙

if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {

  Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
 
  发现BLE设备
为了发现BLE设备,使用startLeScan()方法,这个方法需要一个参数BluetoothAdapter.LeScanCallback。你必须实现他的回调函数,那就是返回的扫描结果。因为扫描非常耗电,所以应当准守一下准则:
1、找到所需设备,立即停止扫描
2、不要在循环里面扫描,并且对扫描设置时间限制。以前可用的设备可能已经移出范围,继续扫描消耗电池电量

private BluetoothAdapter mBluetoothAdapter;
private Boolean mScanning;
private Handler mHandler;

private static final Long SCAN_PERIOD = 10000L;

private LeScanCallback mLeScanCallback = new LeScanCallback() {
  @Override
  public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
    Log.i("TAG", device.toString());
  }
};

public void scanLeDevice(final boolean enable) {
  if (enable) {
    mHandler.postDelayed(new Runnable() {
      @Override
      public void run() {
        mScanning = false;
        mBluetoothAdapter.stopLeScan(mLeScanCallback);
      }
    }, SCAN_PERIOD);
    mScanning = true;
    mBluetoothAdapter.startLeScan(mLeScanCallback);
  } else {
    mScanning = false;
    mBluetoothAdapter.stopLeScan(mLeScanCallback);
  }
}

如果你只想扫描指定类型的外围设备,可以改为调用startLeScan(UUID[], BluetoothAdapter.LeScanCallback)),需要提供你的app支持的GATT services的UUID对象数组。

注意:只能扫描BLE设备或者扫描传统蓝牙设备,不能同时扫描BLE和传统蓝牙设备。

  连接到GATT服务端

与一个BLE设备交互的第一步就是连接它,也就是连接BLE设备上的GATT服务端:

  mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

第一个参数是Context对象,第二个是自动连接(表示BLE设备可用是否自动连接到它),第三个是BluetoothGattCallback调用。连接到GATT服务端时,由BLE设备做主机,并返回一个BluetoothGatt实例,然后你可以使用这个实例来进行GATT客户端操作

   读取BLE变量
uuid = gattService.getUuid().toString();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
uuid = gattCharacteristic.getUuid().toString();
  接收GATT通知
当设备上的特性发生改变时候会通知BLE应用程序。这段代码显示了如何使用setCharacteristication()给一个特性设置通知:
mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
如果对一个特性启用通知,当远程蓝牙设备特性发送变化,回调函数onCharacteristicChanged( )被触发。
  关闭客户端APP
当你的app完成BLE设备的使用后,应该调用close(),系统可以合理释放占用的资源
public void close() {
  if (null == mBluetoothGatt) {
    return;
  }
  mBluetoothGatt.close();
  mBluetoothGatt = null;
}

蓝牙4.0 BLE入门的更多相关文章

  1. Android 蓝牙4.0 BLE

    Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用. BLE是蓝牙4.0的核心Profil ...

  2. IOS学习之蓝牙4.0 BLE

    IOS学习也一段时间了,该上点干货了.前段时间研究了一下IOS蓝牙通讯相关的东西,把研究的一个成果给大家分享一下. 一 项目背景 简单介绍一下做的东西,设备是一个金融刷卡器,通过蓝牙与iphone手机 ...

  3. Android项目实战(三十四):蓝牙4.0 BLE 多设备连接

    最近项目有个需求,手机设备连接多个蓝牙4.0 设备 并获取这些设备的数据. 查询了很多资料终于实现,现进行总结. ------------------------------------------- ...

  4. Android 蓝牙4.0 BLE (onServicesDiscovered 返回 status 是 129,133时)

    Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说android 4.3+, API level >= 18,且支持蓝牙4.0的手机才可以使用. BLE是 ...

  5. android蓝牙4.0(BLE)开发之ibeacon初步

    一个april beacon里携带的信息如下 ? 1 <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC ...

  6. 蓝牙4.0 BLE 广播包解析

    在使用EN-Dongle捕获和解析广播包之前,我们先了解一下BLE报文的结构,之后,再对捕获的广播包进行分析.在学习BLE的时候,下面两个文档是极其重要的,这是SIG发布的蓝牙的核心协议和核心协议增补 ...

  7. 蓝牙BLE: 蓝牙4.0 BLE广播数据解析(转)

    BLE 设备工作的第一步就是向外广播数据.广播数据中带有设备相关的信息.本文主要说一下 BLE 的广播中的数据的规范以及广播包的解析. 1. 广播模式 BLE 中有两种角色 Central 和 Per ...

  8. 蓝牙4.0 BLE 开发

    在BLE开发中的一些随记,供大家参考: 凡事皆有状态 低功耗蓝牙背后有个基本的概念:任何事务都有状态.状态可以是任何东西:当前的温度,设备里电池的状态,设备名称或者对测量温度的地点的描述.它通过属性服 ...

  9. 蓝牙4.0 BLE基础之vdd检测new

    外部ADC通道,我们现在用的是A0脚,也就是P00通道 把它设置成输出的一个模式.在程序中设置,代码如下: #include <ioCC2540.h> #define HAL_ADC_RE ...

随机推荐

  1. pycharm 修改新建文件时的头部模板

    pycharm 修改新建文件时的头部模板 默认为__author__='...' [省略号是默认你的计算机名] 修改这个作者名的步骤: 依次点击:File->Settings->Edito ...

  2. mysql索引利弊分析

    转载自:http://blog.csdn.net/linminqin/article/details/44342205  索引的利弊与如何判定,是否需要索引 相信读者都知道索引能够极大地提高数据检索的 ...

  3. Windows Server 2008 R2 安装WinDbg以及符号路径设置

    1.下载WinDbg安装包(Debuggers And Tools-x64_en-us v6.12.0002.633 AMD64.msi),双击安装 2.从网站http://msdn.microsof ...

  4. 计算机网络【9】—— HTTP1.0和HTTP1.1的区别及常见状态码

    一.HTTP1.0与HTTP1.1的区别 1.HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理 HTTP 1.0规定浏览器与服务器只保持 ...

  5. python3+selenium 牛刀小试

    # coding:utf-8 # __author__ = 'Carry' import unittest from selenium import webdriver import time cla ...

  6. 【uoj#280】[UTR #2]题目难度提升 对顶堆+STL-set

    题目描述 给出 $n$ 个数 $a_1,a_2,...,a_n$ ,将其排为序列 $\{p_i\}$ ,满足 $\{前\ i\ 个数的中位数\}$ 单调不降.求字典序最大的 $\{p_i\}$ . 其 ...

  7. 【转】Latex编译报错后中断编译并改正,然后重复出现不明原因报错的解决方法

    转自:https://www.douban.com/note/419828344/ 目录: 一.问题描述 二.测试情况(可以跳过,直接看建议) 三.建议 四.参考资料 正文: 问题描述: 错漏某个符号 ...

  8. linux 批量更改文件名 rename 命令

    rename 的典型应用: # rename $1 $2 $3# $1: 要被取代的關鍵字# $2: 新的關鍵字# $3: 檔名符合這個規則的才取代 # 把 IMG001.jpg, IMG002.jp ...

  9. 【BZOJ3534】重建(矩阵树定理)

    [BZOJ3534]重建(矩阵树定理) 题面 BZOJ 洛谷 题解 这.... 矩阵树定理神仙用法???? #include<iostream> #include<cmath> ...

  10. 【NOI2015】寿司晚宴

    题目链接:http://uoj.ac/problem/129 描述 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴. ...