android BLE 编程详解

来源:互联网 发布:淘宝卖家支付宝在哪里 编辑:程序博客网 时间:2024/05/16 19:06

最近可穿戴设备发展的很火,而且蓝牙4.0 以上支持低功耗模式,因此,android4.3(API18)以上支持蓝牙BLE编程。BLE是蓝牙4.0的核心Profile,主打功能是快速搜索,快速连接,超低功耗保持连接和传输数据,弱点是数据传输速率低,由于BLE的低功耗特点,因此普遍用于穿戴设备。下面介绍android 的BLE开发。

1.   基本概念介绍

  • BluetoothManager :管理蓝牙服务的一个类,主要用于得到一个蓝牙适配器BluetoothAdapter。
  • BluetoothAdapter类:代表了一个本地的蓝牙适配器。它是所有蓝牙交互的的入口点。利用它你可以发现其他蓝牙设备,查询绑定了的设备,使用已知的MAC地址实例化一个蓝牙设备和建立一个BluetoothServerSocket(作为服务器端)来监听来自其他设备的连接。 
  • BluetoothDevice类:代表了一个远端的蓝牙设备,使用它请求远端蓝牙设备连接或者获取远端蓝牙设备的名称、地址、种类和绑定状态。
  • BluetoothGatt类:符合BLE GATT协议,封装了与其他蓝牙设备通信功能的一个类。可以通过BluetoothDevice的connectGatt(Context, boolean, BluetoothGattCallback)得到其实例。
  • GATT(Generic Attribute Profile) 通用属性参数文件,通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。蓝牙 4.0特有。可以理解为一个规范文件。
  • ATT(Attribute Protocol) 属性协议。GATT是基于ATTProtocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics 和services的形式传输。
  • Service 服务。Characteristic的集合。例如一个service叫做“Heart RateMonitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic
  • Characteristic 特性。Characteristic可以理解为一个数据类型,它包括1个value和0至多个Descriptor
  • Descriptor 对Characteristic的描述,例如范围、计量单位等,一个Descriptor包含一个Value

其中Service、Characteristic、Descriptor,这三部分是BLE的核心,都由UUID作为唯一标示符。一般来说,Characteristic是手机与BLE终端交换数据的关键,Characteristic有较多的跟权限相关的字段,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY。

 

2.   BLE编程

1.      权限配置

由于android4.3及以上才支持BLE,因此需指定编译版本为targetSdkVersion大于等于18。并且需要在AndroidManifest.xml文件中配置如下所示的权限

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

2.      编程步骤

1.获取BluetoothManager服务及BluetoothAdapter实例

BluetoothManager是系统管理蓝牙的一种服务,获取了BluetoothManager我们就可以通过其getAdapter()获取蓝牙适配器了。

       //1.获取蓝牙管理服务及BluetoothAdapter实例       mBluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);       mBluetoothAdapter = mBluetoothManager.getAdapter();       if (mBluetoothAdapter == null){            return;       }

2.打开蓝牙

         接下来调用BluetoothAdapter的isEnabled()判断蓝牙是否打开,未打开我们可以发送一个action为BluetoothAdapter.ACTION_REQUEST_ENABLE的intent来打开蓝牙。

       //2. 判断蓝牙是否打开,没有打开就打开       if (!mBluetoothAdapter.isEnabled()){            Intent intent = newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);           startActivityForResult(intent,REQUEST_ENABLE_BT);       }

         这时界面上回弹出一个对话框提示我们打开蓝牙,打开成功后会回调Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法,我们可以在里面提示一些信息。比如提示蓝牙已经打开等。

   @Override   protected void onActivityResult(int requestCode, int resultCode, Intentdata) {       super.onActivityResult(requestCode, resultCode, data);        if (resultCode != RESULT_OK){            return;       }       if (requestCode == REQUEST_ENABLE_BT){            Toast.makeText(this,"蓝牙已开启",Toast.LENGTH_LONG).show();       }   }

        

