android BluetoothKit 蓝牙开发实战 requestMtu的坑

前言

第一次做蓝牙开发,刚开始是懵逼的,花了2-3天可以实现功能了,连接血糖仪血压仪胰岛素泵并发送接收数据,用到了BluetoothKit。能力有限,错误之处还望指出。

首先需要知道的两点,1不需要配对也可以连接成功后直接发送数据(代码中无感) 2可以同时存在多个连接

大体流程:打开蓝牙-搜索蓝牙设备-连接某个蓝牙设备-读写数据

封装


public class BleManager {

private BluetoothClientmClient;

private MyBleListenermyBleListener;

private BleConnectStatusListenermBleConnectStatusListener;

private BluetoothBondListenermBluetoothBondListener;

private BluetoothStateListenermBluetoothStateListener;

private SearchResponsemSearchResponse;

private BleConnectOptionsbleConnectOptions;

private SearchRequestsearchRequest;

private BleManager() {

}

private static class BleManagerHolder {

private static final BleManagerinstance =new BleManager();

}

public static BleManager getInstance() {

return BleManager.BleManagerHolder.instance;

}

public void initBle(Context context, MyBleListener myBleListener) {

this.myBleListener = myBleListener;

mClient = getBleManager(context);

//判断打开

        mBluetoothStateListener =new BluetoothStateListener() {

@Override

            public void onBluetoothStateChanged(boolean openOrClosed) {

if (null !=myBleListener && openOrClosed) {

myBleListener.onBleOpenSuccess();

}

}

};

//搜索

        mSearchResponse =new SearchResponse() {

@Override

            public void onSearchStarted() {

if (myBleListener !=null)myBleListener.onSearchStarted();

}

@Override

            public void onDeviceFounded(SearchResult device) {

if (myBleListener !=null)myBleListener.onDeviceFounded(device);

}

@Override

            public void onSearchStopped() {

if (myBleListener !=null)myBleListener.onSearchStopped();

}

@Override

            public void onSearchCanceled() {

if (myBleListener !=null)myBleListener.onSearchCanceled();

}

};

//搜索配置

        searchRequest =new SearchRequest.Builder()

.searchBluetoothLeDevice(3000,3)

.searchBluetoothClassicDevice(5000)

.searchBluetoothLeDevice(2000)

.build();

//配对

        mBluetoothBondListener =new BluetoothBondListener() {

@Override

            public void onBondStateChanged(String mac,int bondState) {

}

};

//连接

        mBleConnectStatusListener =new BleConnectStatusListener() {

@Override

            public void onConnectStatusChanged(String mac,int status) {

if (status == com.inuker.bluetooth.library.Constants.STATUS_DISCONNECTED) {

//如果你同时连接多个设备可以判断mac

                    if (null !=myBleListener)myBleListener.onDisConnected();

}

}

};

//连接配置

        bleConnectOptions =new BleConnectOptions.Builder()

.setConnectRetry(3)

.setConnectTimeout(5000)

.setServiceDiscoverRetry(3)

.setServiceDiscoverTimeout(5000)

.build();

mClient.registerBluetoothBondListener(mBluetoothBondListener);

}

private BluetoothClient getBleManager(Context context) {

return new BluetoothClient(context);

}

/**

* 设备是否支持蓝牙

*

    * @return

    */

    public boolean isCanUseBle() {

return null != BluetoothAdapter.getDefaultAdapter();

}

public void openBluetooth() {

if (null !=mClient) {

mClient.openBluetooth();

mClient.registerBluetoothStateListener(mBluetoothStateListener);

}

}

public void closeBluetooth() {

if (null !=mClient)mClient.closeBluetooth();

}

public boolean isBluetoothOpened() {

if (null !=mClient)return mClient.isBluetoothOpened();

return false;

}

public void search() {

if (null ==mClient)return;

if (null !=mSearchResponse)mClient.search(searchRequest,mSearchResponse);

}

public void stopSearch() {

if (null !=mClient)mClient.stopSearch();

}

public void connect(final String mac) {

if (null ==mClient)return;

mClient.connect(mac,bleConnectOptions,new BleConnectResponse() {

@Override

            public void onResponse(int code, BleGattProfile data) {

if (code == com.inuker.bluetooth.library.Constants.REQUEST_SUCCESS) {

if (null !=myBleListener) {

myBleListener.onConnectSuccess(code, data,mac);

}

}else if (code == com.inuker.bluetooth.library.Constants.REQUEST_FAILED) {

if (null !=myBleListener)myBleListener.onConnectFail();

}

}

});

mClient.registerConnectStatusListener(mac,mBleConnectStatusListener);

}

public void disconnect(String mac) {

if (null !=mClient)mClient.disconnect(mac);

}

/**

* 自动接受蓝牙设备返回的数据,建立订阅关系

*

    * @return

    */

