您的位置:首页 > 其它

蓝牙4.0

2016-05-25 17:09 281 查看
网上关于蓝牙4.0的讲解:http://www.2cto.com/kf/201411/349575.html

http://blog.csdn.net/changemyself/article/details/8454633

大家贡献的demo 下载 :http://download.csdn.net/detail/lqw770737185/8116019

目前主流手机蓝牙基本已经是4.0 及以上了 , 网上对于蓝牙4.0的讲解也有不少,有的已经深入到刨祖坟的地步,虽然讲的很详细,但是我看的也是云里雾里(原谅我太蠢~~~),这里打算先理清整个工作流程,后面再贴上我封装的蓝牙4.0模块(官方demo是通过广播来写,本人喜欢用接口)。

蓝牙4.0整个工作流程:

1 . 对于需要连接蓝牙设备的移动端,首先需要判断是否具有蓝牙功能(有的话就打开蓝牙),要不然你的设备再牛客户没办法用,也是白搭;

2 . 确认完移动端有蓝牙模块后,接着判断支持蓝牙4.0 还是2.0 ;

/**
* 打开蓝牙
* @return
*/
@SuppressLint("NewApi")
private boolean EnableBle() {
boolean enable = false;
// BluetoothManager在Android4.3以上支持(API level 18)。
BluetoothManager bluetoothManager=(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothadapter=bluetoothManager.getAdapter();
//开启蓝牙
if(bluetoothadapter!=null && SupportBle()){
bluetoothadapter.enable();
enable=true;
}else if(bluetoothadapter==null){
ToastMore("没有检测到蓝牙设备");
enable=false;
}else if(!SupportBle()){
ToastMore("本设备不支持蓝牙4.0");
enable=false;
}
return enable;
}
/**
* 检查设备是否支持蓝牙4.0
* @return
*/
public boolean SupportBle(){
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
return true;
}
return false;
}


3 . 确认移动端是支持蓝牙4.0 后,打开蓝牙,开启扫描,查找指定设备 , 查找到我们的设备后,关闭蓝牙扫描,这样可以减低功耗;

/**是否开始搜索设备
* @param
* enable :是否搜索
* devicename: 搜索到该设备名  停止搜索 devicename==null 默认搜索1分钟
* */
public void SearchDevice(boolean enable,String devicename){
this.devicename=devicename;
if(enable){
ToastMore("开始扫描");
continue_search=true;
//查找特定设备
//bluetoothadapter.startLeScan(serviceUuids, callback);
if(devicename==null||devicename.equals("")){
new Handler().postDelayed(new Runnable() {

@Override
public void run() {
continue_search=false;
bluetoothadapter.stopLeScan(callback);
}
},60000);
}
//开始扫描
bluetoothadapter.startLeScan(callback);
}else{
ToastMore("停止扫描");
continue_search=false;
//停止扫描
bluetoothadapter.stopLeScan(callback);
}
}
/**
* Device scan callback.
4.0  callback
蓝牙搜索到设备会回调该方法
搜索时,只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索
*/
private BluetoothAdapter.LeScanCallback callback=new BluetoothAdapter.LeScanCallback() {

@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
((MainActivity)context).runOnUiThread(new Runnable() {
public void run() {
//找到指定设备停止扫描
LogMore("扫描到设备:"+device.getName());
if(continue_search){
if(devicename.equals(device.getName())){
LogMore("已经扫描到设备:"+device.getName());
//停止扫描
SearchDevice(false, null);
}
}
}
});

}
};


4 . 查找到我们的设备后,开始连接,通过 BluetoothGattCallback 接口的onConnectionStateChange方法我们可以确认此时的连接状态(通过这个状态可以做出提示,提高友好度),连接设备之后, onServicesDiscovered(BluetoothGatt gatt, int status) 这个方法会返回两个参数,status 表示此时的连接状态,if(status==BluetoothGatt.GATT_SUCCESS ),表示连接成功,并且发现了远程设备的services,这个时候我们就可以做自己的操作了,比如可以向自己的设备写入数据,例如发出开始的命令;

