android蓝牙开发,通过Sbbluetooth.aar文件连接蓝牙设备并上传与解析数据

    这篇博客帮助用来帮助我们在App开发中需要连接蓝牙硬件设备接收与上传数据的,如果大家有什么不理解的或者更好的方法欢迎大家与我沟通。在这里我就不介绍蓝牙的基本知识了,有不理解的大家可以找一找。一起来看下如何使用吧。

1.使用准备

1.在项目级的build.gradle文件中加入aar文件。

implementation(name: 'Sbbluetooth', ext: "aar")

2.在清单文件中添加蓝牙权限

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/><uses-permission
    android:name="android.permission.ACCESS_MOCK_LOCATION"
    tools:ignore="MockLocation,ProtectedPermissions" />
<uses-permission
    android:name="android.permission.BLUETOOTH_PRIVILEGED"
    tools:ignore="ProtectedPermissions" />

<uses-feature
    android:name="android.hardware.bluetooth_le"
    android:required="true" />

2.开始使用

1.在自定义的Application的onCreate里面初始化

SBluetoothContext.set(this);

2.使用

1.创建ClientManager类,单例管理。

public class ClientManager {

    private static SBluetoothClient mClient;

    public static SBluetoothClient getClient() {
        if (mClient == null) {
            synchronized (ClientManager.class) {
                if (mClient == null) {
                    mClient = new SBluetoothClient(AppAplication.getInstance());
                }
            }
        }
        return mClient;
    }
}

2.在需要扫描蓝牙设备的地方使用,使用之前先判断蓝牙是否开启,如果没有开启就打开蓝牙。

if (ClientManager.getClient().isBluetoothOpened()) {
    ClientManager.getClient().openBluetooth();

}

3.搜索蓝牙设备并连接设备。

SearchRequest request = new SearchRequest.Builder()
        .searchBluetoothLeDevice(3000, 3)   // 扫BLE设备3次,每次3s
        .searchBluetoothClassicDevice(5000) // 扫经典蓝牙5s
        .searchBluetoothLeDevice(5000)      // 扫BLE设备5s
        .build();

ClientManager.getClient().search(request, searchResponse);
ClientManager.getClient().registerBluetoothBondListener(mBluetoothBondListener);

/**
 * 搜索出的设备集合
 */
private List<Map<String, String>> devices = new ArrayList<>();

//这个类是查看搜索到的设备的
private SearchResponse searchResponse = new SearchResponse() {
    @Override
    public void onSearchStarted() {

    }

    @Override
    public void onDeviceFounded(SearchResult device) {

        RBroadcast RBroadcast = new RBroadcast(device.scanRecord);

        // 定义一个装载蓝牙设备名字和地址的Map
        Map<String, String> deviceMap = new HashMap<>();

        // 过滤已配对的和重复的蓝牙设备
        if (isSingleDevice(device.device)) {
            deviceMap.put("name", device.getName() == null ? "null" : device.getName());
            deviceMap.put("address", device.getAddress());

            if (device.getName() != null && !device.getName().equals("NULL") )) {
             
                devices.add(deviceMap);
                // 把设备在列表中显示出来,
                showDevices();
                
                //如果这里知道已经找到了设备可以调用ClientManager.getClient().stopSearch();结束搜索。
            }
        }
        // 显示发现的蓝牙设备列表,这里就是个recyclerview
        mainRec.setVisibility(View.VISIBLE);

    }

    @Override
    public void onSearchStopped() {

    }

    @Override
    public void onSearchCanceled() {

    }
};

/**
 * 判断此设备是否存在
 */
private boolean isSingleDevice(BluetoothDevice device) {
    if (devices == null) {
        return true;
    }
    for (Map<String, String> mDeviceMap : devices) {
        if ((device.getAddress()).equals(mDeviceMap.get("address"))) {
            return false;
        }
    }
    return true;
}

/**
 * 监听设备配对状态变化
 */