    public void notify(String mac, String uuid, String uuidread) {

unnotify(mac, uuid, uuidread);

if (null ==mClient)return;

mClient.notify(mac, UUID.fromString(uuid), UUID.fromString(uuidread),new BleNotifyResponse() {

@Override

            public void onNotify(UUID service, UUID character,byte[] value) {

if (null !=myBleListener)myBleListener.onNotify(value);

}

@Override

            public void onResponse(int code) {

if (code == com.inuker.bluetooth.library.Constants.REQUEST_SUCCESS) {

if (null !=myBleListener)myBleListener.onNotifySuccess();

}else if (code == com.inuker.bluetooth.library.Constants.REQUEST_FAILED) {

if (null !=myBleListener)myBleListener.onNotifyFailure();

}

}

});

}

public void unnotify(String mac, String uuid, String uuidread) {

if (null ==mClient)return;

mClient.unnotify(mac, UUID.fromString(uuid), UUID.fromString(uuidread),new BleUnnotifyResponse() {

@Override

            public void onResponse(int code) {

}

});

}

public void write(String MAC, String uuid, String uuidwrite,final byte[] data) {

if (null ==mClient)return;

mClient.write(MAC, UUID.fromString(uuid), UUID.fromString(uuidwrite), data,new BleWriteResponse() {

@Override

            public void onResponse(int code) {

if (code == com.inuker.bluetooth.library.Constants.REQUEST_SUCCESS) {

if (null !=myBleListener)myBleListener.onWriteSuccess();

}else {

if (null !=myBleListener)myBleListener.onWriteFailure();

}

}

});

}

public void destroy(String mac, String uuid, String uuidread) {

if (null !=mClient) {

mClient.stopSearch();

mClient.clearRequest(mac, com.inuker.bluetooth.library.Constants.REQUEST_READ);

mClient.clearRequest(mac, com.inuker.bluetooth.library.Constants.REQUEST_WRITE);

mClient.clearRequest(mac, com.inuker.bluetooth.library.Constants.REQUEST_NOTIFY);

mClient.refreshCache(mac);

mClient.unregisterConnectStatusListener(mac,mBleConnectStatusListener);

mClient.unregisterBluetoothBondListener(mBluetoothBondListener);

mClient.unregisterBluetoothStateListener(mBluetoothStateListener);

}

unnotify(mac, uuid, uuidread);

mBleConnectStatusListener =null;

mBluetoothBondListener =null;

mBluetoothStateListener =null;

myBleListener =null;

}

/**

* 蓝牙传输数据限制20字节,当数据过大时,可以设置,第二个参数好像23-512(详情见源码)

*

    * @return

    */

    public void requestMtu(String MAC) {

if (null ==mClient)return;

mClient.requestMtu(MAC,500,new BleMtuResponse() {

@Override

            public void onResponse(int code, Integer data) {

//code为1说明设置成功

            }

});

}

}

调用

我去掉了自己的业务逻辑,只保留最基础的


public class DemoActivityextends Activityimplements MyBleListener {

private BleManagerbleManager;

private SearchResultdevice;

//请使用自己的uuid

    public Stringuuid ="0003cdd0-0000-1000-8000-00805f9b0131";

public Stringuuidread ="0003cdd1-0000-1000-8000-00805f9b0131";

public Stringuuidwrite ="0003cdd2-0000-1000-8000-00805f9b0131";

@Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

bleManager = BleManager.getInstance();

bleManager.initBle(this,this);

if (!bleManager.isBluetoothOpened()) {

bleManager.openBluetooth();

}else {

bleManager.search();

}

}

@Override

    protected void onDestroy() {

super.onDestroy();

bleManager.destroy(device.getAddress(),uuid,uuidread);

}

@Override

    public void onSearchStarted() {

}

@Override

    public void onDeviceFounded(SearchResult device) {

//这里一般是要用列表展现所有设备的

        if (device !=null && device.getName().indexOf("P4B") != -1) {

this.device = device;

bleManager.connect(device.getAddress());

}

}

@Override

    public void onSearchStopped() {

}

@Override

    public void onSearchCanceled() {

}

@Override

    public void onWriteSuccess() {

}

@Override

    public void onWriteFailure() {

}

@Override

    public void onBleOpenSuccess() {

}

@Override

    public void onDisConnected() {

}

@Override

    public void onStartConnect() {

}