5 . 发送命名,我们需要知道service所包含的某一个characteristic的uuid,因为service是一个characteristic的集合,如果不知道那么就遍历characteristic集合,给所有的characteristic发送开始的命令(这里要提醒一下:遍历写入的时候要加延迟,不然很可能写入失败,我掉过的坑啊~~),并给每一个characteristic设备添加setCharacteristicNotification,表示给当前这个characteristic设置提醒,那么当指定的这个characteristic的值发生变化后,就会回调 onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)方法,在这里接收蓝牙回传数据,一般到了这里我们就已经可以拿到需要的数据了,接下来就是读取数据,通过bluetoothGatt.readCharacteristic(characteristic),characteristic已经被读取后,会回调onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status),最后把characteristic解析就是我们需要的数据了,当然,如果这还不是你需要的(可能你的设备需要进行几次交互),那么可以通过判断来决定是否再次写入

/**连接设备后回调*/
private BluetoothGattCallback Gattcallback=new BluetoothGattCallback() {
/**连接状态发生改变*/
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if(status==BluetoothProfile.STATE_CONNECTED){
LogMore("已经连接");
}else if(status==BluetoothProfile.STATE_CONNECTING){
LogMore("正在连接");
}else if(status==BluetoothProfile.STATE_DISCONNECTED){
LogMore("已经断开");
}else if(status==BluetoothProfile.STATE_CONNECTING){
LogMore("正在断开");
}

};
/**发现sevice*/
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//设备连接成功
if(status==BluetoothGatt.GATT_SUCCESS){
vble.WriteDatatoBle(getSupportedGattServices());
}else{
LogMore("onServicesDiscovered+"+status+"-->"+gatt);
}
}
/**读取数据*/
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if(status==BluetoothGatt.GATT_SUCCESS){
//解析数据
AnalysisBleData(characteristic);
}
}
/**检测用户向蓝牙写数据的状态 */
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

}
/**接收蓝牙回传数据*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
//读取
ReadData(characteristic);
}
};


6 . 最后测量完之后,不要忘了关闭蓝牙连接

/**断开连接*/
public void disconnect(){
if(bluetoothadapter!=null &&bluetoothGatt !=null){
bluetoothGatt.disconnect();
LogMore("disconnect");
}
}
/**关闭连接*/
public void closeconnect(){
if(bluetoothadapter!=null &&bluetoothGatt !=null){
bluetoothGatt.close();
bluetoothGatt=null;
LogMore("close");
}
}


上面已经讲完了整个流程,下面贴出整个工具类:

import java.util.List;
import java.util.UUID;
import com.siheal.bledevice66b6b5.view.MainActivity;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

