Android之BLE(低功耗)蓝牙开发

       前段时间由于项目需要,针对部分热敏蓝牙打印机做了开发,本来刚开始是要用佳博的,结果开发完了说要换成汉印的打印机(此时内心一万只草泥马奔腾而过)。好了,言归正传。既然是蓝牙打印机,那么首先要做的就是进行蓝牙开发。先贴一个别人推荐的一个开源库:https://github.com/Jasonchenlijian/FastBle  话说在15年的时候有接触过原生的蓝牙开发,但是那时候并没有运用到项目中,当时给我的一个感觉就是再也不要做这个玩意儿了。没想到从今年(2019年)开始,一直在做这方面的项目,为了养家糊口只能硬着头皮上了。各种Google各种百度,最后还是没搞明白,那就放弃吧(怎么阔能,我是那么容易放弃的人吗(●'◡'●))。最后还是得感谢老天眷顾,我朋友他们也都在做这个,那就一起约个饭出来聊波技术咯~

    其实对于蓝牙开发,最难的不是网上能找到的那些东西,它的一个关键点就是它需要的那几个UUID怎么获取?从何而来?同样这也是困惑我良久的一个问题。(serviceUuid、 writeCharactUuid 、 notifyCharactUuid 这三个)。我问了好多人他们都说不知道,实际上这个应该是厂家那边应该提供过来的,但是厂家不是技术,他们根本都不知道这是什么玩意儿,好吧 ,我跪了。那是不是真的没有办法了?并不是,虽然我的办法有点不太靠谱,但是对于菜的要死又无知的自己来说,当然要抱着试一试的态度咯。

连接成功后拿到UUID集合然后进行遍历,将遍历得到的这些UUID一个一个赋值去试,终于皇天不负有心人,守得云开见月明,成功啦。o(* ̄▽ ̄*)ブ(PS:这么长时间的头发总算没有白掉)。

下面介绍一下完整步骤。

首先,清单文件中给权限(6.0以上一定要加定位权限):


<!-- 使用蓝牙的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 扫描蓝牙设备或者操作蓝牙设置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--模糊定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--精准定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

还有要添加

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

 <service android:name="com.inuker.bluetooth.library.BluetoothService" />

然后就根据之前贴出的开源库进行开发就好了,我在这里贴一个工具类:

public class BleUtil {
    private static final String TAG = "BleUtil-->";
    private static BleUtil bleUtil;
    public List<BleDevice> bleDevices;
    private OnBleListener listener;
    private String uuid_service = "自己获取的";
    //接受数据特征UUID
    private String uuid_characteristic_receive = "自己获取的";
    //发送数据特征UUID(视情况而定,本人不需要发送数据功能)
//    private String uuid_characteristic_send = "自己获取的";
    private boolean isStandByBle;
    private boolean isEnableBle;
    private Context context;
    private Handler handler = new Handler(Looper.getMainLooper());
    private final int START_SCAN = 100;
    private final int RESET_CONNECT = 101;
//    private final UUID[] serviceUuids;
    private BleDevice connectedBleDevice;
    private BleScanRunnable bleScanRunnable;
    private BleResetConnectRunnable bleConnectRunnable;
    private BleManager bleManager;
    private BleConnectedRunnable bleConnectedRunnable;
    private boolean isResetConnect = false;
    private boolean isScaning;
    private final ReturnTimeOutRunnable returnTimeOutRunnable;
    private String currentData = "";
    private final ReceiveDataRunnable receiveDataRunnable;

    private BleUtil(Context context) {
        this.context = context.getApplicationContext();
        bleManager = BleManager.getInstance();
        isStandByBle = bleManager.isSupportBle();
        isEnableBle = bleManager.isBlueEnable();
//        //根据指定的UUID扫描特定的设备
//        UUID serviceUuid = UUID.fromString(uuid_service);
//        serviceUuids = new UUID[]{serviceUuid};
        bleScanRunnable = new BleScanRunnable();
        bleConnectRunnable = new BleResetConnectRunnable();
        bleConnectedRunnable = new BleConnectedRunnable();
        returnTimeOutRunnable = new ReturnTimeOutRunnable();
        receiveDataRunnable = new ReceiveDataRunnable();
    }

