android蓝牙ble4.0开发
2015-11-18 22:26
483 查看
1、权限配置
AndroidManifest.xml里配置,“android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行。
2、判断是否支持蓝牙
3、打开和关闭蓝牙
先获取蓝牙适配器:
如果蓝牙关闭,则打开蓝牙:
// 也可以用enable()方法来开启,无需询问用户(无声息的开启蓝牙设备),这时就需要用到android.permission.BLUETOOTH_ADMIN权限。
// mBluetoothAdapter.enable(); //打开蓝牙
// mBluetoothAdapter.disable();//关闭蓝牙
注意,如果用静默的方式打开蓝牙,不能马上开始扫描,这样会失败,因为打开蓝牙要一两秒时间。
4、搜索蓝牙
device代表蓝牙设备,rssi是信号强度,scanRecord是广播数据,一些项目要求广播匹配蓝牙设备才能被发现,就是根据把产品ID写到广播里来判别。如下:
4.3以下的通过广播方式来搜索,如下:
另外,还可以配置本机蓝牙是否可见,被对方搜索到:
5、蓝牙连接
两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。
连接GATT Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
函数成功,返回BluetoothGatt对象,它是GATT
profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。
BluetoothGatt常规用到的几个操作示例:
connect() :连接远程设备。
discoverServices() : 搜索连接设备所支持的service。
disconnect():断开与远程设备的GATT连接。
close():关闭GATT Client端。
readCharacteristic(characteristic) :读取指定的characteristic。
setCharacteristicNotification(characteristic, enabled) :设置当指定characteristic值变化时,发出通知。
getServices() :获取远程设备所支持的services。
google的demo里,连接蓝牙,首先绑定一个服务:
initialize()初始化函数里,主要是获得mBluetoothManager和mBluetoothAdapter:
这里的mGattCallback是蓝牙连接和通讯读写和收到通知时的回调函数。
6、蓝牙通讯
BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value
我们一般需要操作的是Characteristic,需要先获取Service,然后可以进行读、写和打开通知操作。
public static final UUID SERVIE_UUID = UUID.fromString("0000FE95-0000-1000-8000-00805f9b34fb");
BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
1)、Characteristic读操作
蓝牙读操作对应上面mGattCallback的函数是onCharacteristicRead,执行完读之后可以在onCharacteristicRead里收到读的数据。
2)Characteristic写操作
3)Characteristic打开\关闭notify
如果我们要长期监视蓝牙设备的状态变化,一般需要用到notify功能。
蓝牙notify操作对应上面mGattCallback的函数是onCharacteristicChanged,打开之后,可以在这个函数里监视notify的数据变化。
AndroidManifest.xml里配置,“android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行。
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
2、判断是否支持蓝牙
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); }
3、打开和关闭蓝牙
先获取蓝牙适配器:
final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); // Checks if Bluetooth is supported on the device. if (mBluetoothAdapter == null) { Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); finish(); return; }
如果蓝牙关闭,则打开蓝牙:
if (!mBluetoothAdapter.isEnabled()) { if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } }
public void onActivityResult(int requestCode, int resultCode, Intent data){ if(requestCode == REQUEST_ENABLE_BT){ if(requestCode == RESULT_OK){ //蓝牙已经开启 } } }
// 也可以用enable()方法来开启,无需询问用户(无声息的开启蓝牙设备),这时就需要用到android.permission.BLUETOOTH_ADMIN权限。
// mBluetoothAdapter.enable(); //打开蓝牙
// mBluetoothAdapter.disable();//关闭蓝牙
注意,如果用静默的方式打开蓝牙,不能马上开始扫描,这样会失败,因为打开蓝牙要一两秒时间。
4、搜索蓝牙
mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); invalidateOptionsMenu(); } }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); }在4.3之前的api是通过注册广播来处理搜索时发生的一些事件,使用startDiscovery()这个函数搜索,而支持ble的新的api中,是通过回调的方式来处理的,mLeScanCallback就是一个接口对象。
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.addDevice(device); mLeDeviceListAdapter.notifyDataSetChanged(); } }); } };
device代表蓝牙设备,rssi是信号强度,scanRecord是广播数据,一些项目要求广播匹配蓝牙设备才能被发现,就是根据把产品ID写到广播里来判别。如下:
4.3以下的通过广播方式来搜索,如下:
// 设置广播信息过滤 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); // 注册广播接收器,接收并处理搜索结果 context.registerReceiver(receiver, intentFilter); // 寻找蓝牙设备,android会将查找到的设备以广播形式发出去 adapter.startDiscovery();
private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); System.out.println(device.getName()); } } }
另外,还可以配置本机蓝牙是否可见,被对方搜索到:
//使本机蓝牙在300秒内可被搜索 private void ensureDiscoverable() { if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent); } }还有查找以前配对过的设备:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { //device.getName() +" "+ device.getAddress()); } } else { mPairedDevicesArrayAdapter.add("没有找到已匹对的设备"); }
5、蓝牙连接
两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。
连接GATT Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
函数成功,返回BluetoothGatt对象,它是GATT
profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。
BluetoothGatt常规用到的几个操作示例:
connect() :连接远程设备。
discoverServices() : 搜索连接设备所支持的service。
disconnect():断开与远程设备的GATT连接。
close():关闭GATT Client端。
readCharacteristic(characteristic) :读取指定的characteristic。
setCharacteristicNotification(characteristic, enabled) :设置当指定characteristic值变化时,发出通知。
getServices() :获取远程设备所支持的services。
google的demo里,连接蓝牙,首先绑定一个服务:
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
// Code to manage Service lifecycle. private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service) .getService(); if (!mBluetoothLeService.initialize()) { Log.e(TAG, "Unable to initialize Bluetooth"); finish(); } // Automatically connects to the device upon successful start-up // initialization. mBluetoothLeService.connect(mDeviceAddress); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } };
initialize()初始化函数里,主要是获得mBluetoothManager和mBluetoothAdapter:
/** * Initializes a reference to the local Bluetooth adapter. * * @return Return true if the initialization is successful. */ public boolean initialize() { // For API level 18 and above, get a reference to BluetoothAdapter through // BluetoothManager. if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { Log.e(TAG, "Unable to initialize BluetoothManager."); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Log.e(TAG, "Unable to obtain a BluetoothAdapter."); return false; } return true; }连接函数mBluetoothLeService.connect里,先用getRemoteDevice获取BluetoothDevice,然后调用connectGatt函数连接,连接成功返回BluetoothGatt。
/* Connects to the GATT server hosted on the Bluetooth LE device. * * @param address The device address of the destination device. * * @return Return true if the connection is initiated successfully. The connection result * is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } // Previously connected device. Try to reconnect. if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { mConnectionState = STATE_CONNECTING; return true; } else { return false; } } final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { Log.w(TAG, "Device not found. Unable to connect."); return false; } // We want to directly connect to the device, so we are setting the autoConnect // parameter to false. mBluetoothGatt = device.connectGatt(this, false, mGattCallback); Log.d(TAG, "Trying to create a new connection."); mBluetoothDeviceAddress = address; mConnectionState = STATE_CONNECTING; System.out.println("device.getBondState=="+device.getBondState()); return true; }
这里的mGattCallback是蓝牙连接和通讯读写和收到通知时的回调函数。
//蓝牙数据返回 // Implements callback methods for GATT events that the app cares about. For example, // connection change and services discovered. private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; mConnectionState = STATE_CONNECTED; broadcastUpdate(intentAction); Log.i(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; mConnectionState = STATE_DISCONNECTED; Log.i(TAG, "Disconnected from GATT server."); broadcastUpdate(intentAction); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); } else { Log.w(TAG, "onServicesDiscovered received: " + status); System.out.println("onServicesDiscovered received: " + status); } } public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) { Log.e(TAG, "onCharacteristicRead"); if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG,"onCharRead "+gatt.getDevice().getName() +" read " +characteristic.getUuid().toString() +" -> " +UMDataProcessUtil.bytesToHexString(characteristic.getValue())); broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } } /** * 返回数据。 */ @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); //数据 Log.i("onCharacteristicChanged", "返回读出的值"); Log.e("notify data:", UMDataProcessUtil.bytesToHexString(characteristic.getValue())); } };
6、蓝牙通讯
BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value
我们一般需要操作的是Characteristic,需要先获取Service,然后可以进行读、写和打开通知操作。
public static final UUID SERVIE_UUID = UUID.fromString("0000FE95-0000-1000-8000-00805f9b34fb");
BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
1)、Characteristic读操作
public static final UUID LIGHT_UUID = UUID.fromString("00001006-0000-1000-8000-00805F9B34FB");
public void readLlsAlertLevel(){ BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID); if (linkLossService == null) { showMessage("readLlsAlertLevel, link loss Alert service not found!"); return; } BluetoothGattCharacteristic alertLevel = linkLossService.getCharacteristic(STATE_UUID); if(mBluetoothGatt.readCharacteristic(alertLevel)) { Log.e("test","ble read success"); } else { Log.e("test","ble read fail"); } }
蓝牙读操作对应上面mGattCallback的函数是onCharacteristicRead,执行完读之后可以在onCharacteristicRead里收到读的数据。
2)Characteristic写操作
public void writeLlsAlertLevel(int iAlertLevel, byte[] bb) { BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID); if (linkLossService == null) { showMessage("writeLlsAlertLevel,link loss Alert service not found!"); return; } BluetoothGattCharacteristic alertLevel = null; alertLevel = linkLossService.getCharacteristic(KEY_UUID); if (alertLevel == null) { showMessage("writeLlsAlertLevel,link loss Alert Level charateristic not found!"); return; } int storedLevel = alertLevel.getWriteType(); Log.d(TAG, "storedLevel() - storedLevel=" + storedLevel); alertLevel.setValue(bb); Log.e("发送的指令", "bb" + bb[0]); alertLevel.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); boolean status = mBluetoothGatt.writeCharacteristic(alertLevel); Log.d(TAG, "writeLlsAlertLevel() - status=" + status); }蓝牙写操作对应上面mGattCallback的函数是onCharacteristicWrite,但是我们一般没有必要监视这个,直接从返回的status判断是否写成功就行了。
3)Characteristic打开\关闭notify
如果我们要长期监视蓝牙设备的状态变化,一般需要用到notify功能。
public boolean enableStateNotification(boolean enable){ BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID); if (linkLossService == null) { showMessage("enableStateNotification, link loss Alert service not found!"); return false; } BluetoothGattCharacteristic characteristic = linkLossService.getCharacteristic(STATE_UUID); int charaProp = characteristic.getProperties(); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) <= 0) { showMessage("getProperties wrong!Not PROPERTY_NOTIFY !"); return false; } return setCharacteristicNotification(characteristic,enable); }
public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
/** * Enables or disables notification on a give characteristic. * @param characteristic Characteristic to act on. * @param enabled If true, enable notification. False otherwise. */ public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return false; } boolean result =mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); if(!result){ <span style="white-space:pre"> </span>Log.e(TAG, "setCharacteristicNotification fail!!!!!!!!!!!"); <span style="white-space:pre"> </span>return false; } BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(UMGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); return mBluetoothGatt.writeDescriptor(descriptor); }
蓝牙notify操作对应上面mGattCallback的函数是onCharacteristicChanged,打开之后,可以在这个函数里监视notify的数据变化。
相关文章推荐
- android自定义流式布局解析与源码
- android头像设置
- Android 自己画View -- drawable.draw 以及 drawText
- 极品Android学习资料整合
- Android控件Activity、Fragment详解
- 为何 YunOS 有别于 Android?
- 更新Android版本后,新建工程出错
- Android activity跳转方式
- Android性能优化之使用线程池处理异步任务
- AndroidStudio的使用(持续更新)
- ubuntu12.04下搭建android开发环境
- Android 拖拉控件遇到的问题
- Android Studio快捷键1、查看——2、查找——3、修改
- 使用jenkins自动化构建android和ios应用
- android背景选择器selector用法、自定义Button按钮样式..........
- Windows系统下Android开发环境搭建
- ViewAnimator之ViewFlipper
- Android中的各种单位
- 命令行构建安卓工程,了解工程原理
- Android基础入门教程——10.12 传感器专题(3)——加速度-陀螺仪传感器