public class BluetoothHandle {
private VBle vble;
private Context context;
private BluetoothAdapter bluetoothadapter;
/**指定要搜索的设备名*/
private String devicename;
/**记录上次连接过的蓝牙地址*/
private String exist_device_address;
private BluetoothGatt bluetoothGatt;
/**
* 蓝牙心率解析uuid
*/
private static UUID UUID_HEART_RATE_MEASUREMENT=UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb");
private final String TAG = BluetoothHandle.class.getSimpleName();
/**
* 用于处理数据的接口
*/
public interface VBle {
/**设置测量结果*/
void SetMeasureData(String data,BluetoothGattCharacteristic characteristic);
/**
* 向蓝牙写入数据
* @param supportedGattServices
*/
void WriteDatatoBle(List<BluetoothGattService> supportedGattServices);
}
public BluetoothHandle(Context context) {
vble=(VBle) context;
this.context=context;
}
/**
* 打开蓝牙
* @return
*/
@SuppressLint("NewApi")
public boolean EnableBle() {
boolean enable = false;
// BluetoothManager在Android4.3以上支持(API level 18)。
BluetoothManager bluetoothManager=(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothadapter=bluetoothManager.getAdapter();
//开启蓝牙
if(bluetoothadapter!=null && SupportBle()){
bluetoothadapter.enable();
enable=true;
}else if(bluetoothadapter==null){
ToastMore("没有检测到蓝牙设备");
enable=false;
}else if(!SupportBle()){
ToastMore("本设备不支持蓝牙4.0");
enable=false;
}
return enable;
}
/**
* 检查设备是否支持蓝牙4.0
* @return
*/
public boolean SupportBle(){
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
return true;
}
return false;
}
/**是否开始搜索设备
* @param
* enable :是否搜索
* devicename: 搜索到该设备名  停止搜索 devicename==null 默认搜索1分钟
* */
public void SearchDevice(boolean enable,String devicename){
this.devicename=devicename;
if(enable){
ToastMore("开始扫描");
//bluetoothadapter.startLeScan(serviceUuids, callback);//查找特定设备
if(devicename==null||devicename.equals("")){
new Handler().postDelayed(new Runnable() {

@Override
public void run() {
bluetoothadapter.stopLeScan(callback);
}
},60000);
}
bluetoothadapter.startLeScan(callback);
}else{
ToastMore("停止扫描");
bluetoothadapter.stopLeScan(callback);
}
}
/**
* Device scan callback.
4.0  callback
蓝牙搜索到设备会回调该方法
搜索时,只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索
*/
private BluetoothAdapter.LeScanCallback callback=new BluetoothAdapter.LeScanCallback() {

@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
((MainActivity)context).runOnUiThread(new Runnable() {
public void run() {
//找到指定设备停止扫描
LogMore("扫描到设备:"+device.getName());
if(devicename.equals(device.getName())){
LogMore("已经扫描到设备:"+device.getName());
SearchDevice(false, null);
//当查找到指定设备后 开始连接
BluetoothHandle.this.connect(device);
}
}
});

}
};

/**
* 连接设备
* @param device
* @return
*/
@SuppressWarnings("unused")
public boolean connect(BluetoothDevice device){
LogMore("正在连接设备:"+device.getName());
String deviceaddress=device.getAddress();
if(exist_device_address!=null&&deviceaddress.equals(exist_device_address)&&bluetoothGatt!=null){
LogMore("Trying to use an existing mBluetoothGatt for connection.");
if(bluetoothGatt.connect()){
LogMore("connection success");
return true;
}else{
return false;
}
}
if(device!=null){
//三个参数:a Context object, autoConnect(boolean 类型的,确定 是否自动连接)
//and a reference to a BluetoothGattCallback
bluetoothGatt=device.connectGatt(context,false, Gattcallback);
}else{
LogMore("Device not found.  Unable to connect.");
return false;
}
return true;
}
/**连接设备后回调*/
private BluetoothGattCallback Gattcallback=new BluetoothGattCallback() {
/**连接状态发生改变*/
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if(status==BluetoothProfile.STATE_CONNECTED){
LogMore("已经连接");
}else if(status==BluetoothProfile.STATE_CONNECTING){
LogMore("正在连接");
}else if(status==BluetoothProfile.STATE_DISCONNECTED){
LogMore("已经断开");
}else if(status==BluetoothProfile.STATE_CONNECTING){
LogMore("正在断开");
}
};
/**发现sevice*/
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//设备连接成功
if(status==BluetoothGatt.GATT_SUCCESS){
vble.WriteDatatoBle(getSupportedGattServices());
}else{
LogMore("onServicesDiscovered+"+status+"-->"+gatt);
}
}
/**读取数据*/
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if(status==BluetoothGatt.GATT_SUCCESS){
//读取数据
LogMore("onCharacteristicRead+"+characteristic.getUuid().toString());
AnalysisBleData(characteristic);
}
}
/**检测用户向蓝牙写数据的状态 */
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

}
/**接收蓝牙回传数据*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
ReadData(characteristic);
//AnalysisBleData(characteristic);
}
};
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
*
* @return A {@code List} of supported services.
* <p>
* 获取远程设备所支持的services
* <p>
* services : Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,
* 它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。
*/
private List<BluetoothGattService> getSupportedGattServices() {
if (bluetoothGatt == null) return null;
return bluetoothGatt.getServices();
}

