Android BLE通讯详解,连接JDY-19

最近做一款Android与蓝牙BLE设备通讯的项目,记录下开发经验。

蓝牙设备是JDY-19模块,串口透传,非常方便好用。官方教程需要创建Service进行通讯,此处需求为简单数据透传,直接在Activity中收发完成就结束,不开启服务,简单便捷。话不多说,代码伺候。

一、Android扫描BLE设备

0. 开启权限

    





1. 检查是否有BLE支持

    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, "您的设备不支持蓝牙BLE", Toast.LENGTH_SHORT).show();
        finish();
    }

2.检查是否有蓝牙支持

    final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        Toast.makeText(this, "您的设备不支持蓝牙", Toast.LENGTH_SHORT).show();
        finish();
    }

3.如果本地蓝牙没有开启,请求打开

    if (!mBluetoothAdapter.isEnabled()) {
        //两种方式
        //1.请求用户打开
        // 我们通过startActivityForResult()方法发起的Intent将会在onActivityResult()回调方法中获取用户的选择,比如用户单击了Yes开启,
        // 那么将会收到RESULT_OK的结果,
        // 如果RESULT_CANCELED则代表用户不愿意开启蓝牙
        Intent mIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(mIntent, REQUEST_ENABLE_BT);

        // 2.用enable()方法来开启,无需询问用户(无声息的开启蓝牙设备),这时就需要用到android.permission.BLUETOOTH_ADMIN权限。
        //mBluetoothAdapter.enable();
        // mBluetoothAdapter.disable();//关闭蓝牙
    }

4.开始扫描LE设备,这个API要求 targetSdkVersion 必须低于21 , minSdkVersion必须大于等于18

scanLeDevice(true);


private void scanLeDevice(final boolean enable) {
    if (enable) {
        // Stops scanning after a pre-defined scan period.

        //是否需要自动停止扫描
//            mHandler.postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    mScanning = false;
//                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
//                }
//            }, SCAN_PERIOD); //

        mScanning = true;
        mBluetoothAdapter.startLeScan(mLeScanCallback);
    } else {
        mScanning = false;
        mBluetoothAdapter.stopLeScan(mLeScanCallback);
    }
}

5.扫描结果

private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (Map<String, Object> item : mData) {
                    if (item.get("mac").equals(device.getAddress())) {
                        item.put("rssi",rssi);
                        adapter.notifyDataSetChanged();
                        return;
                    }
                }
                Log.i("CTLockBLE", "device found name:" + device.getName() + " mac:" + device.getAddress() + " type:" + device.getType() + " rssi:" + rssi);
                if (device.getAddress() == null) {
                    return;
                }
                if (scanRecord.length != 62 || scanRecord[20 - 6] != (byte) 0xa0) {
                    //不是透传模块
                    return;
                }
                Map<String, Object> itemData = new HashMap<>();
                itemData.put("dev",device);
                itemData.put("name", device.getName());
                itemData.put("mac", device.getAddress());
                itemData.put("type", device.getType());
                itemData.put("rssi", rssi);
                itemData.put("sr", scanRecord);
                mData.add(itemData);
                adapter.notifyDataSetChanged();
            }
        });
    }
};

6.保存扫描结果

一次连接需要的数据是扫描后的device对象,连接哪个设备就使用这个device对象进行后续连接

二、与蓝牙BLE通讯

package cn.nodemedia.ctlockble;

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.BluetoothProfile;
import android.content.Context;
import android.util.Log;

public class BLEControl {

    public interface BLEControlCallback {
        void onConnStatus(int status);
    }

    private final static String TAG = "CTBLE.BLEControl";
    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    public static String Service_uuid = "0000ffe0-0000-1000-8000-00805f9b34fb";
    public static String Characteristic_uuid_TX = "0000ffe1-0000-1000-8000-00805f9b34fb";
    public static String Characteristic_uuid_RX = "00002902-0000-1000-8000-00805f9b34fb";
    public static String Characteristic_uuid_FUNCTION = "0000ffe2-0000-1000-8000-00805f9b34fb";

    private Context mContext;
    private BluetoothDevice mDevice;
    private BluetoothGatt mBluetoothGatt;
    private BLEControlCallback mCallback;

    private int mConnectionState = STATE_DISCONNECTED;
    private boolean isSubscribe = false;

    public BLEControl(Context context, BluetoothDevice device, BLEControlCallback callback) {
        this.mContext = context;
        this.mDevice = device;
        this.mCallback = callback;
    }

    public int connect() {
        mConnectionState = STATE_CONNECTING;
        this.mBluetoothGatt = mDevice.connectGatt(mContext, true, mGattCallback);
        return this.mBluetoothGatt == null ? -1 : 0;
    }

    public void disconnect() {
        if (mBluetoothGatt != null) {
            mCallback.onConnStatus(1004);
            mBluetoothGatt.close();
        }
    }

    void deley(int ms) {
        try {
            Thread.currentThread();
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public int updateRom() {

        return 0;
    }


    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                mConnectionState = STATE_CONNECTED;
                Log.i(TAG, "Connected to GATT server.");
                Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
//                runOnUiThread(() -> );
                mCallback.onConnStatus(1000);
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                mConnectionState = STATE_DISCONNECTED;
                Log.i(TAG, "Disconnected from GATT server.");
//                runOnUiThread(() -> stateTv.setText("设备已断开"));
                mCallback.onConnStatus(1002);
            }
        }

        @Override
        // New services discovered
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d(TAG, "onServicesDiscovered received: " + status);

                for (BluetoothGattService service : mBluetoothGatt.getServices()) {
                    Log.d(TAG, "get service uuid " + service.getUuid() + " type:" + service.getType());
                    for (BluetoothGattCharacteristic gc : service.getCharacteristics()) {
                        Log.d(TAG, "get service gc uuid " + gc.getUuid());
                        for (BluetoothGattDescriptor descriptor : gc.getDescriptors()) {
                            Log.d(TAG, "get service gc descriptor uuid " + descriptor.getUuid());
                            isSubscribe = mBluetoothGatt.setCharacteristicNotification(gc, true);
                            if (isSubscribe) {
                                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                                mBluetoothGatt.writeDescriptor(descriptor);
                                mCallback.onConnStatus(1001);
                            } else {
                                Log.e(TAG, "setCharacteristicNotification error");
                                mCallback.onConnStatus(1003);
                            }

                        }
                    }
                }


            } else {
                Log.w(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        // Result of a characteristic read operation
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.d(TAG, "onCharacteristicRead received: " + status);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.d(TAG, "onCharacteristicChanged " + characteristic.getValue().length);
        }
    };
}

0.创建对象

传入Context对象,扫描后得到的device对象,当前Activity类implements BLEControl.BLEControlCallback后的 this指针

 bleControl = new BLEControl(this, mDevice, this);

1.实现事件监听器

@Override
public void onConnStatus(int status) {
    Log.d("CTBLE.CommActivity", "OnConnStatus " + status);
    runOnUiThread(() -> {
        switch (status) {
            case 1000:
                stateTv.setText("设备已连接");
                break;
            case 1001:
                stateTv.setText("设备已订阅");
                break;
            case 1002:
                stateTv.setText("设备已断开");
                break;
            case 1003:
                stateTv.setText("设备订阅失败");
                break;
            case 1004:
                stateTv.setText("设备已注销");
                break;
        }
    });
}

2.连接设备

bleControl.connect();

3.断开设备

bleControl.disconnect();

原创文章,转载请注明: 转载自贝壳博客

本文链接地址: Android BLE通讯详解,连接JDY-19

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据