Android 蓝牙 bluetoothle 开发

前段时间项目中用到了bluetoothle 方面的开发,项目结束后总结一下,开发的流程与一些思路;
主要步骤

一:注册蓝牙所需权限

二:Android 6.0 以上权限获取定位权限

三:开启蓝牙

四:注册一个专门处理蓝牙连接的服务

五:activity接收回调

一:注册蓝牙所需权限, 注意一定要注册定位定位权限,Android6.0搜索周围的蓝牙设备,需要位置权限ACCESS_COARSE_LOCATION和ACCESS_FINE_LOCATION 其中的一个,并且将手机的位置服务(定位 GPS)打开。
蓝牙连接和通讯需要获取相关的蓝牙权限BLUETOOTH和BLUETOOTH_ADMIN。
蓝牙权限是normal级权限,只需要在Manifest里面声明即可,不需要判断和处理(测试即使禁用了也不影响蓝牙连接)。

 <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
 <uses-permission android:name="android.permission.BLUETOOTH" />
 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
 <uses-feature android:name="android.bluetooth.le" android:required="true" />

二:Android 6.0 以上权限获取定位权限
位置权限是dangerous级权限,除了需要在Manifest里申请之外,还需要在代码中进行动态申请。
ACCESS_COARSE_LOCATION通过WiFi或移动基站获取粗略定位(误差在30~1500米),ACCESS_FINE_LOCATION为GPS精确定位(精度10米以内)。

private void mayRequestLocation() {
        if (Build.VERSION.SDK_INT >= 23) {
            int checkCallPhonePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
            if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
                //判断是否需要 向用户解释,为什么要申请该权限
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION))
                    Toast.makeText(this, R.string.ble_need_location, Toast.LENGTH_LONG).show();
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
                return;
            } else {

            }
        } else {

        }
    }

三:开启蓝牙

   Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableBtIntent, REQUEST_ENABLE);

四:注册一个专门处理蓝牙连接的服务

<service android:name=".ble_server.BLEService" />

import android.app.Service;
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.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;

public class BLEService extends Service {
 private final static String TAG = "BluetoothLeService";
    public final static String ACTION_GATT_CONNECTION_NOFIND =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTION_NOFIND";//蓝牙未找到
    public final static String ACTION_GATT_CONNECTION_FAIL =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTION_FAIL";//蓝牙连接错误
    public final static String ACTION_GATT_CONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";//蓝牙已连接
    public final static String ACTION_GATT_DISCONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";//蓝牙断开
    public final static String ACTION_GATT_SERVICES_DISCOVERED =
            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";//发现服务,发现可用服务方可判断该蓝牙可用;
    public final static String ACTION_DATA_AVAILABLE =
            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";//接收到Notify通知或者接收到对方发送的内容
    public final static String EXTRA_DATA =
            "com.example.bluetooth.le.EXTRA_DATA";//intent回调name
    public final static String ACTION_WRITE_SUCCESSFUL =
            "com.example.bluetooth.le.WRITE_SUCCESSFUL";//发送成功,但是感觉不太靠谱,就是测试发现返回发送成功,对方扔未收到,不过正常流程就是如此
    public final static String ACTION_WRITE_FAIL =
            "com.example.bluetooth.le.WRITE_FAIL";//发送失败
    public final static String ACTION_GATT_SERVICES_NO_DISCOVERED =
            "com.example.bluetooth.le.GATT_SERVICES_NO_DISCOVERED";//未发现可用服务
    public final static String SEND_DATA_TIMEOUT =
            "com.example.bluetooth.le.SEND_DATA_TIMEOUT";//发送超时
    public final static String SEND_DATA_FAIL =
            "com.example.bluetooth.le.SEND_DATA_FAIL";//发送失败
    public final static String SET_MTU_RESULT =
            "com.example.bluetooth.le.SET_MTU_RESULT";//MTU设置返回
    String ecServerId = "0000FFF0-0000-1000-8000-00805F9B34FB";//我们所需服务,此处需要注意,该值需要结合对方蓝牙设备厂商的规约使用
    String ecWriteCharacteristicId = "0000FFF2-0000-1000-8000-00805F9B34FB";//服务中可用的特征值,依赖于对蓝牙读写的特征值的值;
    String ecReadCharacteristicId = "0000FFF1-0000-1000-8000-00805F9B34FB";//服务中可用的特征值,依赖于对蓝牙读写的特征值的值;
    private BluetoothGattCharacteristic mNotifyCharacteristic;//Notify通知特征值,通常通过该特征值接收对方发送的指令,然后有部分会通过专门约定一个read读的特征值,具体要看真实应用场景
    private BluetoothGattCharacteristic mWriteCharacteristic;//写如特征值,用于发送指令