private final BluetoothBondListener mBluetoothBondListener = new BluetoothBondListener() {
    @Override
    public void onBondStateChanged(String mac, int bondState) {
        // bondState = Constants.BOND_NONE, BOND_BONDING, BOND_BONDED
        if (bondState == BOND_BONDED) {

            Log.e("onBondStateChanged: ", "设备配对成功");

        } else if (bondState == BOND_BONDING) {
            Log.e("onBondStateChanged: ", "设备配对中");

        } else if (bondState == BOND_NONE) {
            Log.e("onBondStateChanged: ", "没有设备配对");
            Toast.makeText(ShouHuanActivity.this, "配对成功", Toast.LENGTH_LONG).show();

        }
    }
};

    /**
     * 显示搜索到的设备列表,这里就是用了个recyclerview自带的布局。你们根据自己的程序自己写
     */
    private void showDevices() {
        SimpleAdapter mSimpleAdapter = new SimpleAdapter(ShouHuanActivity.this, devices,
                android.R.layout.simple_list_item_2,
                new String[]{"name", "address"},
                new int[]{android.R.id.text1, android.R.id.text2});
        mainRec.setAdapter(mSimpleAdapter);
       
//这里是连接设备,根据设备的mac地址
ClientManager.getClient().connect(devices.get(posi).get("address"),new BleConnectResponse() {
                @Override
                public void onResponse(int code, BleGattProfile profile) {
                     
                    if (code == REQUEST_SUCCESS) {
                        
                         //连接成功,可以发送和接收数据了
                         notify();   

 


                    } else if (code == Constants.REQUEST_FAILED) {
                        //连接失败

                    } else if (code == Constants.REQUEST_TIMEDOUT) {
                        //连接超时


                    }
                }
            });
            ClientManager.getClient().registerConnectStatusListener(devices.get(posi).get("address"), mBleConnectStatusListener);


    }
    /**
     * 监听蓝牙连接状态
     */
    private final BleConnectStatusListener mBleConnectStatusListener = new BleConnectStatusListener() {

        @Override
        public void onConnectStatusChanged(String mac, int status) {
            if (status == STATUS_CONNECTED) {

            } else if (status == STATUS_DISCONNECTED) {
                Log.e("onConnectStatusChanged: ", "断开连接");
             
            }
        }
    };

 4.发送和接收数据

   private void  notify(){
        //通知接收数据
        ClientManager.getClient().notify(“设备的mac地址”, UUID.fromString(Service), UUID.fromString(character), mNotifyRsp);

    
    }
private final BleNotifyResponse mNotifyRsp = new BleNotifyResponse() {
        @Override
        public void onNotify(UUID service, UUID character, byte[] value) {
            //在这里根据service和character判断当前收到的数据是否是你需要的,如果是就
            //解析value里面的值就可以了,下面这个方法可以把值变成字符串形式
           String s = String.format(ByteUtils.byteToString(value));
             

        }

        @Override
        public void onResponse(int code) {
            if (code == Constants.REQUEST_SUCCESS) {

                Log.d("onResponse: ", "成功");

            } else {
                Log.d("onResponse: ", "失败");
               
            }


        }
    };
