蓝牙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<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);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值