     public class LocalBinder extends Binder {
        public BLEService getService() {
            return BLEService.this;
        }
    }

    private final IBinder mBinder = new LocalBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        offBLECallBack();
        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();
        }
        if (bluetoothGatt != null)
            bluetoothGatt.close();
        bluetoothGatt = null;
        Log.e(TAG, "关闭蓝牙服务");
        return super.onUnbind(intent);
    }
}
    BluetoothAdapter bluetoothAdapter = null;
    BluetoothGatt bluetoothGatt = null;
    BluetoothManager bluetoothManager;

    public int bluetoothInit() {//初始化蓝牙
//此处适用于蓝牙连接未断开,重新获取蓝牙,此处我用不上,但也做个记录,有需要的可以启用
//        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
//        for (BluetoothDevice device : bluetoothManager.getConnectedDevices(7)) {
//            Log.e("Bluetoothle Connection", "ConnectedDevices:" + device.getName());
//            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//                bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback, TRANSPORT_LE);
//            } else {
//                bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback);
//            }
//        }

        if (bluetoothAdapter == null)
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if (bluetoothAdapter == null) {
            //设备不支持蓝牙
            return 1;
        }
        if (!isLocServiceEnable(this)) {
            //定位功能开关未开启
            return 2;
        }
        if (!getBluetoothAdapterState()) {
            openBluetoothAdapter();
            //bluetooth is off
            return 3;
        }
        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();
        }
        return 0;
    }
     boolean getBluetoothAdapterState() {
        if (bluetoothAdapter == null) return false;
        return bluetoothAdapter.isEnabled();
    }

    private boolean isLocServiceEnable(Context context) {
        LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        return gps || network;
    }

    void openBluetoothAdapter() {
        if (bluetoothAdapter != null) {
            bluetoothAdapter.enable();
        }
    }
     public boolean isConnect = false;//连接状态,找到读写服务才算正式连接成功;
    String BleName = "";
    CountDownTimerUtils mLeScanCountDown;//定时器工具类,此处就不贴代码,自行取我的文章中取

    public void connect(String BleName) {
        this.BleName = BleName;
        if (mLeScanCountDown != null) {
            mLeScanCountDown.cancel();
        }
        mLeScanCountDown = CountDownTimerUtils
                .getCountDownTimer();
        mLeScanCountDown.setMillisInFuture(1000 * 20)
                .setFinishDelegate(new CountDownTimerUtils.FinishDelegate() {
                    @Override
                    public void onFinish() {
                        if (!isConnect) {//20秒内未连接成功 1:停止搜索 2:通知activity连接失败
//                            mBLEScanner.stopScan(mScanCallback);
                            bluetoothAdapter.stopLeScan(mLeScanCallback);
                            broadcastUpdate(ACTION_GATT_CONNECTION_NOFIND, null);
                            offBLECallBack();
                        }
                    }
                }).start();
        isBLECallBack = true;//开启回调
        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        for (BluetoothDevice device : bluetoothManager.getConnectedDevices(7)) {//此处为7,具体已经忘却了,但大抵就是搜索BluetoothLe设备
            Log.e(TAG, "ConnectedDevices:" + device.getName());
            if (device.getName().equals(BleName))
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback, TRANSPORT_LE);
                } else {
                    bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback);
                }
        }
        if (bluetoothGatt == null)
            bluetoothAdapter.startLeScan(mLeScanCallback);
