乐趣区

关于android:Android-的BLE蓝牙开发

Android 的 BLE 蓝牙开发

一: 定义
传统蓝牙实用于电池应用强度较大的操作,例如 Android 设施之间的流传输和通信等。针对具备低功耗要求的蓝牙设施,Android 4.3(API 18)中引入了面向低功耗蓝牙的 API 反对
应用程序通过这些 API 扫描蓝牙设施、查问 services、读写设施的 characteristics(属性特色)等操作。
Android BLE 应用的蓝牙协定是 GATT 协定

二:Android BLE API 简介
1.BluetoothAdapter
BluetoothAdapter 领有根本的蓝牙操作,例如开启蓝牙扫描,应用已知的 MAC 地址(BluetoothAdapter#getRemoteDevice)实例化一个 BluetoothDevice 用于连贯蓝牙设施的操作等等。
2.BluetoothDevice
代表一个近程蓝牙设施。这个类能够让你连贯所代表的蓝牙设施或者获取一些无关它的信息,例如它的名字,地址和绑定状态等等。
3.BluetoothGatt
这个类提供了 Bluetooth GATT 的基本功能。例如从新连贯蓝牙设施,发现蓝牙设施的 Service 等等。
4.BluetoothGattService
这一个类通过 BluetoothGatt#getService 取得,如果以后服务不可见那么将返回一个 null。这一个类对应下面说过的 Service。咱们能够通过这个类的 getCharacteristic(UUID uuid) 进一步获取 Characteristic 实现蓝牙数据的双向传输。
5.BluetoothGattCharacteristic
这个类对应下面提到的 Characteristic。通过这个类定义须要往外围设备写入的数据和读取外围设备发送过去的数据。

三:Android 蓝牙开发示例
第一步:增加权限

 <!-- 蓝牙连贯权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <!-- 蓝牙通信权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <!-- 地位信息  获取精准地位 -->
    <!--Android 6.0 及后续版本,应用蓝牙扫描,还须要增加如下的权限,且该权限还须要在应用时动静申请 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

第二步:连贯蓝牙前的初始化工作
在建设蓝牙连贯之前,须要确认设施反对 BLE。如果反对,再确认蓝牙是否开启。如果蓝牙没有开启,能够应用 BLuetoothAdapter 类来开启蓝牙。
1. 获取 BluetoothAdapter

 private BluetoothAdapter mBluetoothAdapter;
  /**
     * 初始化蓝牙配置
     */
    private void initBlueTooth() {bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 获取蓝牙适配器
 
 }

获取蓝牙适配器的形式二:

private BluetoothAdapter bluetoothAdapter;
...
final BluetoothManager bluetoothManager =
        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
   // 通过蓝牙管理器来获取适配器     
bluetoothAdapter = bluetoothManager.getAdapter();

BluetoothAdapter 代表本地设施的蓝牙适配器。该 BluetoothAdapter 能够执行根本的蓝牙工作,例如启
动设施发现,查问配对的设施列表,应用已知的 MAC 地址实例化一个 BluetoothDevice 类,并创立一个
BluetoothServerSocket 监听来自其余设施的连贯申请。
查看源码:

public final class BluetoothAdapter {
// 获取蓝牙的适配器
public static synchronized BluetoothAdapter getDefaultAdapter() {}
  // 传入地址获取蓝牙的设施
public BluetoothDevice getRemoteDevice(String address){}
  
  // 获取蓝牙的状态
public int getState() {}
// 蓝牙是否可用
public boolean isEnabled() {}
    
// 获取本机蓝牙名称
public String getName() {}
     
// 获取本机蓝牙地址
public String getAddress() {}
  // 开始扫描搜寻    
public boolean startDiscovery() {}
 // 进行扫描搜寻
public boolean cancelDiscovery() {}
       
// 获取已配对蓝牙设施  
public Set<BluetoothDevice> getBondedDevices() {}
// 开启蓝牙扫描
 public boolean startLeScan(LeScanCallback callback) {return startLeScan(null, callback);
    }
   // 在 BluetoothAdapter 中,咱们能够看到有两个扫描蓝牙的办法。第一个办法能够指定只扫描含有特定 UUID Service 的蓝牙设施,第二个办法则是扫描全副蓝牙设施。public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {}
等性能

2. 如果检测到蓝牙没有开启,尝试开启蓝牙

 if (bluetoothAdapter != null) {// 是否反对蓝牙
                if (bluetoothAdapter.isEnabled()) {// 关上
                    // 开始扫描四周的蓝牙设施, 如果扫描到蓝牙设施,通过播送接收器发送播送
                    if (mAdapter != null) {// 当适配器不为空时,这时就阐明曾经有数据了,所以革除列表数据,再进行扫描
                        list.clear();
                        mAdapter.notifyDataSetChanged();}
                    bluetoothAdapter.startDiscovery();} else {// 未关上
                    Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                    startActivityForResult(intent, REQUEST_ENABLE_BLUETOOTH);
                }
            } else {showMsg("你的设施不反对蓝牙");
            }

监听搜寻设施:
咱们能够自定义一个播送接管这些零碎播送
通过播送接收者查看扫描到的蓝牙设施,每扫描到一个设施,零碎都会发送此播送(BluetoothDevice.ACTION_FOUND)。其中参数 intent 能够获取蓝牙设施 BluetoothDevice。

 private class BluetoothReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {String action = intent.getAction();
            switch (action) {
                case BluetoothDevice.ACTION_FOUND:// 扫描到设施
                    showDevicesData(context, intent);// 数据展现
                    break;
                case BluetoothDevice.ACTION_BOND_STATE_CHANGED:// 设施绑定状态产生扭转
                    mAdapter.changeBondDevice();// 刷新适配器
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_STARTED:// 开始扫描
                    loadingLay.setVisibility(View.VISIBLE);// 显示加载布局
                    break;
                case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:// 扫描完结
                    loadingLay.setVisibility(View.GONE);// 暗藏加载布局
                    break;
            }
        }

创立一个监听者播送监听者

  private void initBlueTooth() {IntentFilter intentFilter = new IntentFilter();// 创立一个 IntentFilter 对象
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);// 取得扫描后果
        intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);// 绑定状态变动
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);// 开始扫描
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 扫描完结
        bluetoothReceiver = new BluetoothReceiver();// 实例化播送接收器
        registerReceiver(bluetoothReceiver, intentFilter);// 注册播送接收器
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 获取蓝牙适配器}

