开源地址:FastBle
FastBle蓝牙快速开发框架的使用
权限申请
在文件【AndroidManifest.xml】中添加权限:蓝牙权限和位置权限
<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
dependencies {
api 'com.clj.fastble:FastBleLib:2.2.4'
}
代码嵌入
myBleDevice
创建蓝牙设备类 myBleDevice.java
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中调用
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);
}
}