    public static BleUtil getInstance(Context context) {
        if (bleUtil == null) {
            synchronized (BleUtil.class) {
                if (bleUtil == null) {
                    bleUtil = new BleUtil(context);
                }
            }
        }
        return bleUtil;
    }


    public void startBle() {
        if (!isStandByBle) {
            Toast.makeText(context, "该设备不支持蓝牙功能", Toast.LENGTH_SHORT).show();
            return;
        }
        bleDevices = new ArrayList<>();
        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
//                .setServiceUuids(serviceUuids)
//                .setAutoConnect(true)
//                .setDeviceMac("连接到的蓝牙MAC地址")
                .setScanTimeOut(15000)
                .build();
        bleManager.initScanRule(scanRuleConfig);
        if (!bleManager.isBlueEnable()) {
            bleManager.enableBluetooth();
        }
        handler.postDelayed(bleScanRunnable, 2 * 100);
    }

    private void startScan() {
        if (isResetConnect && listener != null) {
            listener.onResetConnect();
            isResetConnect = false;
        }
        bleManager.scan(new BleScanCallback() {

            @Override
            public void onScanFinished(List<BleDevice> list) {
                isScaning = false;
            }

            @Override
            public void onScanStarted(boolean b) {
                isScaning = true;
            }

            @Override
            public void onScanning(BleDevice bleDevice) {
                Log.e(TAG, bleDevice.getName() + "        " + bleDevice.getMac());
                bleDevices.add(bleDevice);
                if (listener != null) {
                    listener.onScaningBle(bleDevice);
                }
            }
        });
    }
//停止扫描
    public void stopScan() {
        if (isScaning)
            bleManager.cancelScan();
    }
//断开连接
    public void disConnect() {
        handler.removeCallbacks(bleScanRunnable);
        handler.removeCallbacks(bleConnectedRunnable);
        handler.removeCallbacks(bleConnectRunnable);
        handler.removeCallbacks(returnTimeOutRunnable);
        handler.removeCallbacks(receiveDataRunnable);
        if (connectedBleDevice != null && bleManager.isConnected(connectedBleDevice)) {
            stopIndicate();
            bleManager.clearCharacterCallback(connectedBleDevice);
            bleManager.disconnect(connectedBleDevice);
        }
    }
//判断是否连接
    public boolean isConnected() {
        if (connectedBleDevice == null) {
            return false;
        } else {
            return bleManager.isConnected(connectedBleDevice);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void connectBle(BleDevice bleDevice) {
        stopScan();
        bleManager.connect(bleDevice, new BleGattCallback() {
            @Override
            public void onStartConnect() {

            }

            @Override
            public void onConnectFail(BleDevice bleDevice, BleException e) {
                //连接失败,需做好重连措施
                connectedBleDevice = bleDevice;
                handler.postDelayed(bleConnectRunnable, 200);
                Log.e("连接失败:", e.toString());
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt bluetoothGatt, int i) {
                Log.e(TAG, "连接成功");
                receiveData(bleDevice);
                connectedBleDevice = bleDevice;
                handler.postDelayed(bleConnectedRunnable, 200);
                //设备的服务信息及特征信息
//                List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
//                for (BluetoothGattService service : serviceList) {
//                    UUID uuid_service = service.getUuid();
//                    Log.e(TAG, "onConnectSuccess:service---- " + uuid_service);
//                    List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
//                    for (BluetoothGattCharacteristic characteristic : characteristicList) {
//                        UUID uuid_chara = characteristic.getUuid();
//                        Log.e(TAG, "onConnectSuccess: chara" + uuid_chara);
//                    }
//                }
            }

            @Override
            public void onDisConnected(boolean b, BleDevice bleDevice, BluetoothGatt bluetoothGatt, int i) {
                //连接断开,需区分异常断开与主动断开(b=true),异常断开的重连操作,需做好时间间隔操作,否者可能导致长时间连接不上的情况
                if (b) {
                    Log.e(TAG, "正常断开");
                    bleManager.clearCharacterCallback(bleDevice);
                    bluetoothGatt.connect();
                    bleManager.clearCharacterCallback(connectedBleDevice);
                    if (listener != null) {
                        listener.onDisConnected();
                    }
                } else {
                    isResetConnect = true;
                    Log.e(TAG, "异常断开");
                    if (!bleManager.isBlueEnable()) {
                        bleManager.enableBluetooth();
                        handler.postDelayed(bleScanRunnable, 200);
                    } else {
                        //重连
                        handler.postDelayed(bleConnectRunnable, 200);
                    }
                }
            }
        });
    }
//连接蓝牙
    public void connectBle(String MAC) {
        bleManager.connect(MAC, new BleGattCallback() {
            @Override
            public void onStartConnect() {

            }

            @Override
            public void onConnectFail(BleDevice bleDevice, BleException e) {
                //连接失败,需做好重连措施
                connectedBleDevice = bleDevice;
                handler.postDelayed(bleConnectRunnable, 200);
                Log.e("连接失败:", e.toString());
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                Log.e(TAG, "连接成功");
                receiveData(bleDevice);
                connectedBleDevice = bleDevice;
                handler.postDelayed(bleConnectedRunnable, 200);
            }

            @Override
            public void onDisConnected(boolean b, BleDevice device, BluetoothGatt gatt, int status) {
                //连接断开,需区分异常断开与主动断开(b=true),异常断开的重连操作,需做好时间间隔操作,否者可能导致长时间连接不上的情况
                if (b) {
                    Log.e(TAG, "正常断开");
                    bleManager.clearCharacterCallback(device);
                    gatt.connect();
                    bleManager.clearCharacterCallback(connectedBleDevice);
                    if (listener != null) {
                        listener.onDisConnected();
                    }
                } else {
                    isResetConnect = true;
                    Log.e(TAG, "异常断开");
                    if (!bleManager.isBlueEnable()) {
                        bleManager.enableBluetooth();
                        handler.postDelayed(bleScanRunnable, 200);
                    } else {
                        //重连
                        handler.postDelayed(bleConnectRunnable, 200);
                    }
                }
            }
        });

    }
//接受数据
    private void receiveData(final BleDevice bleDevice) {
        final StringBuilder stringBuilder = new StringBuilder();
        bleManager.indicate(bleDevice,
                uuid_service,
                uuid_characteristic_receive,
                new BleIndicateCallback() {
                    @Override
                    public void onIndicateSuccess() {
                        //订阅通知成功
                        handler.postDelayed(returnTimeOutRunnable, 5 * 1000);
                        Log.e(TAG, "onIndicateSuccess: 订阅成功");
                    }

                    @Override
                    public void onIndicateFailure(BleException e) {
                        Log.e("接收数据异常------------>", e.toString());
                    }

                    @Override
                    public void onCharacteristicChanged(byte[] bytes) {
                        handler.removeCallbacks(returnTimeOutRunnable);
                        //接收到的数据
                        String s = BinaryConversionUtils.byte2hex(bytes);
                        String resultData = BinaryConversionUtils.hexString2String(s);
                        Pattern pattern = Pattern.compile("\n|\r");
                        Matcher matcher = pattern.matcher(resultData);
                        resultData = matcher.replaceAll("");
                        stringBuilder.append(resultData);
                        Log.e("接收数据成功------------>", stringBuilder.toString());
//                        Toast.makeText(context, resultData+"--", Toast.LENGTH_SHORT).show();
                        if (listener != null) {
                            if (TextUtils.isEmpty(stringBuilder.toString()) || stringBuilder.toString().contains("ERROR")) {
                                //空返回
                                handler.postDelayed(returnTimeOutRunnable, 200);
                            } else if (resultData.contains("")) {
                                //成功返回
                                currentData = resultData;
                                handler.postDelayed(receiveDataRunnable, 200);
//                                stopIndicate();
                            }
                        }
                    }
                });
    }
//发送数据
//    public void sendData(final BleDevice bleDevice, final String str) {
//        byte[] data = BinaryConversionUtils.hex2byte(str);
//        bleManager.write(bleDevice,
//                uuid_service,
//                uuid_characteristic_send,
//                data,
//                true,
//                new BleWriteCallback() {
//                    @Override
//                    public void onWriteSuccess(int current, int total, byte[] justWrite) {
//                        // 发送数据到设备成功(分包发送的情况下,可以通过方法中返回的参数可以查看发送进度)
//                        Log.e("发送数据成功------------>", str);
//                        receiveData(bleDevice);
//                        bleManager.removeWriteCallback(bleDevice, uuid_characteristic_send);
//                    }
//
//                    @Override
//                    public void onWriteFailure(BleException exception) {
//                        // 发送数据到设备失败
//                        Log.e("发送数据异常------------>", exception.toString());
//                    }
//                });
//    }

    public void stopIndicate() {
        if (connectedBleDevice != null) {
            bleManager.stopIndicate(connectedBleDevice, uuid_service, uuid_characteristic_receive);
            bleManager.removeIndicateCallback(connectedBleDevice, uuid_characteristic_receive);
        }
    }

    //扫描设备的实时回调
    public interface OnBleListener {

        //扫描结果
        void onScaningBle(BleDevice bleDevice);

        //连接成功
        void onConnected(BleDevice bleDevice);

        //异常重连
        void onResetConnect();

        //返回数据
        void onReceiveData(String data);

        //返回数据超时
        void onTimeOutReturn();

        //蓝牙正常断开
        void onDisConnected();
    }

    public void setOnBleListener(OnBleListener listener) {
        this.listener = listener;
    }

    public class BleScanRunnable implements Runnable {
        @Override
        public void run() {
            startScan();
        }
    }

    public class BleResetConnectRunnable implements Runnable {
        @Override
        public void run() {
            if (connectedBleDevice != null) {
                if (listener != null)
                    listener.onResetConnect();
                connectBle(connectedBleDevice);
            } else {
                Toast.makeText(context, "未扫描到蓝牙,请退出重连", Toast.LENGTH_SHORT).show();
            }
        }
    }

    public class BleConnectedRunnable implements Runnable {
        @Override
        public void run() {
            if (listener != null)
                listener.onConnected(connectedBleDevice);
        }
    }

    public class ReturnTimeOutRunnable implements Runnable {
        @Override
        public void run() {
            if (listener != null) {
                listener.onTimeOutReturn();
            }
        }
    }

    public class ReceiveDataRunnable implements Runnable {
        @Override
        public void run() {
            if (listener != null) {
                listener.onReceiveData(currentData);
            }
        }
    }

}

 记得添加依赖哦

到这里蓝牙连接功能结束了。效果如下(gif图传不上去,委屈大家看看图片咯~):

确实是有点丑的要死哈~ 

 注意:一定要区分是BLE(低功耗)蓝牙还是经典蓝牙

 到这里对于蓝牙开发就结束了,下篇文章将给出上文中提到的佳博和汉印两款打印机的开发历程。敲重点啦哈~如果对于获取UUID有好的方法的,可以留言讨论一下哈,互相学习嘛(*  ̄3)(ε ̄ *),本文的Demo有需要可以留下你的邮箱哟~

猜你喜欢

转载自blog.csdn.net/lzllzllhl/article/details/103902819