Android BLE开发

来源:互联网 发布:手机淘宝修改评价 编辑:程序博客网 时间:2024/06/06 14:06

蓝牙ble(Bluetooth Low Energy):蓝牙低能耗技术蓝牙4.0

适用范围:Android4.3之后才支持BLE;iOS7.0开始支持BLE,Swift语言需要iOS8.0以上,硬件要求iPhone4s以上(包含4s)

蓝牙通信关系:主从关系,每一对设备进行蓝牙通讯时,必须一个为中心设备central,另一个为从设备peripheral.通信时必须central进行查找,发起配对,连接成功后双方可收发数据.一个central可以最多同时连接7个从设进行通讯,一个peripheral只能连接一个central.

Android开发手机做central:

1 获取权限

//判断手机是否有硬件BLE模块

<uses-feature

        android:name="android.hardware.bluetooth_le"

        android:required="false" />

//获取权限

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

//允许程序连接到已配对的蓝牙设备

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

//允许程序发现和配对蓝牙设备

Android6.0蓝牙权限需要添加模糊定位权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

模糊定位是Dangerous Permission,涉及到用户隐私,使用时需要用户实时授权:

在代码中添加首次进入判断://动态运行时权限

 private void checkBluetoothPermission() {         if (Build.VERSION.SDK_INT >= 23) {             //校验是否已具有模糊定位权限             if (ContextCompat.checkSelfPermission(MainActivity.this,                     Manifest.permission.ACCESS_COARSE_LOCATION)                     != PackageManager.PERMISSION_GRANTED) {                 ActivityCompat.requestPermissions(MainActivity.this,                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},                         MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);             } else {             //具有权限             }         } else {             //系统不高于6.0直接执行         }     } @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        doNext(requestCode, grantResults);    }
2 初始化蓝牙外设

   获取到系统BluetoothManager:getSystemService(Context.BLUETOOTH_SERVICE)

   获取到蓝牙适配器:manager.getAdapter

   打开蓝牙:adapter.enable

     /**     * 初始化蓝牙外设     */    public boolean initialize() {        //判断手机是否配置蓝牙4.0        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {            Log.e(TAG, "initialize:不能初始化蓝牙,因为您的手机不适配蓝牙4.0,没有蓝牙模块 " );            return false;        }        //获取到蓝牙管理者        if (mBluetoothManager == null) {            mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);            if (mBluetoothManager == null) {                Log.e(TAG, "initialize:初始化蓝牙管理器失败 ");                return false;            }        }        //获取到蓝牙适配器        if(mBluetoothAdapter == null) {            mBluetoothAdapter = mBluetoothManager.getAdapter();            if (mBluetoothAdapter == null) {                Log.e(TAG, "initialize:初始化蓝牙适配器失败 " );                return false;            }        }        //打开手机蓝牙        if(mBluetoothAdapter == null) {            Log.e(TAG, "initialize:初始化蓝牙适配器失败 " );            return false;        } else {            //判断是否有蓝牙模块            boolean hasBle = mContext.getPackageManager().hasSystemFeature("android.hardware.bluetooth_le");            if (!hasBle) {                Log.e(TAG, "initialize:不能初始化蓝牙,因为您的手机不适配蓝牙4.0,没有蓝牙模块 ");                return false;            }            //打开手机蓝牙            mBluetoothAdapter.enable();            return true;        }    }
3  扫描外设,断开扫描

   蓝牙扫描外设Android:Android5.0(SDK21)之前 startLeScan ,stopLeScan,回调函数LeScanCallback

Android5.0之后版本:先获取到BluetoothLeScanner: mBluetoothAdapter.getBluetoothLeScanner();

扫描:mBluetoothLeScanner.startScan(mScanCallback), 停止扫描:mBluetoothLeScanner.stopScan(mScanCallback)

扫描结果回调函数:ScanCallback

 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)    private static class VersionA {        //扫描外设的回调函数        private static BluetoothAdapter.LeScanCallback mLeScanCallback =                new BluetoothAdapter.LeScanCallback() {                    @Override                    public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {                        Log.e(TAG, "onLeScan: 扫描一次" );                        mBleCallBack.deviceScanned(bluetoothDevice, i, bytes);                    }                };        public static void startLeScan() {            if (mBluetoothAdapter == null) {                Log.e(TAG, "startLeScan:开始扫描,适配器失败 ");                return;            }            mBluetoothAdapter.startLeScan(mLeScanCallback);        }        public static void stopLeScan() {            if (mBluetoothAdapter == null) {                Log.e(TAG, "stopLeScan:停止扫描,适配器失败 ");                return;            }            mBluetoothAdapter.stopLeScan(mLeScanCallback);        }    }    /**     * 5.0之后版本的外设扫描     */    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    private static class VersionB {        private static ScanCallback mScanCallback = new ScanCallback() {            @Override            public void onScanResult(int callbackType, ScanResult result) {                //if (isDevice(result.getScanRecord().getBytes())) {                    // TODO: 16/6/24 扫描回调函数                Log.e(TAG, "onScanResult: 扫描一次" );               // Log.d(TAG, "onScanResult: 扫描回调函数,回调一次"+result.getDevice().getAddress());                    mBleCallBack.deviceScanned(result.getDevice(), callbackType, result.getScanRecord().getBytes());               // }            }        };        public static void startScan() {            if (mBluetoothLeScanner == null) {                mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();            }            mBluetoothLeScanner.startScan(mScanCallback);        }        public static void stopScan() {            if (mBluetoothLeScanner != null) {                mBluetoothLeScanner.stopScan(mScanCallback);            }        }    }
3  连接设备:

手动连接设备,通过address连接

通过address获取到设备device:mBluetoothAdapter.getRemoteDevice(address);

创建连接,连接gatt通道:device.connectGatt(mContext, false, mGattCallback);

GATT:定义两个BLE设备通过Servicecharacteristic的东西进行通信,GATT连接是独占的,一个BLE外设同时只能被一个中心设备连接,一旦外设被连接就不再广播,这样它对其他设备不可见,设备断开时,它又开始广播.

GATT中

一个低功耗蓝牙(ble)可以包括多个Profile

一个Profile中有多个Service(通过uuid就可以找到对应的Service

一个Service中有多个Characteristic(通过uuid就可以找到对应的Characteristic

一个Characteristic中包括一个value和多个Descriptor(通过uuid就可以找到对应的Descriptor

 /**     * 手动连接设备,通过address连接     */    public boolean connect(final String address) {        currentDevice = null;        if (mBluetoothAdapter == null || address == null) {            Log.e(TAG, "connect: 蓝牙适配器初始化失败或者蓝牙外设地址为空");            return false;        }        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);        if (device == null) {            Log.e(TAG, "外设没有找到,连接失败");            return false;        }        currentDevice = device;        // 曾经连接上过,重新连接//        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)//                && mBluetoothGatt != null) {//            Log.e(TAG, "尝试连接一个曾经连接上的外设");//            mBluetoothGatt.close();//            if (mBluetoothGatt.connect()) {//                //已经连接上了,但是基于蓝牙协议,并没有连接上,手动扫描service从而实现连接//                mBluetoothGatt.discoverServices();//                return true;//            } else {//                return false;//            }//        }        if (mBluetoothGatt != null){            mBluetoothGatt.close();            mBluetoothGatt = null;        }        //连接设备        mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);        Log.e(TAG, "尝试创建一个新连接,连接外设Gatt新通道");        mBluetoothDeviceAddress = address;        if (mBluetoothGatt != null){            Log.e(TAG, "Gatt通道建立成功");        }else {            Log.e(TAG, "Gatt通道建立失败");        }        return true;    }

4 断开连接:gatt.disConnect

5发送数据到外设:

 this.writeCharacteristic.setValue(data);

  this.mBluetoothGatt.writeCharacteristic(this.writeCharacteristic);

6 一旦扫描到外设,就可以获取到service了,这样就可以对属性进行读写了

 private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {     @Override     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {         if (newState == BluetoothProfile.STATE_CONNECTED) {             // TODO: 16/6/24 设备连接             mBleCallBack.deviceConnected(currentDevice.getAddress());             //搜索连接到的蓝牙外设的服务             try {                 Thread.sleep(500);             } catch (InterruptedException e) {                 e.printStackTrace();             }             mBluetoothGatt.discoverServices();             //监测到设备连接成功后,扫描service         } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {             // TODO: 16/6/24 设备断开             if (mBluetoothGatt != null){                 mBluetoothGatt.close(); // 释放资源                 mBluetoothGatt = null;             }             mBleCallBack.deviceDisconnected(currentDevice.getAddress());         }     }     @Override     public void onServicesDiscovered(BluetoothGatt gatt, int status) {         Log.d(TAG, "onServicesDiscovered: BluetoothGatt Status:"+status);         if (status == BluetoothGatt.GATT_SUCCESS){             // TODO: 16/6/27 搜索服务中             if(bleServiceList != null && bleServiceList.size() > 0) {                 bleServiceList.clear();             }             if(mBluetoothGatt != null) {                 bleServiceList = mBluetoothGatt.getServices();             }             Log.d(TAG, "onServicesDiscovered: gatt success");             setCharacteristicNull();             BluetoothGattService bluetoothGattService = mBluetoothGatt.getService(SERVICE_UUID);             if (bluetoothGattService != null){                 List<BluetoothGattCharacteristic> characteristicList = bluetoothGattService.getCharacteristics();                 for (BluetoothGattCharacteristic characteristic : characteristicList) {                     Log.d(TAG, "onServicesDiscovered: Characteristic:"+characteristic.getUuid()+"propertity:"+characteristic.getProperties());                     if (characteristic.getUuid().equals(UUID.fromString(""))) {                         if ((characteristic.getProperties() & 18) != 0) {                             Log.d(TAG, "onServicesDiscovered: readCharacteristic:"+characteristic.getProperties());                             readCharacteristic = characteristic;//获取到读写characteristic                             setCharacterNotification(readCharacteristic,true);                         } else if ((characteristic.getProperties() & 12) != 0) {                             Log.d(TAG, "onServicesDiscovered: writeCharacteristic:"+characteristic.getProperties());                             characteristic.setWriteType(1);                             writeCharacteristic = characteristic;                         }                     }                     }                 }             }             BluetoothGattService bluetoothGattServicen = mBluetoothGatt.getService(SERVICE_UUIDN);             if (bluetoothGattServicen != null) {                 List<BluetoothGattCharacteristic> characteristicListn = bluetoothGattServicen.getCharacteristics();                 for (BluetoothGattCharacteristic characteristic : characteristicListn) {                     if (characteristic.getUuid().equals(UUID.fromString("d44bc439-abfd-45a2-b575-925416129601"))) {                         readCharacteristic = characteristic;                         setCharacterNotification(readCharacteristic,true);                         Log.e(TAG, "读:" + characteristic.getProperties());                     }                     if (characteristic.getUuid().equals(UUID.fromString("d44bc439-abfd-45a2-b575-925416129600"))) {                         writeCharacteristic = characteristic;                         //characteristic.setWriteType(1);                         Log.e(TAG, "写:" + characteristic.getProperties());                     }                 }             }         }     }     @Override     public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {         if(status == 0) {             // TODO: 16/6/27 读characteristic的值         }     }     @Override     public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {         byte[] var3 = characteristic.getValue();         Log.d(TAG,"write  character response:"+CharUtils.bytesToHexString(var3));     }     @Override     public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {         byte[] var3 = characteristic.getValue();         Log.d(TAG, "onCharacteristicChanged: data:"+CharUtils.bytesToHexString(var3));         // TODO: 16/6/27 接收数据         mBleCallBack.deviceReceiveData(currentDevice.getAddress(),var3);     }     @Override     public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {         if(status == 0) {             // TODO: 16/6/27 写入descriptor 之后回调         }     }     @Override     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {         // TODO: 16/6/27 读取Rssi的值         mBleCallBack.deviceRssiReport(currentDevice.getAddress(),rssi);     } };
7 开启notify接收数据

如果设备主动给手机发信息,则可以通过notification的方式,如果notificaiton方式对于某个Characteristicenable的,那么当设备上的这个Characteristic改变时,手机上onCharacteristic回调就会被促发。

 private void setCharacterNotification(BluetoothGattCharacteristic characteristic, boolean enabled){     Log.e(TAG,"set ChatacterNotification");     boolean isOk = mBluetoothGatt.setCharacteristicNotification(characteristic,enabled);     Log.e(TAG,"set ChatacterNotification:"+isOk);     if(!isOk) {         Log.e(TAG, "设置通知失败");     }//   BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));//     if(descriptor != null) {//         byte[] bytes = enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;//         descriptor.setValue(bytes);//         boolean isWrite =  mBluetoothGatt.writeDescriptor(descriptor);//         if (isWrite){//             Log.d(TAG, "writeDescriptor:ok ");//         }else{//             Log.d(TAG, "writeDescriptor:on ");//         }//   }     List<BluetoothGattDescriptor> descriptorList = characteristic.getDescriptors();     if(descriptorList != null && descriptorList.size() > 0) {         Log.e(TAG, "descriptor != null");         for(BluetoothGattDescriptor descriptor : descriptorList) {             descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);             boolean isWrite = mBluetoothGatt.writeDescriptor(descriptor);             if (isWrite){             Log.d(TAG, "writeDescriptor:ok ");             }else {             Log.d(TAG, "writeDescriptor:on ");             }         }     } }

原创粉丝点击