Android 蓝牙4.0 BLE (onServicesDiscovered 返回 status 是 129,133时)
Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说android 4.3+, API level >= 18,且支持蓝牙4.0的手机才可以使用。
BLE是蓝牙4.0的核心Profile,主打功能是快速搜索,快速连接,无需配对,超低功耗保持连接和传输数据,弱点是数据传输速率低,由于BLE的低功耗特点,因此普遍用于穿戴设备。
官方demo:http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
官方demo(csdn下载,感谢分享的人吧):http://download.csdn.net/detail/lqw770737185/8116019
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
//不支持ble
finish();
}
BluetoothAdapter.LeScanCallback
接口,BLE设备的搜索结果将通过这个callback返回private ExecutorService mExecutor; // Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() { @Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
// 不能做太多事情,特别周围ble设备多的时候。容易出现错误或者ANR,需要把结果处理放到另外的线程去。
if(mExecutor == null) {
mExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
}
new ScanProcessor().executeOnExecutor(mExecutor, new ScanData(device, rssi, scanRecord));
} };
ScanData:
private class ScanData {
public ScanData(BluetoothDevice device, int rssi, byte[] scanRecord) {
this.device = device;
this.rssi = rssi;
this.scanRecord = scanRecord;
} int rssi;
BluetoothDevice device;
byte[] scanRecord;
}
扫描结果处理:
private class ScanProcessor extends AsyncTask<ScanData, Void, MingbikeBeacon> { public ScanProcessor() {
} @Override
protected Object doInBackground(ScanData... params) {
if (params == null || params.length == 0)
return null;
ScanData scanData = params[0];
// todo scanData
return new Object();
} @Override
protected void onPostExecute(Object obj) {
// todo obj
} @Override
protected void onPreExecute() {
} @Override
protected void onProgressUpdate(Void... values) {
}
}
(2)关闭BLE设备的搜索
mBluetoothAdapter.stopLeScan(mLeScanCallback);
(3)开启BLE设备的搜索
mBluetoothAdapter.startLeScan(mLeScanCallback);
*************注意:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索。
(4)使用BluetoothGatt 来连接设备
private BluetoothGatt mBluetoothGatt;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // 蓝牙mac地址
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback);
参数autoConnect,如果为 true
的话,系统就会发起一个后台连接,等到系统发现了一个设备,就会自动连上,通常这个过程是非常慢的。为 false
的话,就会直接连接,通常会比较快。同样,BluetoothGatt.connect()
只能发起一个后台连接,不是直接连接。所以这个地方需要小心。
(5)使用BluetoothGattCallback 来跟设备进行通信
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt,
int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
9 if (newState == BluetoothProfile.STATE_CONNECTED) {
setState(State.CONNECTED);
gatt.discoverServices();
} else {
setState(State.IDLE);
}
} @Override
public void onServicesDiscovered(BluetoothGatt gatt,
int status) {
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.v(TAG, "onServicesDiscovered: " + status);
}
}
}
连接时会走这个方法onConnectionStateChange,传过来的新状态是连接状态,这时在这个方法中调用一下这句:mBluetoothGatt.discoverServices(),
mBluetoothGatt是连接完成时的对象,调用这句后,会走回调函数的onServicesDiscovered方法。在这个方法中去获取设备的一些服务,蓝牙通道,然后通过这些通道去发送数据给外设。
有些设备,在 onServicesDiscovered 回调中,返回的 status 是 129,133时,在关闭,重新打开蓝牙,无法解决问题时,建议更换设备,这些问题大多是设备底层gatt 服务异常,重新连接,进行discoverServices();
// 出现129,133时。关闭蓝牙
mBluetoothAdapter.disable();
// 关闭蓝牙后,延时1s,重新开启蓝牙
mBluetoothAdapter.enable();
在蓝牙设备中, 其包含有多个BluetoothGattService, 而每个BluetoothGattService中又包含有多个BluetoothGattCharacteristic。
当onServicesDiscovered()回调的 status == BluetoothGatt.GATT_SUCCESS, 可以进行获取service。
(1)获取到设备中的服务列表 mBluetoothGatt.getServices(); 或者通过uuid 来获取某一个服务:
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null)
return null;
return mBluetoothGatt.getServices();
// 或者通过uuid来获取某一个服务 mBluetoothGatt.getServices(uuid);
}
(2)通过Gatt这个对像,就是蓝牙连接完成后获取到的对象,通过这个对象设置好指定的通道向设备中写入和读取数据。
在onServicesDiscovered(BluetoothGatt gatt, int status) 回调中, 获取服务对象,获取读取、写入、描述的特征。
// 获取指定uuid的服务
BluetoothGattService service = gatt.getService(BluetoothUUID.bleServerUUID);
// 获取读取特征
BluetoothGattCharacteristic readCharacteristic = service.getCharacteristic(BluetoothUUID.readDataUUID);
// 获取写入特征
writeCharacteristic = service.getCharacteristic(BluetoothUUID.writeDataUUID);
gatt.setCharacteristicNotification(readCharacteristic, true);
// 获取描述特征
BluetoothGattDescriptor descriptor = readCharacteristic.getDescriptor(BluetoothUUID.CLIENT_CHARACTERISTIC_CONFIG);
// 要看外围设备的设置
if (isNotify) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
gatt.writeDescriptor(descriptor);
服务中, 也可以通过调用 gattService.getCharacteristics():获得Characteristic 集合.
在 Characteristic中, 可以通过 mBluetoothGatt.readCharacteristic(characteristic); 来读取其里面的数据, 其结果在mGattCallback 回调函数中获取.
写如数据:
mCurrentcharacteristic.setValue(data);
mBluetoothGatt.wirteCharacteristic(mCurrentcharacteristic);
public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
} mBluetoothGatt.writeCharacteristic(characteristic);
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
当外围设备,调用:
BluetoothGattServer.class
notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm);
就会触发中心设备的onCharractersticChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) 方法回调:
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
byte[] values = characteristic.getValue();
// todo values
}
注意:BluetoothGattCharacteristic这个是指定的通道,蓝牙服务:
BluetoothGattCharacteristic characteristic = null;
characteristic = mGattCharacteristics.get(4).get(4);
这两个数字就是从指定的服务中找到你要发送数据的那个服务。
如果要进行多个连接,每次连接完成后可以将BluetoothGatt的对象放到一个list里面,获取到的服务也放到一个List里面,然后发送数据的时候调用不同的Gatt发送不同的通道数据即可。
参考:
Android 蓝牙4.0 BLE (onServicesDiscovered 返回 status 是 129,133时)的更多相关文章
- Android 蓝牙4.0 BLE
Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用. BLE是蓝牙4.0的核心Profil ...
- android蓝牙4.0(BLE)开发之ibeacon初步
一个april beacon里携带的信息如下 ? 1 <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC ...
- ym——物联网入口之中的一个Android蓝牙4.0
转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 假设还有同学不知道蓝牙4.0能够做什么请查看Android+蓝牙 4.0 将带来什么? ...
- android 蓝牙4.0 开发介绍
最近一直在研究一个蓝牙功能 由于本人是菜鸟 学起来比较忙 一直搞了好久才弄懂 , 网上对蓝牙4.0也就是几个个dome 抄来抄去,全是英文注解 , 对英语不好的朋友来说 真是硬伤 , 一些没必要的描 ...
- Android项目实战(三十四):蓝牙4.0 BLE 多设备连接
最近项目有个需求,手机设备连接多个蓝牙4.0 设备 并获取这些设备的数据. 查询了很多资料终于实现,现进行总结. ------------------------------------------- ...
- Android 蓝牙4.0的连接和通讯
1.加入权限 <uses-sdk android:minSdkVersion=" android:targetSdkVersion="/> <uses-featu ...
- android 蓝牙4.0多通道
很久没记录东西了,前段时间研究了一哈android4.0控制多个外设的情况,注意,需要使用android版本4.3以上,蓝牙4.0及以上. 我这里使用的控制蓝牙灯泡,使用android4.3的手机,手 ...
- IOS学习之蓝牙4.0 BLE
IOS学习也一段时间了,该上点干货了.前段时间研究了一下IOS蓝牙通讯相关的东西,把研究的一个成果给大家分享一下. 一 项目背景 简单介绍一下做的东西,设备是一个金融刷卡器,通过蓝牙与iphone手机 ...
- 蓝牙4.0 BLE入门
在BLE协议中有两个角色,一个是周边(Periphery),另外一个是中央(Central).一个中央可以同时连接多个周边,但一个周边某一时刻只能连接一个中央.但是不管periphery还是centr ...
随机推荐
- Web的几种上传方式总结
问题 文件上传在WEB开发中应用很广泛. 文件上传是指将本地图片.视频.音频等文件上传到服务器上,可以供其他用户浏览或下载的过程. 以下总结了常见的文件(图片)上传的方式和要点处理. 表单上传 这是传 ...
- 【C++ Primer | 08】IO库
IO类 C++的输入输出分为三种: (1)基于控制台的I/O (2)基于文件的I/O (3)基于字符串的I/O istringstream类 描述:从流中提取数据,支持 >> 操作 这里字 ...
- TFS 生成任务报错:目录不是空的
转到代理目录下,将生成文件夹清空,重新启动生成任务即可
- flanneld,flannel和cni逐步深入
这个问题,现在慢慢搞定. 把这两者的关系搞清楚了. 还有kubeadm join和手工安装Node的故事, 也没那么玄乎~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ htt ...
- JavaScript数组去重的6个方法
方法一无需思考,我们可以得到 O(n^2) 复杂度的解法.定义一个变量数组 res 保存结果,遍历需要去重的数组,如果该元素已经存在在 res 中了,则说明是重复的元素,如果没有,则放入 res 中. ...
- github的pull request是指什么意思
有一个仓库,叫Repo A.你如果要往里贡献代码,首先要Fork这个Repo,于是在你的Github账号下有了一个Repo A2,.然后你在这个A2下工作,Commit,push等.然后你希望原始仓库 ...
- 从入门到深入FIDDLER 2
在开发的过程中使用过不少的HTTP网络抓包工具,如:HTTPAnalyzer,HttpWatch. Fiddler几乎囊括了大部分的抓包请求,当然最给力的还是它的断点调试功能,尤其还有使用本地文件代替 ...
- spring cloud (二、服务注册安全demo_eureka)
spring cloud (一.服务注册demo_eureka) 加强服务的安全性,我们接下来加上访问的账号密码: 首先需要添加对应的依赖 <!--账号密码认证依赖--> <depe ...
- Linux安装Tomcat-Nginx-FastDFS-Redis-Solr-集群——【第七集之SSH远程连接——克隆与更改配置】
一.SSH远程连接 OpenSSH的安装 查看是否安装Openssh:rpm -qa | grep ssh搜索openssh安装包:yum search openssh安装openssh:yum in ...
- request和session的区别
request多用于表单提交,表单数据等 session用于服务器端的记录变量,比如用户的登陆和登出啊 request 资源占用小,安全性较高,但是不持续性 session 资源消耗较大,安全性较低, ...