Android开发——蓝牙
---恢复内容开始---
## 前言
孤芳自赏,一揽芳华;
人情冷暖,自在人心;
登高远眺,望步止前;
喜笑言开,欺人骗己。
上篇文章介绍了基本的蓝牙使用,书写的demo也不是很完善,希望各位大神能够改正。这两周由于公司开发的进度,还有个人的一些原因,没有及时写这篇文章来介绍我写的这个demo。这是对自己的一种不负责。这两周,boss让我按照OCP原则重构代码,改了一遍有一遍,到后来还是boss给我弄了个demo参照着并帮助我把代码重构完毕。对于面向对象的三大特征,六大原则,二十三种设计模式,这里我就不显丑了,等我把书看完在一 一介绍。
正文
一、打开蓝牙并扫描蓝牙设备
private void initBluetoothAdapter() {
if (null == mBluetoothManager) {
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);// 获取系统服务
if (null != mBluetoothManager) {
mBluetoothAdapter = mBluetoothManager.getAdapter();//获得蓝牙适配器(Adapter)
}
}
if (null == mBluetoothAdapter) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//以防Manager为null,再次获取蓝牙适配器
if (null == mBluetoothAdapter) {
Toast.makeText(this, R.string.noBluetooth, Toast.LENGTH_SHORT).show();
return;
}
}
//查看手机是否打开了蓝牙,如果没有打开,提示用户打开蓝牙
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
}
}
}
蓝牙打开后就是扫描蓝牙设备,发现蓝牙了
if (null != mBluetoothAdapter)
mBluetoothAdapter.startDiscovery();//扫描蓝牙
这时需要注册下Receiver,接收发现蓝牙的信息
private void register() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//扫描到蓝牙设备注册的action
intentFilter.addAction(BluetoothConstant.ACTION_DATA_AVAILABLE);//蓝牙启动后,返回数据时的监听
intentFilter.addAction(BluetoothConstant.ACTION_DATA_COMPLETE);//蓝牙数据返回完成后,最后返回的数据
registerReceiver(mBroadcastReceiver, intentFilter);
}
- 对扫描到的蓝牙进行处理,把需要的蓝牙的名字保存下来,并链接Service,在Service中对蓝牙进行连接,并把一些给蓝牙写入命令,处理蓝牙回调的都放到Service中,减小Activity页面的开销。
二、链接蓝牙设备
在蓝牙中有一个至关重要的类——BluetoothGatt,他是对蓝牙进行操作的类,给蓝牙写入Write命令,Read命令,都需要用到它,他的初始化适合蓝牙链接密不可分的。
在Service中封装的方法,有一个是用来链接蓝牙的,并在这个方法中初始化BluetoothGatt。
/**
* 链接蓝牙
*
* @param address 蓝牙地址
* @return 链接是否成功
*/
public boolean connect(BluetoothAdapter bluetoothAdapter,String address) {
this.mBluetoothAdapter = bluetoothAdapter;
if (null == address || null == mBluetoothAdapter) {
Log.e(TAG, "connect Bluetooth address or BluetoothAdapter is null that not initial");
return false;
}
if (mDeviceAddress != null && address.equals(mDeviceAddress)
&& mBluetoothGatt != null) {
//链接过的设备再次链接
Log.i(TAG, "connect existing device");
return mBluetoothGatt.connect();
}
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (null != device) {
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);//第一次链接蓝牙并初始化BluetoothGatt
mDeviceAddress = address;
this.mDeviceName = device.getName();
}else {
Log.i(TAG,"device is null");
}
return true;
}
- 在链接蓝牙中又个坑,这个坑也不是每次出现,也不是每天出现,而是偶尔出现几次,那就是链接过的蓝牙,当你断开再次链接会链接不上,有时会显示扫描不到所有蓝牙设备,我没有很好的解决办法,临时办法就是关闭蓝牙,重新在进行蓝牙扫描并链接。
三、注册通道
对于蓝牙回调的一些方法和回调处理在上篇文章中已经大致写了一些,这里就不再详细的介绍了。
当蓝牙链接成功就需要扫描蓝牙的服务通道
mBluetoothGatt.discoverServices();
扫描到蓝牙服务后,遍历服务中的所有通道并选择你需要的通道进行注册。
/**
* 获取特征值(特征UUID) 用来做与蓝牙通讯的唯一通道
*
* @param gattServices BluetoothGattService
*/
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null)
return;
String uuid;
/**
*这里说一下,names,uuids,receiveUUIDs必须一 一对应(示例在下方),如果有不需要的用设备名称补气,如若为"" 程序可能出错,通道注册失败。
*/
String[] names = BluetoothConstant.getInstance().getDeviceNames();
String[] uuids = BluetoothConstant.getInstance().getNotificationUUIDs();
String[] receiveUUIDs = BluetoothConstant.getInstance().getReceiveNotificationUUIDs();
//从所有服务里面,找到能够和蓝牙通信的有效服务UUID
for (BluetoothGattService gattService : gattServices) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
//从服务中找到自己所需的特征值BluetoothGattCharacteristic
for (BluetoothGattCharacteristic characteristic : gattCharacteristics) {
uuid = characteristic.getUuid().toString();
String device = mBluetoothGatt.getDevice().getName();
for (int i = 0; i < names.length; i++) {
if (uuid.contains(uuids[i]) && device.equals(names[i])) {
//这里就是需要的特征值了
Log.i(TAG,">>>><<<<< \n name ="+names[i]+"\n"+"uuid = "+uuid+"\n"+"receiveUUID = "+receiveUUIDs[i]);
if (!uuid.contains(receiveUUIDs[i])) {
this.mCharacteristic = characteristic;//这里为什么要加一个if,是因为有的蓝牙数据返回和写入命令是一个通道;有的数据返回是一个通道,写入命令是另一个通道;当用返回数据的通道写入命令是,命令是写不进去的。所以,当不是蓝牙返回数据的通道时,把特征值全局化。
}
notification(characteristic);
}
}
}
}
}
//这里说一下,为什么这么写,刚开始注册通道的时候只写了mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true)一句,然而并不是每次都能注册成功的,在网上查找了几个方法,只有这个方法比较用,这样,通道就不会注册错误了。
private void notification(BluetoothGattCharacteristic gattCharacteristic) {
boolean success = mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
Log.i(TAG,"notification characteristic permissions = "+gattCharacteristic.getPermissions()+"\n"
+"characteristic properties = "+ gattCharacteristic.getProperties()+"\n"+
"characteristic uuid = "+gattCharacteristic.getUuid());
if (success) {
for (BluetoothGattDescriptor dp : gattCharacteristic.getDescriptors()) {
if (dp != null) {
if ((gattCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
}
mBluetoothGatt.writeDescriptor(dp);
try {
Thread.sleep(200);//这里为什么会休眠200ms,是因为,注册速度太快,并不是所有的通道都能注册成功,加个延迟,会好些
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
下面是蓝牙的一些基本设置,写在了BluetoothConstant类中,这个类主要是统一写一些蓝牙相关的东西,例如名称,注册通道,接受数据的通道,命令等。
//设备名称
private final String[] deviceNames = new String[]{
DEVICE_NAME_ONE,
DEVICE_NAME_TWO,
DEVICE_NAME_TWO,
DEVICE_NAME_THREE
};
//需要注册蓝牙Characteristic的通道(读,写,通知)
private final String[] notificationUUIDs = new String[]{
"0001",
"0002",
"0003",
"0004"
};
//只接收数据的通道,不进行读写,不是UUID的是占位,占位的也可以是其他字符窜,只要不是""就可以。
private final String[] receiveNotificationUUIDs = new String[]{
"DEVICE_NAME_ONE",
"DEVICE_NAME_TWO",
"0000fff4-0000-1000-8000-00805f9b34fb",
"DEVICE_NAME_THREE"
};
对于隔了这么长时间才写这篇文章,我深感抱歉。在蓝牙开发中,最可恶的是蓝牙提供商,给了协议,但是没有具体命令,这需要我们自己去拼写命令,然而在命令的最后一位是校验位,有奇偶检验,有异或校验,有CRC8校验,有CRC16校验,这里我给大家提供福利,把这异或校验和CRC8校验记录下来:
/**
* 异或校验位计算
* 去掉起起始位,从第二位开始算
*/
private void getXOR(int[] hexs){
int xor = 0;
for (int i = 0;i<hexs.length;i++){
xor = xor^hexs[i];
Log.i(TAG,"XOR ="+xor);
}
Log.i(TAG,"Hex XOR = "+xor);
}
// CRC8校验
private 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
* 长度
* @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;
}
关于蓝牙开发的一些知识内容基本就介绍完了,如果有问题的同学,可以加QQ群:177694195 我们一起讨论蓝牙的开发。
---恢复内容结束---
Android开发——蓝牙的更多相关文章
- Android 开发 蓝牙开发
前言 蓝牙开发其实分2个部分,一个是正常蓝牙功能的开发(比如Android蓝牙的互相连接.读取蓝牙列表.文件传输.蓝牙耳机等等).另外一个是BLE蓝牙开发(属于低功耗蓝牙设备,设备大多是血糖仪.蓝牙手 ...
- Android低功耗蓝牙(BLE)开发的一点感受
最近一段时间,因为产品的需要我做了一个基于低功耗蓝牙设备的Android应用,其中碰到了一些困难,使我深深体会到Android开发的难处:不同品牌,不同型号和不同版本之间的差异使得Android应用适 ...
- 【视频】零基础学Android开发:蓝牙聊天室APP(四)
零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...
- 【视频】零基础学Android开发:蓝牙聊天室APP(二)
零基础学Android开发:蓝牙聊天室APP第二讲 2.1 课程内容应用场景 2.2 Android UI设计 2.3 组件布局:LinearLayout和RelativeLayout 2.4 Tex ...
- Android 串口蓝牙通信开发Java版本
Android串口BLE蓝牙通信Java版 0. 导语 Qt on Android 蓝牙通信开发 我们都知道,在物联网中,BLE蓝牙是通信设备的关键设备.在传统的物联网应用中,无线WIFI.蓝牙和Zi ...
- 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体解释
转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发具体 ...
- 【视频】零基础学Android开发:蓝牙聊天室APP(三)
零基础学Android开发:蓝牙聊天室APP第三讲 3.1 ImageView.ImageButton控件具体解释 3.2 GridView控件具体解释 3.3 SimpleAdapter适配器具体解 ...
- 【视频】零基础学Android开发:蓝牙聊天室APP(一)
零基础学Android开发:蓝牙聊天室APP第一讲 1. Android介绍与环境搭建:史上最高效Android入门学习 1.1 Google的大小战略 1.2 物联网与云计算 1.3 智能XX设备 ...
- Android Studio 蓝牙开发实例——基于Android 6.0
因项目需要做一个Android 的蓝牙app来通过手机蓝牙传输数据以及控制飞行器,在此,我对这段时间里写的蓝牙app的代码进行知识梳理和出现错误的总结. 该应用的Compile Sdk Version ...
随机推荐
- 注入式开发(二):.NET 匿名函数
其实匿名函数就是个委托.只不过写起来更简洁. 为啥要用匿名函数呢?只是为了装逼吗? 诺诺诺 比如说,我们写代码,写着写着,发现有2个函数非常相像: string methodA(string data ...
- Codeforces 755 F. PolandBall and Gifts 多重背包+贪心
F. PolandBall and Gifts It's Christmas time! PolandBall and his friends will be giving themselves ...
- HDU - 1150 Machine Schedule(最小点覆盖数)
1.有两台机器A和B以及N个需要运行的任务.A机器有n种不同的模式,B机器有m种不同的模式,而每个任务都恰好在一台机器上运行.如果它在机器A上运行,则机器A需要设置为模式xi,如果它在机器B上运行,则 ...
- 小程序-demo:小程序示例-page/component2
ylbtech-小程序-demo:小程序示例-page/component2 以下将展示小程序官方组件能力,组件样式仅供参考,开发者可根据自身需求自定义组件样式,具体属性参数详见小程序开发文档. 1. ...
- java笔记之IO1
File:文件和目录(文件夹)路径名的抽象表示形式 * 构造方法: * File(String pathname):根据一个路径得到File对象 * File(String parent, S ...
- (转)理解POCO
POCO的概念是从java的POJO借用而来,而两者的含义是一致的,不同的仅仅是使用的语言不一样.所以POCO的解释就是“Plain Old C# Object”. 从字面上翻译为“纯洁老式的C#对象 ...
- #if、#ifdef、#if defined之间的区别(转载)
转自:http://www.yucoat.com/c_program/difference_if_ifdef_if_defined.html #if的使用说明 #if的后面接的是表达式 #if (MA ...
- 【牛客-14602】xinjun与阴阳师(01背包)
xinjun与阴阳师 题目描述 xinjun是各类手游的狂热粉丝,因随手一氪.一氪上千而威震工大,现在他迷上了阴阳师.xinjun玩手游有一个习惯,就是经过层层计算制定出一套方案来使操作利益最大化(因 ...
- 如何管理第三方接口token过期时间
背景: 随着微服务的盛行,做开发时不可避免的要涉及第三方接口,安全起见,这些接口都会需要一个token参数.而token一般都会有一个过期时间,比如2小时或者30分钟.那么如何在自己的应用中存储并管理 ...
- Python中处理日期时间库的使用方法(转载)
<本文来自公众号“大邓带你玩python”,转载> 用百分之20时间,学会解决百分之80的问题. 常用的库有time.datetime.其中datetime库是对time库的封装,所以使用 ...