Android BLE设备操作之FastBle的使用

开源地址:FastBle

FastBle蓝牙快速开发框架的使用

权限申请

在文件【AndroidManifest.xml】中添加权限:蓝牙权限位置权限

java 复制代码
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

build.gradle配置

在文件【build.gradle】中引入第三方框架:FastBle

jave 复制代码
dependencies {
    api 'com.clj.fastble:FastBleLib:2.2.4'
}

代码嵌入

myBleDevice

创建蓝牙设备类 myBleDevice.java

jave 复制代码
import android.app.Activity;
import android.bluetooth.BluetoothGatt;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.Interface.myBleCommInterface;
import com.Utils.myUtils;
import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleMtuChangedCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleScanAndConnectCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.clj.fastble.scan.BleScanRuleConfig;
import com.others.MainApp;

import java.util.ArrayList;
import java.util.Arrays;

import static com.others.MainApp.NOTIFY_UUID;
import static com.others.MainApp.SERVICE_UUID;
import static java.lang.Thread.sleep;

public class myBleDevice extends Activity {
    private BleDevice bleDeviceTemp = null; //蓝牙设备
    private Context context = null;
    private String BleNameConnected = null;
    private Handler handlerDefineMessage = null;
    private myBleCommInterface mybleCommInterface = null; //接口
    private myUtils myutils;
    private Handler mHandler = null;
    private int RxdOutTimer = 0;
    private ArrayList<byte[]> rd = new ArrayList<byte[]>();
    //ArrayList<byte[]> 转 byte[]
    private static byte[] byteMerger(ArrayList<byte[]> bytes) {
        //需要处理的是一个ArrayList<byte[]> bytes
        int lengthByte = 0;
        for(byte[] by : bytes){
            lengthByte +=by.length;
        }
        byte[] allbyte = new byte[lengthByte];
        int countLength=0;
        for(byte[] by : bytes){
            System.arraycopy(by,0,allbyte,countLength,by.length);
            countLength+=by.length;
        }
        return allbyte;
    }
    /***********************************************************************************************
     * 构造函数
     * @param context
     * @param mainHandler
     * @param bleName
     */
    public myBleDevice(Context context, Handler mainHandler, final myBleCommInterface mybleCommInterface, String bleName) {
        this.context = context;
        BleNameConnected = bleName;
        handlerDefineMessage = mainHandler;
        this.mybleCommInterface = mybleCommInterface;
        myutils = new myUtils();

        mHandler = new Handler();
        Runnable r = new Runnable() {
            @Override
            public void run() {
            //由于BLE设备的20字节的首发限制,此处代码主要完成的任务是,当接受的字节流大于20字节时,
            //从机BLE设备可能会进行分包发送。比如modbus的03读取的寄存器数量过多,
            //导致响应的字节流超过了20字节,则从机设备就会进行分包发送,每包不超过20字节,
            //而接收设备则需要进行收包并进行拼接。此处代买就是实现此功能。
                if(RxdOutTimer++ > 1){ //RxdOutTimer就是接收包之间的超时计数
                    if(!rd.isEmpty()){
                        byte[] rxdBytes = byteMerger(rd);
                        //Log.d("myDebug", Arrays.toString(rxdBytes));
                        //myutils.printHexString(rxdBytes);
                        //接受到通知消息 这里需要自己创建个回调接口,或者自己定义其他的数据处理方式。
                        //把接收到的数据发送处理进行解析处理。
                        mybleCommInterface.UpdateBleReceiveData(rxdBytes);
                        rd.clear();
                    }
                    RxdOutTimer = 0;
                }
                mHandler.postDelayed(this, 100);
            }
        };

        mHandler.postDelayed(r, 100);//延时100毫秒
    }

    /***********************************************************************************************
     * 获取Ble的设备
     * @return
     */
    public BleDevice getBleDevice() {
        return bleDeviceTemp;
    }

