当前位置: 首页 > 操作系统 > 手机系统 > 正文

Android 5.0中的蓝牙BLE

时间:2016-08-31 csdn博客 chy555chy

一、蓝牙BLE(Bluetooth Low Energy)介绍概要

蓝牙低能耗(BLE)技术是低成本、短距离、可互操作的鲁棒性无线技术,工作在免许可的2.4GHz ISM射频频段。它从一开始就设计为超低功耗(ULP)无线技术。

蓝牙低能耗技术的三大特性成就了ULP性能,这三大特性分别是最大化的待机时间、快速连接和低峰值的发送/接收功耗。

无线“开启”的时间只要不是很短就会令电池寿命急剧降低,因此任何必需的发送或接收任务需要很快完成。被蓝牙低能耗技术用来最小化无线开启时间的第一个技巧是仅用3个“广告”信道搜索其它设备,或向寻求建立连接的设备宣告自身存在。相比之下,标准蓝牙技术使用了32个信道。

蓝牙低能耗技术“完成”一次连接(即扫描其它设备、建立链路、发送数据、认证和适当地结束)只需3ms。而标准蓝牙技术完成相同的连接周期需要数百毫秒。再次提醒,无线开启时间越长,消耗的电池能量就越多。

二、关键概念:

(1)Generic Attribute Profile (GATT)

通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。

(2)Attribute Protocol (ATT)

GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。

(3)Characteristic

Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。

(4)Descriptor

对Characteristic的描述,例如范围、计量单位等。

(5)Service

Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。

三、相关权限

<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 允许程序进行发现和配对新的蓝牙设备 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
public class BluetoothBleDemo extends Activity {
    private static final int REQUEST_CODE_BLUETOOTH_ENABLE = 1;
    private static final int SCAN_PERIOD = 10000;

    private BluetoothAdapter bluetoothAdapter;
    //import android.bluetooth.le.ScanCallback;
    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            //Batch 一批
        }

        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            switch(callbackType) {
                case ScanSettings.CALLBACK_TYPE_ALL_MATCHES:
                    break;
                case ScanSettings.CALLBACK_TYPE_FIRST_MATCH:
                    break;
                case ScanSettings.CALLBACK_TYPE_MATCH_LOST:
                    break;
            }

            BluetoothDevice device = result.getDevice();
            String deviceName = device.getName();
            String deviceAddress = device.getAddress();
            int deviceType = device.getType();
            ParcelUuid[] deviceUuids = device.getUuids();
            int deviceBondState = device.getBondState();

            ScanRecord scanRecord = result.getScanRecord();
            int advertiseFlags = scanRecord.getAdvertiseFlags();
            //txPowerLevel 发射功率等级
			//URL:http://www.bianceng.cn/OS/extra/201608/50410.htm
            int txPowerLevel = scanRecord.getTxPowerLevel();
            String recordDeviceName = scanRecord.getDeviceName();
            List<ParcelUuid> serviceUuids = scanRecord.getServiceUuids();
            Map<ParcelUuid, byte[]> serviceData = scanRecord.getServiceData();

            //RSSI 信号强度,可以用来测算距离
            int rssi = result.getRssi();
            long timestampNanos = result.getTimestampNanos();
        }

        @Override
        public void onScanFailed(int errorCode) {

        }
    };
    private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
        }

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

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

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

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

        @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 onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }

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

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }
    };
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //判断是否支持BLE特性
        if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            initBluetoothBle();
        } else {
            showToast("this device can not support Bluetooth BLE");
        }
    }

    private void initBluetoothBle() {
        //BluetoothAdapter是Android系统中所有蓝牙操作都需要的,它对应本地Android设备的蓝牙模块,在整个系统中BluetoothAdapter是单例的。当你获取到它的示例之后,就能进行相关的蓝牙操作了。
        //BluetoothManager在Android4.3以上支持(API level 18)
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
    }

    /**
     * 开启蓝牙
     * 打开和关闭蓝牙模块, 都可以通过ACTION_STATE_CHANGED广播来监听
     */
    private void requestEnable() {
        //第一种方法打开蓝牙, 没有任何提示, 直接就打开了
        //boolean result = bluetoothAdapter.enable();
        //第二种方法发送广播, 会弹出一个对话框, 选择是否打开蓝牙, 选择是蓝牙才打开;
        if(bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, REQUEST_CODE_BLUETOOTH_ENABLE);
        }
    }

    /**
     * 扫描BLE设备.注意该方法无法扫描标准蓝牙,只能扫描BLE设备
     */
    private void scanBleDevice(final boolean enabled) {
        if(bluetoothAdapter == null) {
            return;
        }
        /*
        为什么不能再使用单例的BluetoothAdapter? 原因如下:
        bluetoothAdapter.startLeScan() //deprecated
        http://stackoverflow.com/questions/30223071/startlescan-replacement-to-current-api
        Remember that the method: public BluetoothLeScanner getBluetoothLeScanner () isn't static.
        If you do: BluetoothAdapter.getBluetoothLeScanner()
        you will get an error, since getDefaultAdapter() is a static method, but getBluetoothLeScanner() isn't.
        You need an instance of a BluetoothAdapter.
         */
        final BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
        if(enabled) {
            //scan分为2类,而在android L之前,搜索条件只有uuid
            //(1)直接搜索全部周围peripheral(外围的)设备,搜索结果将通过这个callback返回
            scanner.startScan(scanCallback);
            //(2)根据过滤条件搜索设备
            final List<ScanFilter> scanFilters = new ArrayList<ScanFilter>();
            //uuid格式8-4-4-4-12(32位,128bit)
            //address格式(12位,48bit)
            scanFilters.add(new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("00000000-0000-0000-0000-000000000000")).setDeviceAddress("00:00:00:00:00:00").build());
            ScanSettings scanSettings = new ScanSettings.Builder()
                    //require API 23
                    //.setCallbackType(0).setMatchMode(0).setNumOfMatches(0)
                    .setReportDelay(0).setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE).build();
            scanner.startScan(scanFilters, scanSettings, scanCallback);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scanner.stopScan(scanCallback);
                }
            }, SCAN_PERIOD);
        } else {
            scanner.stopScan(scanCallback);
        }
    }

    /**
     * 两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。数据发送方向总是从server推送到client
     */
    private void connectToGATTServer(BluetoothDevice device) {
        //函数成功,返回BluetoothGatt对象,它是GATT profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。
        BluetoothGatt bluetoothGatt = device.connectGatt(this, false, gattCallback);

        //连接远程设备
        boolean connectResult = bluetoothGatt.connect();
        //搜索连接设备所支持的service
        boolean discoverResult = bluetoothGatt.discoverServices();
        //断开与远程设备的GATT连接
        bluetoothGatt.disconnect();
        //关闭GATT Client端
        bluetoothGatt.close();
        //读取指定的characteristic。
        //boolean readResult = bluetoothGatt.readCharacteristic(characteristic);
        //设置当指定characteristic值变化时,发出通知
        //boolean setResult = bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        //获取远程设备所支持的services
        List<BluetoothGattService> gattServices = bluetoothGatt.getServices();
    }

    private void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
    
}