@Override

    public void onConnectFail() {

}

@Override

    public void onConnectSuccess(int code, BleGattProfile data, String mac) {

bleManager.unnotify(device.getAddress(),uuid,uuidread);

bleManager.requestMtu(device.getAddress());

bleManager.notify(device.getAddress(),uuid,uuidread);

}

@Override

    public void onNotify(byte[] value) {

//处理返回数据

        read(value);

}

private void read(byte[] value) {

Log.e("bobowa","读取数据=" + Arrays.toString(value));

}

@Override

    public void onNotifyFailure() {

}

@Override

    public void onNotifySuccess() {

//延时处理要不写数据可能会失败

        try {

Thread.sleep(200L);

}catch (InterruptedException e) {

e.printStackTrace();

}

bleManager.write(device.getAddress(),uuid,uuidwrite, getWriteData());

}

private StringdeviceName ="20200105001";

private int sendtype =1;

//根据自己的需求完成写指令的拼接

    private byte[] getWriteData() {

String s1 ="551400A3";

String s2 ="";

if (sendtype ==0) {

//获取泵运行状态

            s2 ="00AA";

}

if (sendtype ==1) {

//获取大剂量

            s2 ="01AA";

}

if (sendtype ==2) {

//获取基础率

            s2 ="0200";

}

if (sendtype ==3) {

//获取警示

            s2 ="03AA";

}

if (sendtype ==4) {

//获取排气

            s2 ="04AA";

}

String s3 = stringToHexString(deviceName) +"00";

String s4 = s1 + s2 + s3;

String crc =getCRC(s4);

Log.d("bobowa","s4=" + s4);

return hexStringToBytes(s4 + crc);

}

/**

* 字符串转换为16进制字符串

* 设备号转hex命令

*

    * @param s

    * @return

    */

    public String stringToHexString(String s) {

String str ="";

for (int i =0; i < s.length(); i++) {

int ch = s.charAt(i);

String s4 = Integer.toHexString(ch);

str = str + s4;

}

return str;

}

public static String getCRC(String data) {

data = data.replace(" ","");

int len = data.length();

if (!(len %2 ==0)) {

return "0000";

}

int num = len /2;

byte[] para =new byte[num];

for (int i =0; i < num; i++) {

int value = Integer.valueOf(data.substring(i *2,2 * (i +1)),16);

para[i] = (byte) value;

}

return getCRC(para);

}

public static String getCRC(byte[] bytes) {

//CRC寄存器全为1

        int CRC =0x0000ffff;

//多项式校验值

        int POLYNOMIAL =0x0000a001;

int i, j;

for (i =0; i < bytes.length; i++) {

CRC ^= ((int) bytes[i] &0x000000ff);

for (j =0; j <8; j++) {

if ((CRC &0x00000001) !=0) {

CRC >>=1;

CRC ^= POLYNOMIAL;

}else {

CRC >>=1;

}

}

}

//结果转换为16进制

        String result = Integer.toHexString(CRC).toUpperCase();

if (result.length() !=4) {

StringBuffer sb =new StringBuffer("0000");

result = sb.replace(4 - result.length(),4, result).toString();

}

//交换高低位

        return result.substring(2,4) + result.substring(0,2);

}

/**

* String转换成每2位的数组

*

    * @param hexString

    * @return

    */

    public byte[] hexStringToBytes(String hexString) {

Log.d("bobowa","hexStringToBytes=" + hexString);

if (hexString ==null || hexString.equals("")) {

return null;

}

hexString = hexString.toUpperCase();

int length = hexString.length() /2;

char[] hexChars = hexString.toCharArray();

byte[] d =new byte[length];

for (int i =0; i < length; i++) {

int pos = i *2;

d[i] = (byte) (charToByte(hexChars[pos]) <<4 | charToByte(hexChars[pos +1]));

}

return d;

}

public byte charToByte(char c) {

return (byte)"0123456789ABCDEF".indexOf(c);

}

}

requestMtu

如果你只依赖implementation 'com.inuker.bluetooth:library:1.4.0'会发现找不到这个方法,

项目中的源码有,sdk中没用,需要手动复制源码进自己的项目。

我设置了500,但每次只返回200字节,这个坑后续补上。

uuid

这个可以简单理解为通信的秘钥,要对应上设备的识别码才能操作,当时百度了好几个都没法用,可以用蓝牙连接设备查看

读写数据

蓝牙通信过程是使用byte数组传递的,而我们读写命令使用的hex指令(16位的字符串)

你可能感兴趣的:(android BluetoothKit 蓝牙开发实战 requestMtu的坑)