Android开发之蓝牙通信(二)
2016-08-31 10:56
288 查看
接着上篇蓝牙通信往下写,若有不对还请指出,大家共同进步。
Android开发之蓝牙通信(一)
Android开发之蓝牙通信(二)
Android开发之蓝牙通信(三)
先大概了解蓝牙扫描连接收发数据的工作流程,这里只提notify接收数据,read自动忽略。首先蓝牙需要动态权限,个人采用动态权限的开源库permissionsdispatcher,不懂若有需要可以github检索这里不在叙述(本篇多为代码块,完整接口和类可以自己拷贝到项目+开源库就可以直接用)
首先是一个接口定义,关于蓝牙的使用之前的一些判断OnBluetoothInspectListener
实现类OnBluetoothInspectListenerImpl
具体使用这块的代码块(根据动态权限结果,有蓝牙的权限后调用onBluetoothInspectListenerImpl.onInspect();方法即可,会自动根据相应函数执行回调,onOpenBluetoothState方法回调时表示可以开始蓝牙扫描了)
蓝牙扫描代码个人感觉比较繁琐,最后选用了小米一哥们的开源库https://github.com/dingjikerbo/BluetoothKit,由于该库没有提供compile路径,之前blog提到过搭建maven私服,于是下载源码下来把module上传到了本地maven私服,根据开发需求,进行了简单得的封装
接口定义IBluetoothListener、BluetoothCallback
实现类OnBluetootListener ,UUID特别重要,不能随便copy,最好找硬件那边要。(如果你拷贝了该类需要自行补充完整UUID)
根据上面的实现类,使用时只需在onCreate获取实现类实例,在蓝牙判断检查的回掉函数执行扫描,通过这个实现类代理即可
开启扫描,扫描到指定设备,开始注册蓝牙通知服务,注册成功了就开始写入数据等待返回数据,大致工作流程就这样的,主要关注回掉函数如下
再提一点,数据按照字节传输,一次接受的字节长度有限制,如果要保证自己接受完整,需要自己采用相应的办法,如下
最后一点,与硬件通信一般都会用到Crc8、Crc16算法相关的,而硬件开发用C与java有所不同,算法转换这里提供一个Crc8的一个类(网上多为c char,java的有长度限制直接拷贝到java里用会有点问题)
小结:蓝牙通信这块的开发会遇到高地位的转换、机型适配的烦恼(小米5.1、4.4手机),个人这块工作暂时告一段落,用过api直接写通信模块,也用过第三方框架,感觉都是麻烦事,还要动态权限一对代码,希望有一天有位大神闪亮登场,搞个比较牛逼的开源库让我一键调用就好了。
Android开发之蓝牙通信(一)
Android开发之蓝牙通信(二)
Android开发之蓝牙通信(三)
先大概了解蓝牙扫描连接收发数据的工作流程,这里只提notify接收数据,read自动忽略。首先蓝牙需要动态权限,个人采用动态权限的开源库permissionsdispatcher,不懂若有需要可以github检索这里不在叙述(本篇多为代码块,完整接口和类可以自己拷贝到项目+开源库就可以直接用)
首先是一个接口定义,关于蓝牙的使用之前的一些判断OnBluetoothInspectListener
public interface IBluetoothInspectListener { public interface OnBluetoothCheckListener { void onOpenBluetoothState(); void onRefuseOpenBluetoothState(); void unSupportBluetooth(); } public interface OnBluetoothInspectListener { void onInspect(); void onSupportBluetooth(); boolean isOpenBluetooth(); void onOpenBluetooth(); } }
实现类OnBluetoothInspectListenerImpl
public class OnBluetoothInspectListenerImpl implements OnBluetoothInspectListener { private static final int REQUEST_ENABLE_BT = 1; private static OnBluetoothInspectListenerImpl instance; private OnBluetoothCheckListener onBluetoothCheckListener; BluetoothAdapter mBluetoothAdapter; Activity mContext; private OnBluetoothInspectListenerImpl(Activity mContext, OnBluetoothCheckListener onBluetoothCheckListener) { this.mContext = mContext; this.onBluetoothCheckListener = onBluetoothCheckListener; this.mBluetoothAdapter = ((BluetoothManager)mContext.getSystemService("bluetooth")).getAdapter(); } public static OnBluetoothInspectListenerImpl init(Activity activity, OnBluetoothCheckListener onBluetoothCheckListener) { instance = new OnBluetoothInspectListenerImpl(activity, onBluetoothCheckListener); return instance; } public void onInspect() { if(this.mBluetoothAdapter == null) { this.onBluetoothCheckListener.unSupportBluetooth(); } else { this.onSupportBluetooth(); } } public void onSupportBluetooth() { if(this.isOpenBluetooth()) { this.onBluetoothCheckListener.onOpenBluetoothState(); } else { this.onOpenBluetooth(); } } public boolean isOpenBluetooth() { return this.mBluetoothAdapter.isEnabled(); } public void onOpenBluetooth() { Intent enableBtIntent = new Intent("android.bluetooth.adapter.action.REQUEST_ENABLE"); this.mContext.startActivityForResult(enableBtIntent, 1); } public void performResult(int requestCode, int resultCode) { switch(requestCode) { case 1: if(this.onBluetoothCheckListener != null) { if(this.isOpenBluetooth()) { this.onBluetoothCheckListener.onOpenBluetoothState(); } else { this.onBluetoothCheckListener.onRefuseOpenBluetoothState(); } } default: } } public BluetoothAdapter getBluetoothAdapter() { return this.mBluetoothAdapter; } }
具体使用这块的代码块(根据动态权限结果,有蓝牙的权限后调用onBluetoothInspectListenerImpl.onInspect();方法即可,会自动根据相应函数执行回调,onOpenBluetoothState方法回调时表示可以开始蓝牙扫描了)
public class BluetoothActivity extends AppCompatActivity implements IBluetoothInspectListener.OnBluetoothCheckListener{ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //.........略.................. onBluetoothInspectListenerImpl = OnBluetoothInspectListenerImpl.init(this, this); //.......动态权限......... } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); onBluetoothInspectListenerImpl.performResult(requestCode, resultCode); } @Override public void onOpenBluetoothState() { //扫描读写 startScan(); } @Override public void onRefuseOpenBluetoothState() { showInformation("您拒绝了开启蓝牙将影响到功能的使用"); finish(); } @Override public void unSupportBluetooth() { showInformation("手机不支持低功耗蓝牙通信"); finish(); } }
蓝牙扫描代码个人感觉比较繁琐,最后选用了小米一哥们的开源库https://github.com/dingjikerbo/BluetoothKit,由于该库没有提供compile路径,之前blog提到过搭建maven私服,于是下载源码下来把module上传到了本地maven私服,根据开发需求,进行了简单得的封装
接口定义IBluetoothListener、BluetoothCallback
public interface IBluetoothListener { public void startScan(); public void stopScan(); public void connect(); public void read(); public void write(); public void registerNotify(); public void unRegisterNotify(); public void disconnect(); public void release(); } public interface BluetoothCallback { public void showInformation(String information); public void toastMessage(String message); public void readResponse(byte[] bytes); }
实现类OnBluetootListener ,UUID特别重要,不能随便copy,最好找硬件那边要。(如果你拷贝了该类需要自行补充完整UUID)
public class OnBluetootListener implements IBluetoothListener { public static final UUID SERVICE_UUID ; public static final UUID WRITE_CHARA ; public static final UUID READ_CHARA ; private byte[] bytes; private String deviceMac; private SearchRequest request; private IBluetoothClient mClient; private BluetoothDevice currentBluetoothDevice; private BluetoothCallback callback; private boolean isStopScan = false; public OnBluetootListener(Context context, String deviceMac, byte[] bytes, BluetoothCallback callback) { this.deviceMac = deviceMac; this.bytes = bytes; this.callback = callback; mClient = BluetoothClient.getInstance(context); request = new SearchRequest.Builder() .searchBluetoothLeDevice(3000, 1) // scan Bluetooth LE device for 3000ms, 3 times .searchBluetoothClassicDevice(5000) // then scan Bluetooth Classic device for 5000ms, 1 time .searchBluetoothLeDevice(2000) // at last scan Bluetooth LE device for 2000ms .build(); } @Override public void startScan() { //执行扫描任务 callback.showInformation("扫描设备.."); mClient.search(request, new SearchResponse() { @Override public void onSearchStarted() { } @Override public void onDeviceFounded(SearchResult device) { if (device.device.getAddress().equals(deviceMac)&&!isStopScan) { isStopScan=true; //扫描到指定设备后停止扫描 callback.showInformation("发现设备"); currentBluetoothDevice = device.device; //连接设备 connect(); stopScan(); } } @Override public void onSearchStopped() { if (currentBluetoothDevice == null) { callback.toastMessage("没有发现匹配的设备"); } } @Override public void onSearchCanceled() { } }); } @Override public void stopScan() { mClient.stopSearch(); } @Override public void connect() { mClient.connect(deviceMac, new BleConnectResponse() { @Override public void onResponse(int code, Bundle data) { if (code == REQUEST_SUCCESS) { //连接成功 //注册notify以后发送数据和读取数据 callback.showInformation("连接成功"); registerNotify(); } else { release(); callback.toastMessage("连接失败"); } } }); } @Override public void read() { mClient.read(deviceMac, SERVICE_UUID, READ_CHARA, new BleReadResponse() { @Override public void onResponse(int code, byte[] data) { if (code == REQUEST_SUCCESS) { callback.showInformation(data.toString()); } else { release(); callback.toastMessage("读取数据失败"); } } }); } @Override public void write() { mClient.write(deviceMac, SERVICE_UUID, WRITE_CHARA, bytes, new BleWriteResponse() { @Override public void onResponse(int code) { if (code == REQUEST_SUCCESS) { callback.showInformation("发送数据成功"); // read(); } else { release(); callback.toastMessage("发送数据失败"); } } }); } public void write(byte[] bytes) { mClient.write(deviceMac, SERVICE_UUID, WRITE_CHARA, bytes, new BleWriteResponse() { @Override public void onResponse(int code) { if (code == REQUEST_SUCCESS) { } else { release(); callback.toastMessage("发送数据失败"); } } }); } @Override public void registerNotify() { mClient.notify(deviceMac, SERVICE_UUID, READ_CHARA, new BleNotifyResponse() { @Override public void onNotify(UUID service, UUID character, byte[] value) { callback.readResponse(value); } @Override public void onResponse(int code) { if (code == REQUEST_SUCCESS) { // callback.showInformation("注册蓝牙通知成功"); //write数据需要注意,个别手机有限制一次发送数据最大值,如果超过了需要自己分多次发送 callback.showInformation("数据已发送,等待数据响应"); } else { release(); callback.toastMessage("发送失败,请再试一次"); } } }); } @Override public void unRegisterNotify() { mClient.unnotify(deviceMac, SERVICE_UUID, READ_CHARA, new BleUnnotifyResponse() { @Override public void onResponse(int code) { } }); } @Override public void disconnect() { mClient.disconnect(deviceMac); } @Override public void release() { unRegisterNotify(); disconnect(); stopScan(); } public BluetoothDevice getCurrentBluetoothDevice(){ return currentBluetoothDevice; } }
根据上面的实现类,使用时只需在onCreate获取实现类实例,在蓝牙判断检查的回掉函数执行扫描,通过这个实现类代理即可
listener = new OnBluetootListener(this,macAddress,sendMessageBytes,this); //........................................... @Override public void onOpenBluetoothState() { //扫描读写 listener.startScan(); }
开启扫描,扫描到指定设备,开始注册蓝牙通知服务,注册成功了就开始写入数据等待返回数据,大致工作流程就这样的,主要关注回掉函数如下
@Override public void showInformation(String message) { toast.setText(message); // Logger.e(message); } @Override public void toastMessage(String s) { Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show(); handler.postDelayed(new Runnable() { @Override public void run() { finish(); } },1000); } @Override public void readResponse(byte[] bytes) { }
再提一点,数据按照字节传输,一次接受的字节长度有限制,如果要保证自己接受完整,需要自己采用相应的办法,如下
@Override public void readResponse(byte[] bytes) { saveBytes(bytes, responseBytes); if (readCount == responseBytes.length) { onResponseReadResult(responseBytes);//解析回传数据 } } /** * 拼接byte数据 * * @param src * @param ds */ public void saveBytes(byte[] src, byte[] ds) { for (int i = 0; i < src.length; i++) { ds[i + readCount] = src[i]; } readCount = readCount + src.length; }
最后一点,与硬件通信一般都会用到Crc8、Crc16算法相关的,而硬件开发用C与java有所不同,算法转换这里提供一个Crc8的一个类(网上多为c char,java的有长度限制直接拷贝到java里用会有点问题)
public class Crc8Helper { /** * CRC8算法 * * @param bytes * @return */ public static byte CRC8_Table(byte[] bytes)// counter默认为2 { return calcCrc8(bytes); } static byte[] crc8_tab = {(byte) 0, (byte) 94, (byte) 188, (byte) 226, (byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194, (byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253, (byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33, (byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30, (byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96, (byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159, (byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160, (byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128, (byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2, (byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61, (byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29, (byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24, (byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155, (byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102, (byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219, (byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228, (byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251, (byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101, (byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184, (byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69, (byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248, (byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199, (byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134, (byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185, (byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237, (byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242, (byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205, (byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112, (byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141, (byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14, (byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77, (byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109, (byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82, (byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142, (byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177, (byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145, (byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148, (byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23, (byte) 73, (byte) 8, (byte) 86, (byte) 180, (byte) 234, (byte) 105, (byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235, (byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212, (byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244, (byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183, (byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52, (byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201, (byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116, (byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75, (byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10, (byte) 84, (byte) 215, (byte) 137, (byte) 107, 53}; /** * 计算数组的CRC8校验值 * * @param data 需要计算的数组 * @return CRC8校验值 */ public static byte calcCrc8(byte[] data) { return calcCrc8(data, 0, data.length, (byte) 0); } /** * 计算CRC8校验值 * * @param data 数据 * @param offset 起始位置 * @param len 长度 * @return 校验值 */ public static byte calcCrc8(byte[] data, int offset, int len) { return calcCrc8(data, offset, len, (byte) 0); } /** * 计算CRC8校验值 * * @param data 数据 * @param offset 起始位置 * @param len 长度 * @param preval 之前的校验值 * @return 校验值 */ public static byte calcCrc8(byte[] data, int offset, int len, byte preval) { byte ret = preval; for (int i = offset; i < (offset + len); ++i) { ret = crc8_tab[(0x00ff & (ret ^ data[i]))]; } return ret; } /** * 计算CRC8校验值 * * @param data * 数据 * @param offset * 起始位置 * @param len * 长度 * @param preval * 之前的校验值 * @return 校验值 */ public static byte parseCalcCrc8(byte[] data, int offset, int len, byte preval) { byte ret = preval; for (int i = offset; i < (offset + len); ++i) { ret = crc8_tab[(0x00ff & (ret ^ data[i]))]; } return ret; } }
小结:蓝牙通信这块的开发会遇到高地位的转换、机型适配的烦恼(小米5.1、4.4手机),个人这块工作暂时告一段落,用过api直接写通信模块,也用过第三方框架,感觉都是麻烦事,还要动态权限一对代码,希望有一天有位大神闪亮登场,搞个比较牛逼的开源库让我一键调用就好了。
相关文章推荐
- Android手机蓝牙与单片机蓝牙串通信开发经验总结
- Android上的蓝牙通信功能的开发:BluetoothChat例程分析
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- 1 android蓝牙开发---与蓝牙模块进行通信
- Android蓝牙通信功能开发
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- android蓝牙开发---与蓝牙模块进行通信
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- android蓝牙开发---与蓝牙模块进行通信
- Android蓝牙通信功能开发
- Android应用开发笔记(11):Android上的蓝牙通信功能的开发:BluetoothChat例程分析
- Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子_Android支持蓝牙4.0版本_BLE开发
- Android上蓝牙通信功能开发:BluetoothChat例程分析
- android蓝牙开发---与蓝牙模块进行通信
- 基于 Android蓝牙4.0开发详细讲解,与硬件通信 史上最牛逼,最详细
- 【转】android蓝牙开发---与蓝牙模块进行通信--不错
- 转载_Android Bluetooth蓝牙开发\蓝牙协议\蓝牙通信例子