//。      感觉这个方法搜索会慢一点,但也做个记录;
//        mBLEScanner = bluetoothAdapter.getBluetoothLeScanner();
//        mBLEScanner.startScan(mScanCallback);

    }
    BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {

                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                    String deviceName = device.getName();
                    Log.i(TAG, "Connection deviceName" + device.getName());
                    //此处需要可以将搜索到的蓝牙回调给activity,我的项目中用不懂,需要自己去开发,逻辑也是跟其他回调一样;
                    if (!Utils.isEmpty(device.getName()) && deviceName.equals(BleName)) {//根据蓝牙名称连接设备
                        if (mLeScanCountDown != null) {//关闭超时,也可以在发现服务后关闭超时
                            mLeScanCountDown.cancel();
                        }
                        bluetoothAdapter.stopLeScan(mLeScanCallback);
                        Log.i(TAG, "停止搜索 搜索到匹配蓝牙 " + deviceName + " Address:" + device.getAddress());
                        isBLECallBack = true;//开启通知
                        /**
                         * 其中TRANSPORT_LE参数是设置传输层模式
                         * 传输层模式有三种TRANSPORT_AUTO 、TRANSPORT_BREDR 和TRANSPORT_LE。
                         * 如果不传默认TRANSPORT_AUTO,6.0系统及以上需要使用TRANSPORT_LE这种传输模式,
                         * 具体为啥,我也不知道,我猜是因为Android6.0及以上系统重新定义了蓝牙BLE的传输模式必须使用TRANSPORT_LE这种方式吧。
                         */
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback, TRANSPORT_LE);
                        } else {
                            bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback);
                        }
                    }
                }
            };
             BluetoothLeScanner mBLEScanner;
    ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            BluetoothDevice device = result.getDevice();
            String deviceName = device.getName();
            Log.i("Bluetoothle Connection", "deviceName" + device.getName());
            if (!KHDataUtils.isEmpty(device.getName()) && deviceName.equals(BleName)) {//根据蓝牙名称连接设备
                if (mLeScanCountDown != null) {
                    mLeScanCountDown.cancel();
                }
                mBLEScanner.stopScan(this);
                Log.i(TAG, "停止搜索 搜索到匹配蓝牙 " + (KHDataUtils.isEmpty(deviceName) ? "null name" : deviceName) + " Address:" + device.getAddress());
                isBLECallBack = true;//开启通知
                /**
                 * 其中TRANSPORT_LE参数是设置传输层模式
                 * 传输层模式有三种TRANSPORT_AUTO 、TRANSPORT_BREDR 和TRANSPORT_LE。
                 * 如果不传默认TRANSPORT_AUTO,6.0系统及以上需要使用TRANSPORT_LE这种传输模式,
                 * 具体为啥,我也不知道,我猜是因为Android6.0及以上系统重新定义了蓝牙BLE的传输模式必须使用TRANSPORT_LE这种方式吧。
                 */
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback, TRANSPORT_LE);
                } else {
                    bluetoothGatt = device.connectGatt(BLEService.this, false, bluetoothGattCallback);
                }

            }

        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }
    };
BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            Log.e(TAG, "onConnectionStateChange status=" + status + "|" + "newState=" + newState);
            if (status != BluetoothGatt.GATT_SUCCESS) { //连接失败
                isConnect = false;
                broadcastUpdate(ACTION_GATT_CONNECTION_FAIL, null);
            }
            if (newState == BluetoothProfile.STATE_CONNECTED) { //连接成功
                Log.i(TAG, "已连接到GATT服务器,正在尝试启动服务发现"); 
                broadcastUpdate(ACTION_GATT_CONNECTED, null);
                bluetoothGatt.discoverServices();// 尝试在成功连接后发现服务。
            }
            if (newState == BluetoothProfile.STATE_DISCONNECTED) { //连接断开
                isConnect = false;
                if (bluetoothGatt != null) {
                    Log.e(TAG,"Bluetoothle Connection 关闭蓝牙连接");
                    bluetoothGatt.close();
                    bluetoothGatt = null;
                }
                broadcastUpdate(ACTION_GATT_DISCONNECTED, null);
                offBLECallBack();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            bluetoothGatt = gatt;
            List<BluetoothGattService> bluetoothGattServices = gatt.getServices();
            if (bluetoothGattServices != null) {
                for (BluetoothGattService item : bluetoothGattServices) {
                    Log.e(TAG, "UUID=:" + item.getUuid().toString());
                }
            }
            BluetoothGattService service = gatt.getService(UUID.fromString(ecServerId));
            if (service == null) {
                Log.e("Bluetoothle service", "未找到定制服务");
                return;
//                isConnect = false;
//                broadcastUpdate(ACTION_GATT_SERVICES_NO_DISCOVERED, null);
//                offBLECallBack();
//                closeBLEConnection();

            }
            //找到服务,继续查找特征值
            mNotifyCharacteristic = service.getCharacteristic(UUID.fromString(ecReadCharacteristicId));
            mWriteCharacteristic = service.getCharacteristic(UUID.fromString(ecWriteCharacteristicId));

            if (mNotifyCharacteristic != null && mWriteCharacteristic != null) {
                isConnect = true;
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED, null);
                //使能Notify
                notifyBLECharacteristicValueChange(ecServerId, ecReadCharacteristicId);

//心跳监听,按需启用
//                new Handler(Looper.getMainLooper()).post(new Runnable() {//开始监听心跳
//                    @Override
//                    public void run() {
//                        if (mHeartBeatTimeOut != null) {//清理上次的倒计时
//                            mHeartBeatTimeOut.cancel();
//                        } else {
//                            //创建一个1分钟的倒计时,一分钟内未监听到蓝牙,主动断开
//                            mHeartBeatTimeOut = CountDownTimerUtils
//                                    .getCountDownTimer();
//                        }
//                        mHeartBeatTimeOut.setMillisInFuture(1000 * 60)
//                                .setFinishDelegate(new CountDownTimerUtils.FinishDelegate() {
//                                    @Override
//                                    public void onFinish() {
//                                        Log.i("心跳", "心跳超时,关闭蓝牙");
//                                        closeBLEConnection();
//                                    }
//                                }).start();
//                    }
//                });



                new Thread(() -> {
                    try {
                        Thread.sleep(200);
                        setMtu(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }).start();//设置MTU需要隔一段时间后,否则会设置失败;
            }
            if (mWriteCharacteristic == null || mNotifyCharacteristic == null) //适配没有可用特征值
            {
                isConnect = false;
                broadcastUpdate(ACTION_GATT_CONNECTION_FAIL, null);
                offBLECallBack();
                closeBLEConnection();
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            byte[] bytes = characteristic.getValue();
            if (bytes != null) {
                Log.e("Bluetoothle receive", "读取成功[hex]:" + bytesToHexString(bytes));
                //initFrameAssembly(bytes);//对接收到的数据进行处理,如因mtu原因指令被分包,或者两包粘在一起
            }
        }

//        @Override
//        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//            通过读取特征值接收指令消息,我用的是notify通知接收,所以屏蔽,可根据实际启用
//            super.onCharacteristicRead(gatt, characteristic, status);
//            byte[] bytes = characteristic.getValue();
//            if (bytes != null) {
//                Log.e("bluetoothle receive", "读取成功[hex]:" + bytesToHexString(bytes));
//                initFrameAssembly(bytes);
//            }
//        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.e(TAG, "sendMsg success " + status);
            //感觉不够靠谱,所以没有使用
            super.onCharacteristicWrite(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {

            } else {

            }

        }


        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
            if (BluetoothGatt.GATT_SUCCESS == status) {
                Log.e("Bluetoothle Mtu", "onMtuChanged success MTU = " + mtu);
                if (mtu - 7 > sendSize)
                    sendSize = mtu - 7;
            } else {
                Log.e("Bluetoothle Mtu", "onMtuChanged fail ");
            }
            broadcastUpdate(SET_MTU_RESULT, null);
        }
    };
