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

栏目: Android · 发布时间: 6年前

内容简介:最近做一款Android与蓝牙BLE设备通讯的项目,记录下开发经验。蓝牙设备是JDY-19模块,串口透传,非常方便好用。官方教程需要创建Service进行通讯,此处需求为简单数据透传,直接在Activity中收发完成就结束,不开启服务,简单便捷。话不多说,代码伺候。一次连接需要的数据是扫描后的device对象,连接哪个设备就使用这个device对象进行后续连接

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

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

一、Android扫描BLE设备

0. 开启权限

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

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;
        }
    });
}
 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python网络编程基础

Python网络编程基础

John Goerzen / 莫迟 等 / 电子工业出版社 / 2007 / 68.00元

《Python网络编程基础》可以作为各层次Python、Web和网络程序的开发人员的参考书,在实际工作中使用书中的技术,效果更佳。一起来看看 《Python网络编程基础》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码