//这个是给设备发送数据,需要把十六进制字符串转成字节数组发送,
//当设备收到数据并给手机回复数据时,会通过上面的mNotifyRsp把数据返回给手机,咱们可以在那里
//解析数据。要注意这里写的byte[]不能超过20字节,如果超过了需要自己分成几次写。建议的办法是第一个//byte放剩余要写的字节的长度。writeNoRsp方法比普通的write快2~3倍,建议用于固件升级。
ClientManager.getClient().write(mac, UUID.fromString(Service), UUID.fromString(character), HexStringToByteArray(s), new BleWriteResponse() {
            @Override
            public void onResponse(int code) {
                Log.e("onResponse: ", "获取数据:" + code);


                if (code == REQUEST_SUCCESS) {
                    Toast.makeText(ShouHuanActivity.this, "请求发送成功", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_FAILED) {
                    Toast.makeText(ShouHuanActivity.this, "请求发送失败", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_CANCELED) {
                    Toast.makeText(ShouHuanActivity.this, "请求发送取消", Toast.LENGTH_SHORT).show();
                } else if (code == ILLEGAL_ARGUMENT) {
                    Toast.makeText(ShouHuanActivity.this, "请求参数非法", Toast.LENGTH_SHORT).show();
                } else if (code == BLE_NOT_SUPPORTED) {
                    Toast.makeText(ShouHuanActivity.this, "蓝牙不支持", Toast.LENGTH_SHORT).show();
                } else if (code == BLUETOOTH_DISABLED) {
                    Toast.makeText(ShouHuanActivity.this, "蓝牙未开启", Toast.LENGTH_SHORT).show();
                } else if (code == SERVICE_UNREADY) {
                    Toast.makeText(ShouHuanActivity.this, "服务未开启", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_TIMEDOUT) {
                    Toast.makeText(ShouHuanActivity.this, "连接超时", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_DENIED) {
                    Toast.makeText(ShouHuanActivity.this, "请求被拒绝", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_EXCEPTION) {
                    Toast.makeText(ShouHuanActivity.this, "请求报错", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_UNKNOWN) {
                    Toast.makeText(ShouHuanActivity.this, "未知请求", Toast.LENGTH_SHORT).show();
                }

            }


        });
  /**

     *

     * @param hexString

     * @return 将十六进制转换为字节数组

     */

    public static byte[] HexStringToByteArray(String hexString){

        //hexString的长度对2取整,作为bytes的长度

        int len = hexString.length()/2;

        byte[] bytes = new byte[len];

        byte high = 0;//字节高四位

        byte low = 0;//字节低四位



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

            //右移四位得到高位

            high = (byte)((hexStr.indexOf(hexString.charAt(2*i)))<<4);

            low = (byte)hexStr.indexOf(hexString.charAt(2*i+1));

            bytes[i] = (byte) (high|low);//高地位做或运算

        }

        return bytes;

    }


//当设备提供read操作时可用此方法直接获取返回值
ClientManager.getClient().read(mac, UUID.fromString(Service), UUID.fromString(character), new BleReadResponse() {
            /**
             * @param code
             * @param data
             */
            @Override
            public void onResponse(int code, byte[] data) {
                if (code == REQUEST_SUCCESS) {
                    Toast.makeText(ShouHuanActivity.this, "请求发送成功", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_FAILED) {
                    Toast.makeText(ShouHuanActivity.this, "请求发送失败", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_CANCELED) {
                    Toast.makeText(ShouHuanActivity.this, "请求发送取消", Toast.LENGTH_SHORT).show();
                } else if (code == ILLEGAL_ARGUMENT) {
                    Toast.makeText(ShouHuanActivity.this, "请求参数非法", Toast.LENGTH_SHORT).show();
                } else if (code == BLE_NOT_SUPPORTED) {
                    Toast.makeText(ShouHuanActivity.this, "蓝牙不支持", Toast.LENGTH_SHORT).show();
                } else if (code == BLUETOOTH_DISABLED) {
                    Toast.makeText(ShouHuanActivity.this, "蓝牙未开启", Toast.LENGTH_SHORT).show();
                } else if (code == SERVICE_UNREADY) {
                    Toast.makeText(ShouHuanActivity.this, "服务未开启", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_TIMEDOUT) {
                    Toast.makeText(ShouHuanActivity.this, "连接超时", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_DENIED) {
                    Toast.makeText(ShouHuanActivity.this, "请求被拒绝", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_EXCEPTION) {
                    Toast.makeText(ShouHuanActivity.this, "请求报错", Toast.LENGTH_SHORT).show();
                } else if (code == REQUEST_UNKNOWN) {
                    Toast.makeText(ShouHuanActivity.this, "未知请求", Toast.LENGTH_SHORT).show();
                }
                String s = Utils.byte2hex(data);
               



            }
        });
 /**
     * 字节数组转换为十六进制字符串
     * (非常重要)
     *
     * @param b
     *            byte[] 需要转换的字节数组
     * @return String 十六进制字符串
     */
    public static final String byte2hex(byte b[]) {
        if (b == null) {
            throw new IllegalArgumentException(
                    "Argument b ( byte array ) is null! ");
        }
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0xff);
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
        }
        return hs.toUpperCase();
    }

5:读取Rss


mClient.readRssi(MAC, new BleReadRssiResponse() {

    @Override

    public void onResponse(int code, Integer rssi) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

6.关闭Notify

mClient.unnotify(MAC, serviceUUID, characterUUID, new BleUnnotifyResponse() {

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

7.关闭Indicate

mClient.unindicate(MAC, serviceUUID, characterUUID, new BleUnnotifyResponse() {

    @Override

    public void onResponse(int code) {

        if(code == REQUEST_SUCCESS) {

        }

    }

});

 3.总结

    蓝牙连接设备时要判断好连接状态和搜索状态等与页面的关系,避免出现空指针的情况。有什么要讨论的问题可以留言呦。

 


上一篇:安卓利用fat-aar打包含有第三方aar的model


下一篇:Unity和Android混合开发