    /***********************************************************************************************
     * 扫描和连接蓝牙
     */
    public void scanAndConnect() {
        Log.e("myDebug", "BLE开始连接");
        BleManager.getInstance().scanAndConnect(new BleScanAndConnectCallback() {
            @Override
            public void onScanStarted(boolean success) {
                // 开始扫描(主线程)
                Log.e("myDebug", "BLE开始扫描");
            }

            @Override
            public void onScanFinished(BleDevice scanResult) {
                // 扫描结束,结果即为扫描到的第一个符合扫描规则的BLE设备,如果为空表示未搜索到(主线程)
                Log.e("myDebug", "BLE扫描结束");
                if (scanResult != null) {
                    Log.e("myDebug", "BLE扫描到了");
                } else {
                    Log.e("myDebug", "BLE没扫描到");
                    Toast.makeText(context, "BLE没扫描到", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onStartConnect() {
                Log.e("myDebug", "BLE开始连接");
                // 开始连接(主线程)
            }

            @Override
            public void onConnectFail(BleException exception) {
                // 连接失败(主线程)
                Toast.makeText(context, "BLE连接失败", Toast.LENGTH_SHORT).show();
                Log.e("myDebug", "BLE连接失败");
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                // 连接成功,BleDevice即为所连接的BLE设备(主线程)
                Toast.makeText(context, "BLE连接成功", Toast.LENGTH_SHORT).show();
                Log.e("myDebug", "BLE连接成功");
                Log.e("myDebug", BleManager.getInstance().getAllConnectedDevice().size() + "");
                sendMessage(101);
                bleDeviceTemp = bleDevice;
                //设置MTU
                BleManager.getInstance().setMtu(bleDeviceTemp, 512, new BleMtuChangedCallback() {
                    @Override
                    public void onSetMTUFailure(BleException exception) {
                        // 设置MTU失败
                        Log.e("myDebug", "BLE设置MTU失败");
                    }

                    @Override
                    public void onMtuChanged(int mtu) {
                        // 设置MTU成功,并获得当前设备传输支持的MTU值
                        Log.e("myDebug", "BLE设置MTU成功,并获得当前设备传输支持的MTU值  " + mtu);
                        //启动蓝牙接收消息
                        startNotify(bleDeviceTemp);
                    }
                });
            }

            @Override
            public void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status) {
                // 连接断开,isActiveDisConnected是主动断开还是被动断开(主线程)
                Toast.makeText(context, "BLE连接断开", Toast.LENGTH_SHORT).show();
                Log.e("myDebug", "BLE连接断开");
                Log.e("myDebug", isActiveDisConnected + "");
                sendMessage(102);
            }
        });
    }

    /***********************************************************************************************
     *  蓝牙连接
     */
    public void BleConnectAction() {
        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
//                        .setServiceUuids(serviceUuids)      // 只扫描指定的服务的设备,可选
                .setDeviceName(true, BleNameConnected)   // 只扫描指定广播名的设备,可选
//                .setDeviceMac(mac)                  // 只扫描指定mac的设备,可选
//                .setAutoConnect(isAutoConnect)      // 连接时的autoConnect参数,可选,默认false
                .setScanTimeOut(10000)              // 扫描超时时间,可选,默认10秒
                .build();
        BleManager.getInstance().initScanRule(scanRuleConfig);
    }

    /***********************************************************************************************
     * 发送数据函数
     * @param WriteBytes
     */
    public void SendData(int[] WriteBytes) {
        int len = WriteBytes.length;
        byte[] outData = new byte[len];


        for (int i = 0; i < len; i++) {
            if ((WriteBytes[i] >= 128) && (WriteBytes[i] <= 255)) {
                outData[i] = (byte) ((WriteBytes[i] - 256) & 0xFF);
            } else {
                outData[i] = (byte) (WriteBytes[i] & 0xFF);
            }
        }

        BleManager.getInstance().write(
                bleDeviceTemp,
                SERVICE_UUID,
                MainApp.WRITE_UUID,
                outData,
                new BleWriteCallback() {
                    @Override
                    public void onWriteSuccess(final int current, final int total, final byte[] justWrite) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //Toast.makeText(context, "写入成功", Toast.LENGTH_SHORT).show();
                                //Log.d("myDebug", "写入成功");
                            }
                        });
                    }

                    @Override
                    public void onWriteFailure(final BleException exception) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(context, "写入失败", Toast.LENGTH_SHORT).show();
                                Log.e("myDebug", "写入失败");
                                Log.e("myDebug", String.valueOf(exception));
                            }
                        });
                    }
                });
    }

    /***********************************************************************************************
     * 发送数据函数 注意BLE发送的20字节限制,不同设备可能限制的最大发送字节数不一样,建议发送数据
     * 时自行分包发送,这样可适用于所有BLE设备。
     * @param outData
     */
    public void SendData(byte[] outData) {
        BleManager.getInstance().write(
                bleDeviceTemp,
                SERVICE_UUID,
                MainApp.WRITE_UUID,
                outData,
                new BleWriteCallback() {
                    @Override
                    public void onWriteSuccess(final int current, final int total, final byte[] justWrite) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //Toast.makeText(context, "写入成功", Toast.LENGTH_SHORT).show();
                                //Log.d("myDebug", "写入成功");
                            }
                        });
                    }

                    @Override
                    public void onWriteFailure(final BleException exception) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(context, "写入失败", Toast.LENGTH_SHORT).show();
                                Log.e("myDebug", "写入失败");
                                Log.e("myDebug", String.valueOf(exception));
                            }
                        });
                    }
                });
    }

    /***********************************************************************************************
     * 蓝牙接收数据
     * @param bleDevice
     */
    private void startNotify(BleDevice bleDevice) {
        BleManager.getInstance().notify(
                bleDevice,
                SERVICE_UUID,
                NOTIFY_UUID,
                new BleNotifyCallback() {

                    @Override
                    public void onNotifySuccess() {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //打开通知成功
                            }
                        });
                    }

                    @Override
                    public void onNotifyFailure(final BleException exception) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //打开通知失败
                            }
                        });
                    }

                    /*******************************************************************************
                     * 数据接收处理
                     * @param data
                     */
                    @Override
                    public void onCharacteristicChanged(final byte[] data) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                rd.add(data); //追加方式接收代码
                                RxdOutTimer = 0;
                            }
                        });
                    }
                });
    }
}

