如果不了解androd ble就先学ble整个得大致通信流程,如果大致通信流程了解了,就利用封装好得 ble库,应该对你帮助很大。
android ble连接数据大致也没几个步骤,但是对于刚涉水蓝牙的小伙伴可能会一脸蒙蔽,怎么弄就是不成功,下边讲解,直接从代码中讲解
1.封装号的核心ble通讯层,这个可以解决,完整流程通讯和长时间通讯
package com.reformer.bles;
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.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import com.reformer.utils.commen.LogUtil;
import java.util.UUID;
public class Ble extends BluetoothGattCallback {
private UUID UUID_SERVICE = UUID.fromString("0000fde6-0000-1000-8000-00805f9b34fb");
private UUID UUID_SERVICE2 = UUID.fromString("0000fdeb-0000-1000-8000-00805f9b34fb");//梯控
private UUID UUID_WRITE = UUID.fromString("0000fde7-0000-1000-8000-00805f9b34fb");
private UUID UUID_INDICATE = UUID.fromString("0000fde8-0000-1000-8000-00805f9b34fb");
private UUID UUID_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private Context mCtx;
private BluetoothAdapter mBtAdapter;
private String mAddress;
private OnBleListener mListner;
private BluetoothGattCharacteristic mWriteChar;
private BluetoothGatt mBluetoothGatt;
private byte[] tempCmd2 = null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
removeMessages(1);
break;
}
}
};
public Ble(Context ctx) {
final BluetoothManager bluetoothManager = (BluetoothManager)
ctx.getSystemService(Context.BLUETOOTH_SERVICE);
mBtAdapter = bluetoothManager.getAdapter();
mCtx = ctx;
}
public boolean scanStart() {
LogUtil.d("扫描");
return mBtAdapter != null && mBtAdapter.startLeScan(null, m18LeScanCallback);
}
public void scanStop() {
if (mBtAdapter != null)//华为:G7-Ul20;CHM-00;G7-TL00;蓝牙4.0,会出现空指针异常
mBtAdapter.stopLeScan(m18LeScanCallback);
}
public boolean writeChar(byte[] bytes) {
LogUtil.d("数据写入___" + Utils.bytes2String(bytes));
if (mWriteChar == null || mBluetoothGatt == null || bytes == null)
return false;
if (bytes.length <= 20) {
return writeCharInner(bytes);
} else {
byte[] tempCmd1 = new byte[20];
for (int i = 0; i < 20; i++)
tempCmd1[i] = bytes[i];
tempCmd2 = new byte[bytes.length - 20];
for (int i = 0; i < bytes.length - 20; i++)
tempCmd2[i] = bytes[i + 20];
return writeCharInner(tempCmd1);
}
}
private boolean writeCharInner(byte[] bytes) {//写特征值
LogUtil.d("数据写入_分包__" + Utils.bytes2String(bytes));
return mWriteChar.setValue(bytes) && mBluetoothGatt.writeCharacteristic(mWriteChar);
}
public int connect(String address) {
LogUtil.d("连接");
isOk = true;
return connectGatt(address);
}
public void close() {
LogUtil.d("关闭");
isOk = false;
closeGatt();
}
private void closeGatt() {
if (mBluetoothGatt != null) {
mBluetoothGatt.disconnect();
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
if (mBluetoothGatt != null)
mBluetoothGatt = null;
}
}
if (mBtAdapter != null) {
if (mAddress != null && !mAddress.equals("")) {
BluetoothDevice device = mBtAdapter.getRemoteDevice(mAddress);
if (device != null) {
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
try {
Utils.removeBond(BluetoothDevice.class, device);//适配魅族某款手机
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
private int connectGatt(String address) {
if (!isOk)
return 400;
mAddress = address;
if (mListner != null)
mListner.onConnectStatus(1);
closeGatt();
if (mBtAdapter == null) {
return 201;
}
BluetoothDevice device = mBtAdapter.getRemoteDevice(mAddress);
if (device == null) {
return 202;
}
mBluetoothGatt = device.connectGatt(mCtx, false, this);//第一步:连接gatt:获取gatt管道
return 400;
}
private boolean isOk = false;
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
LogUtil.d("连接状态成功");
gatt.discoverServices();//第二步:gatt连接成功,发现服务
} else {
LogUtil.d("连接状态失败");
connect(mAddress);
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == 0) {//第三步:发现服务成功;获取服务,订阅特征值
LogUtil.d("连接服务成功");
BluetoothGattService service = gatt.getService(UUID_SERVICE);
mWriteChar = service.getCharacteristic(UUID_WRITE);
BluetoothGattCharacteristic mIndicateChar = service.getCharacteristic(UUID_INDICATE);
gatt.setCharacteristicNotification(mIndicateChar, true);//写入特征值改变时,通知
BluetoothGattDescriptor descriptor = mIndicateChar.getDescriptor(UUID_DESCRIPTOR);//获取修饰
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);//修饰配置
gatt.writeDescriptor(descriptor);
} else {
LogUtil.d("连接服务失败");
connect(mAddress);
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == 0 && mListner != null) {//第四步:订阅特征值成功;发送数据;交换随即密钥
LogUtil.d("订阅成功");
mListner.onReady();
mListner.onConnectStatus(0);
} else {
connect(mAddress);
}
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == 0 && mListner != null) {//第六步:写入第一包数据后睡眠,发送第二包数据
if (tempCmd2 != null) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
byte[] a = tempCmd2;
tempCmd2 = null;
writeCharInner(a);
LogUtil.d("第二包数据写入" + Utils.bytes2String(a));
}
} else {
connect(mAddress);
}
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
LogUtil.d("数据接受成功");
if (mListner != null)
mListner.onReceive(characteristic.getValue());
}
public void setOnBleListener(OnBleListener bleListener) {
mListner = bleListener;
}
public abstract static class OnBleListener {
public void onConnectStatus(int status) {
}
public void onReady() {
}
public abstract void onReceive(byte[] value);
public abstract void onScanResult(String name, String address, int rssi, byte[] mac);
}
private BluetoothAdapter.LeScanCallback m18LeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] bytes) {
LogUtil.d("device__" + device.getAddress().toString());
if (mListner == null)
return;
byte[] macTemp = new byte[9];
System.arraycopy(bytes, 18, macTemp, 0, 9);
mListner.onScanResult(device.getName(), device.getAddress(), rssi, macTemp);
}
};
}
// private ScanCallback m21ScanCallback = new ScanCallback() {
// @Override
// public void onScanResult(int callbackType, ScanResult result) {
// byte[] scanRecord = result.getScanRecord().getBytes();
// BluetoothDevice device = result.getDevice();
// int rssi = result.getRssi();
foundNewDevice(scanRecord, device, rssi);
// }
// };
2.通过ble传送数据,这个类,接受数据处理数据
package com.reformer.bles;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import com.reformer.bles.encrypt.KeyBase;
import com.reformer.bles.encrypt.KeyKeyfree;
import com.reformer.utils.commen.LogUtil;
import java.util.ArrayList;
public class Presenter {
private byte[] mMac;
private OnStateListener mOnStateListener;
private OnScanListener mOnScanListener;
private ArrayList<BleBean> mScans = new ArrayList<BleBean>();
private Ble mBle;
public int mTimeOut = 6000;//超时时间
private KeyBase mKey;
private String bytes2HexString(byte[] src) {//字节数组转16进制字符串
StringBuffer sb = new StringBuffer();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
sb.append(0);
}
sb.append(hv);
}
return sb.toString();
}
public Presenter(Context ctx) {
mKey = new KeyKeyfree();
mBle = new Ble(ctx);
mBle.setOnBleListener(new Ble.OnBleListener() {
@Override
public void onReady() {
mBle.writeChar(mKey.get1040());
}
@Override
public void onReceive(final byte[] receiveDatas) {
switch (receiveDatas[3]) {
case (byte) 4://取开门命令相关设备参数
byte[] devRand = new byte[4];//随机数
System.arraycopy(receiveDatas, 6, devRand, 0, 4);//取出随机数
mBle.writeChar(mKey.get1050(mMac, devRand));
break;
case (byte) 8:
case (byte) 9:
case (byte) 5://输出口控制
close();
if (mOnStateListener != null)
mOnStateListener.onState(receiveDatas[5]);
break;
case (byte) 6://查询外设信息
System.arraycopy(receiveDatas, 6, mMac, 0, 9);//MAC_LENGTH=9
break;
case (byte) 7://设置设备初始密钥 (预留,只是配置工具使用)
close();
if (mOnStateListener != null)
mOnStateListener.onState(300);
break;
default:
close();
break;
}
}
@Override
public void onScanResult(String name, String address, int rssi, byte[] mac) {
if (mOnScanListener != null) {
if (!Utils.containBytesFromDevLst(mac, mScans)) {//是否为扫描记录列表中的设备
final BleBean bean = new BleBean(name, address, rssi, mac);
mScans.add(bean);
mHandler.post(new Runnable() {
@Override
public void run() {
mOnScanListener.onScan(mScans, bean);
}
});
}
}
}
});
}
public void setOnScanListener(OnScanListener obdll) {
this.mOnScanListener = obdll;
}
public void setOnStateListener(OnStateListener osl) {
this.mOnStateListener = osl;
}
public void close() {
mBle.close();
mHandler.removeMessages(1);
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1://超时
removeMessages(1);
if (mOnStateListener != null)
mOnStateListener.onState(200);
close();
break;
case 2:
scanStop();
break;
}
}
};
public boolean scanStart(int time) {
scanStop();
mBle.close();
mScans.clear();//清空扫描记录列表
mHandler.removeMessages(2);
mHandler.sendEmptyMessageDelayed(2, time);
return mBle.scanStart();
}
public void scanStop() {
mBle.scanStop();
}
public void init(byte[] devPassword, byte[] phone, int time) {
mKey.init(devPassword, phone, time);
}
public void verifyData(byte[] macs) {
mHandler.sendEmptyMessageDelayed(1, mTimeOut); //超时
scanStop();
mMac = macs;
//校验mac
String address = Utils.getAddressFromMac(macs, mScans);
if (address.equals("") && mOnStateListener != null) {
mOnStateListener.onState(102);//mac不再搜索列表
return;
}
if (mOnStateListener != null) {//设置密码的动作,无需再校验其他数据
mOnStateListener.onState(mBle.connect(address));
}
}
}
3.也就是外部调用的层,方便其他人调用,也可以保证隔离开核心代码,尤其涉及保险柜,门禁,等秘密设备的加密代码,可以完整混淆
package com.reformer.bles;
import android.content.Context;
public class BleKey {
private Presenter mPresenter;
public BleKey(Context ctx) {
mPresenter = new Presenter(ctx);
}
public void scanStart() {
mPresenter.scanStart(5000);
}
//扫描开始
public void scanStart(int time) {
mPresenter.scanStart(time);
}
public void scanStop() {
mPresenter.scanStop();
}
/**
* 释放对应楼层权限
*/
public void ctrlTK(String mac, String phone, int floor) {
// mPresenter.verifyData(Utils.mac2Bytes(mac, 18), "", 0, Utils.mac2Bytes("0" + phone, 12), 1080, floor);
}
/**
* 释放呼梯控制权限 0是up,1是down
*/
public void ctrlHT(String mac, String phone, int up) {
// mPresenter.verifyData(Utils.mac2Bytes(mac, 18), "", 0, Utils.mac2Bytes("0" + phone, 12), 1090, up);
}
public void openDoor(String mac, int time) {
byte[] macs = Utils.stringToBytes(mac, 18);
// byte[] passwords = Utils.mac2Bytes("3131313131313131" + "D67D67966DA21300", 32);
// int mOutputTime = time != 0x0a ? time : 0x0a; //设置输出口时间 //不等于默认值时,对其赋值
mPresenter.init(null,null,time);
mPresenter.verifyData(macs);
}
/**
* 设置密码
*/
public void setPassword(String mac, String password) {
// mPresenter.verifyData(Utils.mac2Bytes(mac, 18), password, 0, null, 1070, 0);
}
/**
* 开门完成监听
*/
public void setOnStateListener(OnStateListener ocl) {
mPresenter.setOnStateListener(ocl);
}
/**
* 设备列表实时监听
*/
public void setOnScanListener(OnScanListener oblc) {
mPresenter.setOnScanListener(oblc);
}
}
4.提供外部的扫描监听
package com.reformer.bles;
import java.util.ArrayList;
public interface OnScanListener {
public void onScan(ArrayList<BleBean> mScans, BleBean bean);
}
5.提供给外部的状态监听
package com.reformer.bles;
public interface OnStateListener {
public void onState(int step);
}
6.涉及部分工具类
package com.reformer.bles;
import android.bluetooth.BluetoothDevice;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
public class Utils {
public static String bytes2String(byte[] msg) {
StringBuffer s = new StringBuffer();
for (int i = 0; i < msg.length; i++) {
s.append(Integer.toHexString(((int) msg[i])));
s.append(",");
}
return s.toString();
}
/**
* 5 * byte数组转换成16进制字符串
* 6 * @param src
* 7 * @return
* 8
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public static byte[] stringToBytes(String outStr, int Length) {
if (outStr.length() != Length)
return null;
int len = outStr.length() / 2;
byte[] mac = new byte[len];
String s = null;
for (int i = 0; i < len; i++) {
s = outStr.substring(i * 2, i * 2 + 2);
if (Integer.valueOf(s, 16) > 0x7F) {
mac[i] = (byte) (Integer.valueOf(s, 16) - 0xFF - 1);
} else {
mac[i] = Byte.valueOf(s, 16);
}
}
return mac;
}
public static String bytesToString(byte[] mac) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < mac.length; i++) {
if (mac[i] < 0)
mac[i] += 256;
sb.append(padLeft(Integer.toHexString(mac[i]), 2));
}
return sb.toString().toUpperCase();
}
public static String padLeft(String str, int len) {
if (str.length() > 2)
str = str.substring(str.length() - 2);
String pad = "0000000000000000";
return len > str.length() && len <= 16 && len >= 0 ? pad.substring(0, len - str.length()) + str : str;
}
public static boolean containBytesFromBytesLst(byte[] bytes, ArrayList<byte[]> arrlt) {
if (arrlt == null)
return true;
for (byte[] mac : arrlt) {
if (Arrays.equals(mac, bytes))
return true;
}
return false;
}
public static boolean containBytesFromDevLst(byte[] bytes, ArrayList<BleBean> arrlt) {
if (arrlt == null)
return false;
for (BleBean dev : arrlt) {
if (Arrays.equals(dev.mac, bytes))
return true;
}
return false;
}
public static String getAddressFromMac(byte[] mac, ArrayList<BleBean> list) {
for (BleBean devContext : list) {
if (Arrays.equals(mac, devContext.mac))
return devContext.address;
}
return "";
}
public static byte[] verifyPhone(String phone) {
if (phone != null) {
//校验电话号码
try {
Integer.parseInt(phone);
} catch (Exception e) {
e.printStackTrace();
return null;//手机号码不是整数
}
StringBuffer sbPhone = new StringBuffer();
if (phone.length() != 12) {
if (phone.length() == 11) {
sbPhone.append("0").append(phone);
} else {
return null;//手机号码长度不对
}
} else {
sbPhone.append(phone);
}
byte[] bPhone = Utils.stringToBytes(sbPhone.toString(), 12);//校验手机号长度
if (bPhone == null) {
return null;//105手机号码长度不对
}
return bPhone;
}
return null;
}
public static boolean createBond(Class btClass, BluetoothDevice btDevice) throws Exception {
Method createBondMethod = btClass.getMethod("createBond");
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
return returnValue.booleanValue();
}
public static boolean removeBond(Class btClass, BluetoothDevice btDevice) throws Exception {
Method removeBondMethod = btClass.getMethod("removeBond");
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
return returnValue.booleanValue();
}
}
7.通讯的设备对象
package com.reformer.bles;
public class BleBean {
public String name;
public String address;
public int rssi = 0;
public byte[] mac = new byte[9];
public BleBean() {
}
public BleBean(String name, String address, int rssi, byte[] mac) {
this.name = name;
this.address = address;
this.rssi = rssi;
this.mac = mac;
}
public String getMacStr() {
if (mac == null) {
return null;
}
return Utils.bytesToString(mac);
}
}