/**
     * 读使能
     *
     * @param serviceId
     * @param characteristicId
     * @return
     */
    boolean notifyBLECharacteristicValueChange(String serviceId, String characteristicId) {
        BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(serviceId));
        if (service == null) {
            return false;
        }
        BluetoothGattCharacteristic characteristicRead = service.getCharacteristic(UUID.fromString(characteristicId));
        boolean res = bluetoothGatt.setCharacteristicNotification(characteristicRead, true);
        if (!res) {
            return false;
        }
        for (BluetoothGattDescriptor dp : characteristicRead.getDescriptors()) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothGatt.writeDescriptor(dp);
        }
        return true;
    }
 public void writeData(byte[] data) {//实际下发指令消息的地方
        if (bluetoothGatt == null)
            return;
        BluetoothGattService service = bluetoothGatt.getService(UUID.fromString(ecServerId));
        if (service == null)
            return;
        BluetoothGattCharacteristic characteristicWrite = service.getCharacteristic(UUID.fromString(ecWriteCharacteristicId));
        if (characteristicWrite == null) {
            Log.d(TAG, "sendMsg: writeData " + "特征值为空 " + HexStrUtil.bytesToHexString(data));
        }
        characteristicWrite.setValue(data);
        if (bluetoothGatt.writeCharacteristic(characteristicWrite)) {
            Log.d(TAG, "sendMsg: writeData " + "下发帧数据: " + HexStrUtil.bytesToHexString(data));
            broadcastUpdate(ACTION_WRITE_SUCCESSFUL, data);
        } else {
            Log.e(TAG, "sendMsg: writeData " + "下发帧数据失败: " + HexStrUtil.bytesToHexString(data));
            broadcastUpdate(ACTION_WRITE_FAIL, data);
        }
    }

 int sendSize = 20;//分包长度大小,此值可以在设置MTU后根据MTU值设置;

    public void sendData(byte[] sendMsgBytes) {
        byte[] subpackage = null;
        int index = 0;
        for (int i = 0; i < sendMsgBytes.length; i++) {
            if (index == 0) {
                subpackage = new byte[sendMsgBytes.length - i < sendSize ? sendMsgBytes.length - i : sendSize];
            }
            subpackage[index] = sendMsgBytes[i];
            index = index + 1;
            if (index == sendSize || i + 1 == sendMsgBytes.length) {
                byte[] finalSubpackage = subpackage;
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                writeData(finalSubpackage);
                index = 0;
            }
        }


    }
     HashMap<String, CountDownTimerUtils> replyCountDownTimer;

    public void sendMsg(byte[] sendMsgBytes) {//此处时为了防止发送的指令没有返回相应的回复指令,不需要的可用replyMsg(byte[] sendMsgBytes)
        if (sendMsgBytes.length > sendSize) {

            sendData(sendMsgBytes);

        } else {
            writeData(sendMsgBytes);
        }
        if (replyCountDownTimer == null)
            replyCountDownTimer = new HashMap<>();

        int functionCode = FunctionCode.getReplyFunctionCode(sendMsgBytes[4] & 0xff);//根据下发指令的code获取回复指令的对应code;例如 发0x01 回复0x81 ,记得在收到指令消息后删掉对应的replyCountDownTimer
        if (functionCode == 0)
            return;
        CountDownTimerUtils mCountDown = CountDownTimerUtils
                .getCountDownTimer();
        mCountDown.setMillisInFuture(1000 * 5)
                .setFinishDelegate(new CountDownTimerUtils.FinishDelegate() {
                    @Override
                    public void onFinish() {
                        broadcastUpdate(SEND_DATA_TIMEOUT, sendMsgBytes);
                    }
                }).start();
        if (replyCountDownTimer.containsKey(functionCode + ""))
            replyCountDownTimer.get(functionCode + "").cancel();
        replyCountDownTimer.put(functionCode + "", mCountDown);
    }
     public void replyMsg(byte[] replyMsgBytes) {
        if (replyMsgBytes.length > sendSize) {
            sendData(replyMsgBytes);
        } else {
            writeData(replyMsgBytes);
        }
    }
void setMtu(int v) {
        if (bluetoothGatt != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            bluetoothGatt.requestMtu(v);
        }
    }

    boolean isBLECallBack = false;//是否回调统一开关
    public void onBLECallBack() {
        Log.e(TAG, "Connection: offBLECallBack 接收监听回调");
        isBLECallBack = true;
    }

    public void offBLECallBack() {
        Log.e(TAG, "Connection: offBLECallBack 取消监听回调");
        isBLECallBack = false;
    }
    private void broadcastUpdate(final String action, byte[] data) {
        if (isBLECallBack) {
            final Intent intent = new Intent(action);
            if (data != null)
                intent.putExtra(EXTRA_DATA, data);
            sendBroadcast(intent);
        }

    }
String bytesToHexString(byte[] bytes) {
        if (bytes == null) return "";
        StringBuilder str = new StringBuilder();
        for (byte b : bytes) {
            str.append(String.format("%02X", b));//每个字节用空格隔开
        }
        return str.toString();
    }

五:activity中bindserver 并接收回调
bindserver

        startWaiting("蓝牙连接中");
        Intent gattServiceIntent = new Intent(this, BLEService.class);
        bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
        if (mGattUpdateReceiver != null)
            registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
        initBleMenu();

在bindserver成功后初始化蓝牙

