首先说一下蓝牙2.0和蓝牙4.0的区别,蓝牙2.0开发用的是socket协议直接连接设备指定的UUID,按字节读取的情况比较多,但是蓝牙4.0在开发时,新版本把它封装成一个类来调用的。
开发蓝牙4.0,首先了解一下支持蓝牙4.0设备的基本信息:蓝牙有好多的gatt服务,也就是service,而每一个gatt服务下面有很多的特征值,也就是characteristic,每一个服务,特征值都会对应一个UUID,这个UUID一般都是硬件开发已经写好的,我们在用android开发和它通信时,只要找到正确的UUID就行了,有些硬件厂商会给,要是没给的话,可以自己一个一个试出来,反正一般情况下不会太多,毕竟谁会在硬件上开发那么多服务但是实际上用的却没几个。
好了,了解上面的东西后,就知道怎么开发了,
1.首先manifest配置权限,一般需要到的如下:
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
这个就比较简单了,一般做开发的都知道,如果还需要存储和读写进SD卡,最好把sd卡的权限也加上。
2.然后呢,因为谷歌在6.0之后权限做了约束,需要动态申请,这个代码大致如下:
public void requestPermission(){ if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH_PRIVILEGED}, 2); }else { } if(ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH_PRIVILEGED}, 5); } if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS}, 3); } }
//initial bluetooth adapter BluetoothManager bluetoothManager = (BluetoothManager) a.getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); //check support adapter or not if (mBluetoothAdapter == null) { Toast.makeText(a,"device is not supported", Toast.LENGTH_SHORT).show(); return; }
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
mBluetoothGattCallBack = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { Log.i("blb", "--------state change"); // gatt.discoverServices(); if (newState == BluetoothProfile.STATE_CONNECTED) { // gatt.discoverServices();//if connected, discover services of remote device Log.i("blb","-------state connected");
//自己定义一个广播通知已经连接 a.sendBroadcast(new Intent(CONNECTION_ACTION));//send broadcast to notify device is connected gatt.discoverServices(); }else if (newState == BluetoothProfile.STATE_DISCONNECTED){ Log.i("blb", "---------disconnected");
//自己定义一个广播通知已经断开 a.sendBroadcast(new Intent(DISCONNECTED_ACTION));//send broadcast to notify device is disconnected } Log.i("blb", "state change" + ", status:" + status + ", new State:" + newState); super.onConnectionStateChange(gatt, status, newState); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); Log.i("blb", "device service discovered"); Listlists = gatt.getServices(); Log. i("blb", "-------gatt service size:" + lists.size()); for (int i = 0; i < lists.size(); i++) { BluetoothGattService temp = lists.get(i); ListcLists = temp.getCharacteristics(); Log. i("blb", "--------i:" + i + ", uuid:" + temp.getUuid() + ", characteristic size:" + cLists.size()); for (int j = 0; j < cLists.size(); j++) { final BluetoothGattCharacteristic bcdemo = cLists.get(j); final int charaProp = bcdemo.getProperties(); Log.i("blb", "---------i's character:" + bcdemo.getUuid() + ", "); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) { Log.i("blb", "----notifycation is available" + ", i:" + i + ", j:" + j); } } }
//这里可以设置需要访问的属性值,就是前面说的UUID,可以从厂商那里得到,也可以自己一个一个试出来mBluetoothGatt .setCharacteristicNotification(lists.get( 3 ).getCharacteristics().get( 0 ), true ); }
@Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); Log.i("blb", "character read"); String value = bytesToHexString(characteristic.getValue()); Log.i("blb",gatt.getDevice().getName() + " recieved " + value + ", length:" + characteristic.getValue().length); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); Log.i("blb", "------write"); }
//这个回调是你设置的那个蓝牙service下的特征值发生改变时,会走这个方法,在这里做业务上的处理就行了,如果只需要读一次的话,直接使用read方法, @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); Log.i("blb", "---------characteristic changed read from device:" + bytesToHexString(characteristic.getValue())); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); Log.i("blb", "descrptor read"); descriptor.getValue(); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); Log.i("blb", "descrptor write"); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { super.onReliableWriteCompleted(gatt, status); Log.i("blb", "ReliableWriteCompleted"); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { super.onReadRemoteRssi(gatt, rssi, status); Log.i("blb", "ReadRemoteRssi"); } @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); Log.i("blb", "----onMtuChanged"); } };
5.扫描的时候需要用到一个回调,这个类就是ScanCallBack类,new一个就行:
mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); BluetoothDevice bluetoothDevice = result.getDevice(); Log.i("blb", "-------scan result:" + bluetoothDevice.getName() + ", address:" + bluetoothDevice.getAddress()); //00:15:83:00:41:DB.equalsIgnoreCase(bluetoothDevice.getAddress() if (bluetoothDevice.getName() != null){ if (bluetoothDevice.getName().toLowerCase().contains("bpm")){//根据字符串判断出是否是指定型号的设备,如果已经搜到就停止搜索 Log.i("blb", "-------contains"); mBluetoothLeScanner.stopScan(mScanCallback);//停止搜索 mBluetoothGatt = bluetoothDevice.connectGatt(a, true, mBluetoothGattCallBack);//连接gatt服务 } } ParcelUuid[] uuids = bluetoothDevice.getUuids(); if (uuids != null){ Log.i("blb", "------uuid length:" + uuids.length); for (int i = 0; i < uuids.length; i++) { } } } @Override public void onBatchScanResults(Listresults) { super.onBatchScanResults(results); Log.i("blb", "---------batch scan result"); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); Log.i("blb", "--------scan failed"); } };
6.前面的工作全部做好后,就可以扫描了,扫描后自动连接,可以获取蓝牙设备的所有服务,你只要找到UUID就可以通信了。
//start le scan public void startLeScan(){ mBluetoothLeScanner.startScan(mScanCallback); }
7.停止的话就直接调用stopScan就行了,如果只是单单的读取一次的话,直接调用read方法就行,后面会回调到onCharacteristicRead方法,根据需求自己用逻辑处理下就行了。