3.扫描周围的BLE蓝牙设备

         扫描BLE蓝牙设备,对于4.3以上的系统,直接调用startLeScan(BluetoothAdapter.LeScanCallbackcallback)即可扫描出BLE设备,在callback中会回调。但是对于5.0以上的系统,android添加了新的API,原有的startLeScan(BluetoothAdapter.LeScanCallback callback)已经被废弃,在5.0以上的系统中是使用BluetoothLeScanner的startScan(ScanCallbackcallback),回调也是ScanCallback了。

    /**     * 扫描Bluetooth LE     * @param enable     */    private void scanBleDevice(boolean enable){        //android 5.0 以前        if (Build.VERSION.SDK_INT < 21){            if (enable){                mHandler.postDelayed(new Runnable() {                    @Override                    public void run() {                        mScaning = false;                        mBluetoothAdapter.stopLeScan(mLeScanCallback);                    }                },SCAN_SECOND);                mScaning = true;                mBluetoothAdapter.startLeScan(mLeScanCallback);            } else {                mScaning = false;                mBluetoothAdapter.stopLeScan(mLeScanCallback);            }        } else {            scanner = mBluetoothAdapter.getBluetoothLeScanner();            scanner.startScan(mScanCallback);            mHandler.postDelayed(new Runnable() {                @Override                public void run() {                    scanner.stopScan(mScanCallback);                }            },SCAN_SECOND);        }    }

 扫描的回调如下:

   //sacn扫描回调 5.0以上用   private ScanCallback mScanCallback = new ScanCallback() {       @Override       public void onScanResult(int callbackType, ScanResult result) {            BluetoothDevice device =result.getDevice();            if (device != null){                //过滤掉其他设备                if (device.getName() != null&& device.getName().startsWith("WINPOS")){                    BLEDevice bleDevice = newBLEDevice(device.getName(),device.getAddress());                    if(!mBLEDeviceList.contains(bleDevice)){                       mBLEDeviceList.add(bleDevice);                       showBluetoothLeDevice(bleDevice);                    }                }            }       }        @Override       public void onBatchScanResults(List<ScanResult> results) {            Log.d(TAG,"onBatchScanResults");       }        @Override       public void onScanFailed(int errorCode) {           Log.d(TAG,"onScanFailed");       }   };     //4.3以上   private BluetoothAdapter.LeScanCallback mLeScanCallback = newBluetoothAdapter.LeScanCallback() {       @Override       public void onLeScan(final BluetoothDevice bluetoothDevice, int i,byte[] bytes) {             if (bluetoothDevice != null){                //过滤掉其他设备                if (bluetoothDevice.getName()!= null && bluetoothDevice.getName().startsWith("WINPOS")){                    BLEDevice bleDevice = newBLEDevice(bluetoothDevice.getName(),bluetoothDevice.getAddress());                    if(!mBLEDeviceList.contains(bleDevice)){                       mBLEDeviceList.add(bleDevice);                       showBluetoothLeDevice(bleDevice);                    }                }            }       }   };

         这里我预先定义了BLEDevice类,用来表示BLE设备。定义如下:

public class BLEDevice {   private String name;   private String mac;   public BLEDevice(String name, String mac) {       this.name = name;       this.mac = mac;   }    public String getName() {       return name;   }    public void setName(String name) {       this.name = name;   }    public String getMac() {       return mac;   }    public void setMac(String mac) {       this.mac = mac;   }    @Override   public boolean equals(Object o) {        return !TextUtils.isEmpty(this.mac) &&!TextUtils.isEmpty(((BLEDevice)o).mac)                &&this.mac.equals(((BLEDevice) o).getMac());    }}

         扫描时我将扫描到的设备添加到List<BLEDevice> mBLEDeviceList中并显示出来。

   /**    * 显示BLE设备    * @param device    */   private void showBluetoothLeDevice(BLEDevice device){       if (device == null){            showToast("没有发现BLE设备");            return;       }       mTextView.append(device.getName() + "   " + device.getMac() + "\n");   }

4.获取远程设备,连接GATT服务




0 0