// Code to manage Service lifecycle.
    private final ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            mBLEService = ((BLEService.LocalBinder) service).getService();
            Connection();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBLEService = null;
        }
    };
     void Connection() {
        startWaiting("蓝牙连接中");
        int res = mBLEService.bluetoothInit();
        if (res == 1) {
            KHToast.warning("该设备不支持蓝牙");
            finishEx();
            return;
        }
        if (res == 2) {
            KHToast.warning("定位功能未开启");
            finishEx();
            return;
        }
        if (res == 3) {
            KHToast.warning("蓝牙未开启");
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE);
            return;
        }
        mBLEService.connect("蓝牙名称");
        //我的项目是需要连接已知的蓝牙名称的设备,如果需要返回搜索到的蓝牙列表,需要在BLEService中通过BluetoothAdapter.LeScanCallback将名称返回,并创建一个arrayList;
    }

声明IntentFilter对象

    private static IntentFilter makeGattUpdateIntentFilter() {
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BLEService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BLEService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(BLEService.ACTION_GATT_SERVICES_DISCOVERED);
        intentFilter.addAction(BLEService.ACTION_DATA_AVAILABLE);
        intentFilter.addAction(BLEService.ACTION_WRITE_SUCCESSFUL);
        intentFilter.addAction(BLEService.ACTION_GATT_SERVICES_NO_DISCOVERED);
        intentFilter.addAction(BLEService.ACTION_GATT_CONNECTION_NOFIND);
        intentFilter.addAction(BLEService.SEND_DATA_TIMEOUT);
        intentFilter.addAction(BLEService.SET_MTU_RESULT);

        return intentFilter;
    }

接收回调

BLEService mBLEService;
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (BLEService.ACTION_GATT_SERVICES_NO_DISCOVERED.equals(action)) {
                Log.i("BluetoothLeService", " Connection 连接失败:特征码未找到 主动断开蓝牙");
                mBLEService.closeBLEConnection();
            } else if (BLEService.ACTION_GATT_SERVICES_NO_DISCOVERED.equals(action)) {
                Log.i("BluetoothLeService", "连接失败:服务未找到 主动断开蓝牙");
                mBLEService.closeBLEConnection();
            } else if (BLEService.ACTION_GATT_CONNECTION_NOFIND.equals(action)) {
               Log.i("BluetoothLeService","连接失败:蓝牙未找到");
            } else if (BLEService.ACTION_GATT_CONNECTED.equals(action)) {
                Log.i("BluetoothLeService","连接成功:无特征码");
            } else if (BLEService.ACTION_GATT_DISCONNECTED.equals(action)) {
               Log.i("BluetoothLeService","蓝牙断开连接");
            } else if (BLEService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                Log.i("BluetoothLeService","连接成功");
            } else if (BLEService.SET_MTU_RESULT.equals(action)) {
                 Log.i("BluetoothLeService","MTU设置成功");
            } else if (BLEService.ACTION_DATA_AVAILABLE.equals(action)) {//收到消息
                final byte[] receiveData = intent.getByteArrayExtra(BLEService.EXTRA_DATA);
              Log.i("BluetoothLeService","收到消息");

            } else if (BLEService.ACTION_WRITE_SUCCESSFUL.equals(action)) {
                Log.i("BluetoothLeService", "Write Finish");
            } else if (BLEService.SEND_DATA_TIMEOUT.equals(action)) {
                final byte[] retransmissionData = intent.getByteArrayExtra(BLEService.EXTRA_DATA);
                Log.v("BluetoothLeService", "回复超时 重新发送");
                int functionCode = retransmissionData[4] & 0xff;
                if (functionCode == LOGIN_APP2PILE) {
                    loginNum = loginNum + 1;
                    if (loginNum == 7) {
                        loginNum = 0;
                        mBLEService.closeBLEConnection();
                    } else {
                        mBLEService.sendMsg(retransmissionData);
                    }
                } else {
                    mBLEService.sendMsg(retransmissionData);
                }
            }
        }
    };

在有需要时候offBLECallBack取消监听回调

if (mBLEService != null) {
    mBLEService.offBLECallBack();
}

先总结至此,因为都是从项目中的代码摘出来的,可能存在一些错误,但步骤上应该是没有问题的;

未解决的问题:当BLEService unbind时会将已连接的蓝牙断开,偶尔会出现实际没断开的情况,坑爹的是:断开和未断开所经历的流程都是一样的,就是偶尔会出现,而且只有关闭蓝牙或用系统的杀死进程才会释放连接。因为对项目影响也不大,后续也就没有过于纠结于此,但在此还是希望有相关处理经验的大神能够分享一下原因和解决办法;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值