BluetoothDevice 代表一个近程蓝牙设施。让你创立一个带有各自设施的 BluetoothDevice 或者查问其皆如名称、地址、类和连贯状态等信息。
源码:

public final class BluetoothDevice implements Parcelable {public void writeToParcel(Parcel out, int flags) {out.writeString(mAddress);
    }
 public String getAddress() {}
   public String getName() {}
}

第三步:扫描蓝牙设施
外围设备开启蓝牙后,会播送出许多的对于该设施的数据信息,例如 mac 地址,uuid 等等。通过这些数据咱们能够筛选出须要的设施。

在 BluetoothAdapter 中,咱们能够看到有两个扫描蓝牙的办法。第一个办法能够指定只扫描含有特定 UUID Service 的蓝牙设施,第二个办法则是扫描全副蓝牙设施。

 public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback){}
  public boolean startLeScan(LeScanCallback callback) {return startLeScan(null, callback);
    }
    // 进行蓝牙扫描
     public void stopLeScan(LeScanCallback callback) {}

实现 LeScanCallback 回调

private LeDeviceListAdapter leDeviceListAdapter;
...
// Device scan callback.
private BluetoothAdapter.LeScanCallback leScanCallback =
        new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi,
            byte[] scanRecord) {runOnUiThread(new Runnable() {
           @Override
           public void run() {leDeviceListAdapter.addDevice(device);
               leDeviceListAdapter.notifyDataSetChanged();}
       });
   }
};


// 开启扫描
mBluetoothAdapter.startLeScan(callback);

总结:
形式一:startLeScan()办法
startLeScan()办法有一个回调参数 BluetoothAdapter.LeScanCallback 类,先创立这个类的对象,在扫描找到四周的蓝牙设施时,会返回到 onLeScan 函数,能够在 onLeScan 函数中解决逻辑
startLeScan()办法的特点:在 onLeScan() 中不能做耗时操作,特地是四周的 BLE 设施多的时候,容易导致底层梗塞
形式二:startDiscovery()办法
这个办法用到播送。
所以先定义一个类 BluetoothReceiver,让他继承自 BroadcastReceiver , 并重写 onReceive()办法,在该办法中写扫描到设施时的逻辑。
而后创立 BluetoothReceiver 对象,注册播送,再执行 startDiscovery()办法
对于经典蓝牙设施,扫描是通过调用 startDiscovery 接口,返回的后果是通过 BroadcastReceiver 接管的,能够获取设施 MAC 地址,名称以及 RSSI。startDiscovery 是个异步调用,会立刻返回。如果不调用 cancelDiscovery 被动进行扫描的话,最多扫描 12s。播送次要监听以下几个 Action:BluetoothDevice.ACTION_FOUNDBluetoothAdapter.ACTION_DISCOVERY_STARTEDBluetoothAdapter.ACTION_DISCOVERY_FINISHED 另外要留神 startDiscovery 返回的设施不包含已配对设施,如要获取已配对设施,须要额定调用 getBondedDevices。

第四步:连贯到 GATT 服务器,连贯蓝牙设施
与 BLE 设施交互的第一步便是连贯到 GATT 服务器。更具体地说,是连贯到设施上的 GATT 服务器。如要连贯到 BLE 设施上的 GATT 服务器,请应用 connectGatt() 办法。此办法采纳三个参数:一个 Context 对象、autoConnect(布尔值,批示是否在可用时主动连贯到 BLE 设施),以及对 BluetoothGattCallback 的援用:

BluetoothGatt   connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)

第二个参数示意是否须要主动连贯。如果设置为 true, 示意如果设施断开了,会一直的尝试主动连贯。设置为 false 示意只进行一次连贯尝试。
第三个参数是连贯后进行的一系列操作的回调,例如连贯和断开连接的回调,发现服务的回调,胜利写入数据,胜利读取数据的回调等等。

END: 锲而舍之,朽木不折;持之以恒,金石可镂

退出移动版