/**
* 数据解析按照蓝牙心率测量配置文件规格进行
* @param characteristic
*/
protected void AnalysisBleData(BluetoothGattCharacteristic characteristic) {
String mdata=null;
// 这是心率测量配置文件。
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
mdata=String.valueOf(heartRate);
} else {
// 对于所有其他的配置文件,用十六进制格式写数据
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
mdata=new String(data) + "\n" +stringBuilder.toString();
}
}
vble.SetMeasureData(mdata,characteristic);
}

/**
* 设置当指定characteristic值变化时,发出通知
* <p>
* 当 其发生变化时会使 onCharacteristicChanged()回调被触发*/
public void SetCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled){
if(bluetoothadapter!=null&&bluetoothGatt!=null){
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor=characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if(descriptor!=null){
LogMore("set descriptor" + descriptor + descriptor.getValue());
if(enabled){
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
}
else{
descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
bluetoothGatt.writeDescriptor(descriptor);
}
}
}
/**
* 向设备写入数据
* @param characteristic
*/
public void WriteData(BluetoothGattCharacteristic characteristic){
if(bluetoothadapter!=null&&bluetoothGatt!=null){
bluetoothGatt.writeCharacteristic(characteristic);
}
}
/**读取蓝牙数据
* @param characteristic */
public void ReadData(BluetoothGattCharacteristic characteristic){
if(bluetoothadapter!=null&&bluetoothGatt!=null){
bluetoothGatt.readCharacteristic(characteristic);
}
}
/**断开连接*/
public void disconnect(){
if(bluetoothadapter!=null &&bluetoothGatt !=null){
bluetoothGatt.disconnect();
LogMore("disconnect");
}
}
/**关闭连接*/
public void closeconnect(){
if(bluetoothadapter!=null &&bluetoothGatt !=null){
bluetoothGatt.close();
bluetoothGatt=null;
LogMore("close");
}
}
//-----------------------------------------------
private void ToastMore(String string){
Toast.makeText(context, string,Toast.LENGTH_SHORT).show();
}
private void LogMore(String string){
Log.i(TAG,string);
}
}


应用:

import java.util.List;
import com.siheal.bledevice66b6b5.R;
import com.siheal.bledevice66b6b5.presenter.BluetoothHandle;
import com.siheal.bledevice66b6b5.presenter.BluetoothHandle.VBle;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.widget.TextView;

public class MainActivity extends Activity implements VBle , OnClickListener {
private TextView measureData;
/**蓝牙工具类*/
private BluetoothHandle blehandle;
/**ָ指定需要查找的设备名*/
private String assigndevicename="BT05";
/** 是否允许测量*/
private boolean allowmeasure=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
blehandle=new BluetoothHandle(this);
measureData=(TextView) findViewById(R.id.measureData);
findViewById(R.id.searchdevice).setOnClickListener(this);
allowmeasure=blehandle.EnableBle();
}
@Override
protected void onResume() {
super.onResume();
if(allowmeasure)
blehandle.SearchDevice(true,assigndevicename);
}
@Override
protected void onPause() {
super.onPause();
if(allowmeasure){
blehandle.SearchDevice(false, null);
blehandle.disconnect();
}
}

@Override
protected void onStop() {
super.onStop();
if(allowmeasure){
blehandle.SearchDevice(false, null);
blehandle.closeconnect();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.searchdevice:
if(allowmeasure){
blehandle.SearchDevice(true,assigndevicename);
}
break;
}
}
@Override
public void WriteDatatoBle(List<BluetoothGattService> supportedGattServices) {
for(BluetoothGattService getservice:supportedGattServices){
for(final BluetoothGattCharacteristic characteristic : getservice.getCharacteristics()){
new Handler().postDelayed(new Runnable() {

@Override
public void run() {
characteristic.setValue("写入数据");
blehandle.WriteData(characteristic);
}
}, 150);
}
}

}
@Override
public void SetMeasureData(String data, BluetoothGattCharacteristic characteristic) {
if(data.contains("自己设备数据的特定标识符")){
measureData.setText(data);
}else {
//如果不是我们需要的那么根据需要在向设备写入
characteristic.setValue("写入数据");
blehandle.WriteData(characteristic);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: