Android关于低功耗的蓝牙开发工具类

        前段时间公司一直在做与蓝牙通讯的项目,蓝牙在网络上有很多资料,发现有些地方还是有些讲述不具体的地方,所以决定总结一下。蓝牙低功耗通讯的工具类使用方法。

       添加蓝牙权限

           <!-- 添加蓝牙权限-->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

        //以下的使用是让其只是在蓝牙低功耗中有效。
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

        概念一:因为低功耗蓝牙是从苹果那边继承沿用的,部分硬件上的描述可能会让安卓工程师懵比,苹果在打印特征中只是打印不同的部分,但是安卓确是打印整体。例如苹果中的特征是“FFE1”,在安卓中表示应该是“0000FFE1-0000-1000-8000-00805f9b34fb”。

        概念二: 蓝牙通讯之中最重要的就是uuid,因为其他的信息都可以通过扫描之后获得。唯有uuid是需要开发者填写进去的交流的双方约定唯一的“钥匙”。uuid可以理解为端口,基本上分为三种,发送数据的uuid,接收数据的uuid,与功能描述的uuid。在实际的开发中间,有一些蓝牙的厂商,会将发送数据的端口与接收数据的端口使用同一个,那样子就是发送跟接受基本上是同一个uuid,至于功能描述的uuid根据所需的不同的功能加入。而发送数据描述uuid为"00002902-0000-1000-8000-00805f9b34fb"。

        开发蓝牙的流程工具类的流程网络上很多教程:

        蓝牙初始化——判断蓝牙是否打开(如果没有打开就打开蓝牙)——扫描设备——建立连接——蓝牙通讯

        以下贴上蓝牙工具类代码

package Util;
import android.app.Activity;
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.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;


import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import MyEventBus.QueryInstructionsEventbus;
import de.greenrobot.event.EventBus;

/**
 * Created by Administrator on 2017/4/25.
 * 低功耗蓝牙的工具类
 */
public class BleUtil {
    private static final String TAG = "BleUtil";
    private static final long SCAN_PERIOD = 2000;
    public static String characterUUID1 = "0000ffe1-0000-1000-8000-00805f9b34fb";//APP发送命令
    public static String characterUUID2 = "0000ffe1-0000-1000-8000-00805f9b34fb";//BLE用于回复命令
    private static String descriptorUUID = "00002902-0000-1000-8000-00805f9b34fb";//BLE设备特性的UUID
    public static byte[] workModel = {0x02, 0x01};
    private Context mContext;
    private static BleUtil mInstance;
    //作为中央来使用和处理数据;
    private BluetoothGatt mGatt;
    private BluetoothManager manager;
    private BTUtilListener mListener;
    private BluetoothDevice mCurDevice;
    private BluetoothAdapter mBtAdapter;
    private List<BluetoothDevice> listDevice;
    private List<BluetoothGattService> serviceList;//服务
    private List<BluetoothGattCharacteristic> characterList;//特征
    private BluetoothGattService service;
    public static BluetoothGattCharacteristic character1;
    private BluetoothGattCharacteristic character2;
    public static String Connnet_Bule_name = "";

    public static synchronized BleUtil getInstance() {
        if (mInstance == null) {
            mInstance = new BleUtil();
        }
        return mInstance;
    }

    public void setContext(Context context) {
        mContext = context;
        init();
    }

