蓝牙4.0

网上关于蓝牙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 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.
     * 

* 获取远程设备所支持的services *

* services : Characteristic的集合。例如一个service叫做“Heart Rate Monitor”, * 它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。 */ private List 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值变化时,发出通知 *

* 当 其发生变化时会使 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 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);
        }
    }
}

你可能感兴趣的:(杂记)