MainActivity

在MainActivity中调用

jave 复制代码
 protected void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
        //setTheme(R.style.AppTheme_Launcher);
        setContentView(R.layout.activity_main);
		// 获取本地蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        // 如果没有蓝牙适配器,则不支持
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        BleManager.getInstance().init(getApplication());
        BleManager.getInstance()
                .enableLog(true)
                .setMaxConnectCount(1)
                .setOperateTimeout(5000);
	//BleNameConnected 需要连接的蓝牙名称,本程序需求是连接指定蓝牙名称的的设备,其他应用可根据具体需求自行修改代码。
        mybleDevice = new myBleDevice(MainActivity.this, handlerDefineMessage, this, BleNameConnected);
        mybleDevice.BleConnectAction();
        checkPermissions(); //权限处理
}
 /***********************************************************************************************
     * 检查权限
     */
    private void checkPermissions() {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!bluetoothAdapter.isEnabled()) {
            Toast.makeText(this, getString(R.string.please_open_blue), Toast.LENGTH_LONG).show();
            return;
        }

        String[] permissions = {
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.CHANGE_WIFI_STATE,
                Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,
                Manifest.permission.WRITE_SETTINGS};
        List<String> permissionDeniedList = new ArrayList<>();

        for (String permission : permissions) {
            int permissionCheck = checkSelfPermission(permission);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                onPermissionGranted(permission);
            } else {
                permissionDeniedList.add(permission);
            }
        }
        if (!permissionDeniedList.isEmpty()) {
            String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
            requestPermissions(deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);
        }
    }
相关推荐
熊大如如3 小时前
Java 反射
java·开发语言
猿来入此小猿4 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
teacher伟大光荣且正确4 小时前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
goTsHgo4 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder4 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
pjx9875 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka
多多*5 小时前
算法竞赛相关 Java 二分模版
java·开发语言·数据结构·数据库·sql·算法·oracle
爱喝酸奶的桃酥5 小时前
MYSQL数据库集群高可用和数据监控平台
java·数据库·mysql
唐僧洗头爱飘柔95276 小时前
【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
java·spring·mybatis·springmvc·动态代理·ioc容器·视图控制器
骑牛小道士6 小时前
Java基础 集合框架 Collection接口和抽象类AbstractCollection
java