    public void init() {
        listDevice = new ArrayList<>();
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            showToast("BLE不支持此设备!");
            ((Activity) mContext).finish();
        }
        manager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
        //注:这里通过getSystemService获取BluetoothManager,
        //再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。
        if (manager != null) {
            mBtAdapter = manager.getAdapter();
        }
        if (mBtAdapter == null || !mBtAdapter.isEnabled()) {
            mBtAdapter.enable();
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            enableBtIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(enableBtIntent);
        }
    }

    //扫描设备的回调
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi,
                             byte[] scanRecord) {
            try {
                Log.e("onLeScan", device.getName());
                if (!listDevice.contains(device)) {
                    //不重复添加
                    listDevice.add(device);
                    Log.e(TAG, "device:" + device.toString());
                }
                mListener.onLeScanDevices(listDevice);
            } catch (Exception e) {
                Log.e("onLeScan", e.getMessage());
            }
        }
    };

    //扫描设备
    public void scanLeDevice(final boolean enable) {
        if (enable) {
            Handler mHandler = new Handler();
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    stopScan();
                    Log.e(TAG, "run: stop");
                }
            }, SCAN_PERIOD);
            startScan();
            Log.e(TAG, "start");
        } else {
            stopScan();
            Log.e(TAG, "stop");
        }
    }

    //开始扫描BLE设备
    private void startScan() {
        mBtAdapter.startLeScan(mLeScanCallback);
        mListener.onLeScanStart();
    }

    //停止扫描BLE设备
    private void stopScan() {
        mBtAdapter.stopLeScan(mLeScanCallback);
        mListener.onLeScanStop();
    }

    //返回中央的状态和周边提供的数据
    private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                            int newState) {
            try {
                Log.e(TAG, "onConnectionStateChange");
                switch (newState) {
                    case BluetoothProfile.STATE_CONNECTED:
                        Log.e(TAG, "STATE_CONNECTED");
                        gatt.discoverServices(); //搜索连接设备所支持的service
                        Connnet_Bule_name = mCurDevice.getName();
                        mListener.onConnected(mCurDevice);
                        break;
                    case BluetoothProfile.STATE_DISCONNECTED:
                        disConnGatt();
                        Log.e(TAG, "STATE_DISCONNECTED");
                        Connnet_Bule_name = "";
                        character1 = null;
                        mListener.onDisConnected(mCurDevice);
                        break;
                    case BluetoothProfile.STATE_CONNECTING:
                        Log.e(TAG, "STATE_CONNECTING");
                        mListener.onConnecting(mCurDevice);
                        break;
                    case BluetoothProfile.STATE_DISCONNECTING:
                        Log.e(TAG, "STATE_DISCONNECTING");
                        mListener.onDisConnecting(mCurDevice);
                        break;
                }
            } catch (Exception e) {
            }
            super.onConnectionStateChange(gatt, status, newState);
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            Log.d(TAG, "onServicesDiscovered");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                serviceList = gatt.getServices();
                for (int i = 0; i < serviceList.size(); i++) {
                    BluetoothGattService theService = serviceList.get(i);
                    Log.e(TAG, "ServiceName:" + theService.getUuid());
                    characterList = theService.getCharacteristics();
                    for (int j = 0; j < characterList.size(); j++) {
                        String uuid = characterList.get(j).getUuid().toString();
                        Log.e(TAG, "---CharacterName:" + uuid);
                        if (uuid.equals(characterUUID1)) {
                            character1 = characterList.get(j);
                            character2 = characterList.get(j);
                        } else if (uuid.equals(characterUUID2)) {
                        }
                    }
                }
                setNotification();
            }
            super.onServicesDiscovered(gatt, status);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.e(TAG, "onCharacteristicRead " + gatt.getDevice().getName()
                    + " Read "
                    + characteristic.getUuid().toString()
                    + " -> "
                    + "结果是:" + characteristic.getValue());
            super.onCharacteristicRead(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.e(TAG, "onCharWrite " + gatt.getDevice().getName()
                    + " write "
                    + characteristic.getUuid().toString()
                    + " -> "
                    + "结果是:" + characteristic.getValue());
            super.onCharacteristicWrite(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.e(TAG, "onCharacteristicChanged");
//            这里是可以监听到设备自身或者手机改变设备的一些数据修改h通知
            receiveData(characteristic);
            super.onCharacteristicChanged(gatt, characteristic);
        }
    };

    //获取设备指定的特征中的特性,其中对其进行监听, setCharacteristicNotification与上面的回调onCharacteristicChanged进行一一搭配
    private void setNotification() {
        mGatt.setCharacteristicNotification(character2, true);
        BluetoothGattDescriptor descriptor = character2.getDescriptor(UUID.fromString(descriptorUUID));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mGatt.writeDescriptor(descriptor);
    }

    //接收数据,对其进行处理(这里才是数据的回传处理)
    private void receiveData(BluetoothGattCharacteristic ch) {
        byte[] bytes = ch.getValue();
        //查询指令帧的回传
        if ((bytes[0] & 0xff) == 186) {
            if ((bytes[1] & 0xff) == 2) {
                instructions.model = bytes[2] & 0xff;
                instructions.brightness = bytes[3] & 0xff;
                instructions.Tone = bytes[4] & 0xff;
                instructions.Timing_state = bytes[5] & 0xff;
                instructions.Time = bytes[6] & 0xff;
                EventBus.getDefault().post(new QueryInstructionsEventbus());
            }
        }
    }

    //连接设备
    public void connectLeDevice(int devicePos) {
        mBtAdapter.stopLeScan(mLeScanCallback);
        mCurDevice = listDevice.get(devicePos);
        new Handler().postDelayed(new Runnable() {//延时连接,防止蓝牙服务还未绑定起来,就连接,导致异常
            @Override
            public void run() {
                checkConnGatt();
            }
        }, 500);
    }

    //连接设备
    public void connectLeDevice(BluetoothDevice devicePos) {
        mBtAdapter.stopLeScan(mLeScanCallback);
        mCurDevice = devicePos;
        new Handler().postDelayed(new Runnable() {//延时连接,防止蓝牙服务还未绑定起来,就连接,导致异常
            @Override
            public void run() {
                checkConnGatt();
            }
        }, 500);
    }

    //发送进入工作模式请求
    public void sendWorkModel() {
        if (character1 != null) {
            character1.setValue(workModel);
            mGatt.writeCharacteristic(character1);
        }
    }

    //发送数据
    public void SendDateBybyte(byte[] date) {
        if (character1 != null) {
            character1.setValue(date);
            mGatt.writeCharacteristic(character1);
        }
    }

    //发送强度
    public void sendStrength(int strength) {
        byte[] strengthModel = {0x01, (byte) strength};
        if (character1 != null) {
            character1.setValue(strengthModel);
            mGatt.writeCharacteristic(character1);
        }
    }

    //检查设备是否连接了
    private void checkConnGatt() {
        if (mGatt == null) {
            mGatt = mCurDevice.connectGatt(mContext, true, mGattCallback);
            try {
                mListener.onConnecting(mCurDevice);
            } catch (Exception e) {
            }
        } else {
            mGatt.connect();
            mGatt.discoverServices();
        }
    }

    //  断开设备连接
    private void disConnGatt() {
        if (mGatt != null) {
            mGatt.disconnect();
            mGatt.close();
            mGatt = null;
            listDevice = new ArrayList<>();
            mListener.onLeScanDevices(listDevice);
        }
    }

    private void showToast(String message) {
        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
    }

    public void setBTUtilListener(BTUtilListener listener) {
        mListener = listener;
    }

    public interface BTUtilListener {
        void onLeScanStart(); // 扫描开始

        void onLeScanStop();  // 扫描停止

        void onLeScanDevices(List<BluetoothDevice> listDevice); //扫描得到的设备

        void onConnected(BluetoothDevice mCurDevice); //设备的连接

        void onDisConnected(BluetoothDevice mCurDevice); //设备断开连接

        void onConnecting(BluetoothDevice mCurDevice); //设备连接中

        void onDisConnecting(BluetoothDevice mCurDevice); //设备连接失败

        void onStrength(int strength); //给设备设置强度

        void onModel(int model); //设备模式
    }
}

     以上的蓝牙工具类中注意的点:

    1:我增加了发送数据的方法。
    //发送数据
    public void SendDateBybyte(byte[] date) {
        if (character1 != null) {
            character1.setValue(date);
            mGatt.writeCharacteristic(character1);
        }
    }

    2:经过测试蓝牙的回传数据不是在onCharacteristicRead方法中回调,而是在receiveData方法中回调。

    

    以上的工具类经过测试有效,但是无意之中发现了有谷歌推荐的官方的工具类可以使用。教程地址为:http://blog.csdn.net/will4906/article/details/53042382locationNum=4&fps=1

    有兴趣的话可以去试试看,本人因为接触蓝牙开发时间一共两个星期,现已经跳槽,等他日有空再来细细回味。

   

猜你喜欢

转载自blog.csdn.net/weixin_30267253/article/details/71080663