在 [深入了解Android蓝牙Bluetooth——《基础篇》](http://blog.csdn.net/androidstarjack/article/details/60468468)一篇中我们对蓝牙的各个版本的有了一个认识,蓝牙版本的历程及其优劣式介绍。那么接下来咱们就深入一点继续开车进入BLE的进及篇章。

蓝牙BLE4.x

BLE分为三部分:

  • Service

  • Characteristic

  • Descriptor

    这三部分都用UUID作为唯一标识符。UUID为这种格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3个Service,那么就有三个不同的UUID与Service对应。这些UUID都写在硬件里,我们通过BLE提供的API可以读取到。

  • 一个BLE终端可以包含多个Service, 一个Service可以包含多个Characteristic,一个Characteristic包含一个value和多个Descriptor,一个Descriptor包含一个Value。Characteristic是比较重要的,是手机与BLE终端交换数据的关键,读取设置数据等操作都是操作Characteristic的相关属性。

API相关介绍

  • 1.先介绍一下关于蓝牙4.0中的一些名词吧:
    (1)GATT(Gneric Attibute Profile)

    通过ble连接,读写属性类小数据Profile通用的规范。现在所有的ble应用Profile 都是基于GATT

    • (2)ATT(Attribute Protocal) GATT是基于ATT Potocal的ATT针对BLE设备专门做的具体就是传输过程中使用尽量少的数据,每个属性都有个唯一的UUID,属性chartcteristics and Service的形式传输。
    • (3)Service是Characteristic的集合。
    • (4).Characteristic 特征类型。

    比如。有个蓝牙ble的血压计。他可能包括多个Servvice,每个Service有包括多个Characteristic

    注意:蓝牙ble只能支持Android 4.3以上的系统 SDK>=18

  • 2.以下是开发的步骤:

  • 2.1首先获取BluetoothManager

  • 2.2获取BluetoothAdapter

  • 2.3创建BluetoothAdapter.LeScanCallback

  • 2.4.开始搜索设备。

  • 2.5.BluetoothDevice 描述了一个蓝牙设备 提供了getAddress()设备Mac地址,getName()设备的名称。

  • 2.6开始连接设备

  • 2.7连接到设备之后获取设备的服务(Service)和服务对应的Characteristic。

  • 2.8获取到特征之后,找到服务中可以向下位机写指令的特征,向该特征写入指令。

  • 2.9写入成功之后,开始读取设备返回来的数据。

  • 2.10、断开连接

  • 2.11、数据的转换方法

大概整体就是如上的步骤。但是也是要具体根据厂家的协议来实现通信的过程。

那么具体要怎么使用呢?我们据需开车往下走。

一.添加权限

  和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature:

// Use this check to determine whether BLE is supported on the device. Then
// you can selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}

第一步:开启蓝牙:

  • 1.首先获取有BluetoothAdapter两种方式:
private BluetoothManager bluetoothManager;

bluetoothManager =   (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();

或者是:

mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

两行方式都是可以的。

注:这里通过getSystemService获取BluetoothManager,再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。

  • 2.判断手机设备是否有蓝牙模块
// 检查设备上是否支持蓝牙
if (mBluetoothAdapter == null) {
showToast("没有发现蓝牙模块");
return;
}
  • 3.开启蓝牙设备

    开启蓝牙设备有两种方式:

    • 第一种直接简单暴力不给用户进行提示:
    if (!mBluetoothAdapter.isEnabled()) {
    mBluetoothAdapter.enable();
    }
    • 第二种直优雅的践行开启并且有弹框进行提示,隐式启动Intent:
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }
  • 4.扫描蓝牙设备

    我这里是把扫描到的BLE地址存放到List集合中去。这里我们可以写一个方法进行封装一下。

/***********
* 扫描设备
********/
private void scanLeDevice(final boolean enable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
if (enable) {
devices.clear();//清空集合
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
}, INTERVAL_TIME);
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
try {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} catch (Exception e) {
}
}
}
}

在这个扫描方法中,我们在AndroidStudio或者是Eclipse中会看到startLeScan方法会有横线,表明这个方式显示过期的方法,那么

如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。 其中UUID数组指定你的应用程序所支持的GATT Services的UUID。

那么LeScanCallback的初始化代码如下:

private void initCallBack(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (device != null) {
if (!TextUtils.isEmpty(device.getName())) {
// devices.add(device);
String name = device.getName();
if (name.contains(BluetoothDeviceAttr.OYGEN_DEVICE_NAME)) {
if (!devices.contains(device)) {
devices.add(device);
}
}
}
}
}
});
}
};
} else {
getToast("设备蓝牙版本过低");
return;
}
}

那么如果在设备多的情况下我们讲搜出很多的设备。我们可以选择我们所需要的地址进行链接。但是这类要注意的是:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索.

  • 5.进行链接设备
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

这里调用的是device的connectGatt方法

/**
* Connect to GATT Server hosted by this device. Caller acts as GATT client.
* The callback is used to deliver results to Caller, such as connection status as well
* as any further GATT client operations.
* The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
* GATT client operations.
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param autoConnect Whether to directly connect to the remote device (false)
* or to automatically connect as soon as the remote
* device becomes available (true).
* @throws IllegalArgumentException if callback is null
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
}

 api中阐述的是第一个参数是上下文对象Context,第二个参数是是否自动连接,第三个是蓝牙的GattCallback回调。

private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
// 这里有9个要实现的方法,看情况要实现那些,用到那些就实现那些
//当连接状态发生改变的时候
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){ };
//回调响应特征写操作的结果。
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){ };
//回调响应特征读操作的结果。
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
}
//当服务被发现的时候回调的结果
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
}
当连接能被被读的操作
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status);
}
......
};

 连接的过程我们一个通过service来进行连接,也可以在activity中进行操作。 好,到此为止,一个BLE蓝牙连接设备的整个流程我们已经清楚完毕。

Android4.x的蓝牙不太成熟性

 但是在实际操作过程中难免会出现一些比较坑人的问题。比如我用一个地址进行蓝牙设备连接,偶尔会出现蓝牙连接不上或者是说连接上设备后不返回数据等问题。那么此时我们可能会重启一下蓝牙或手机就立马有成功了。此时我们千万不能蒙蔽,也不要怀疑自己的人生。这是因为Android4.x的蓝牙还是不太成熟。目前可以来说是个测试阶段。

  • 手机可能会搜索不到蓝牙设备
  • 有时候会在广播中接收不到数据
  • 出现异常需要重新启动手机或者是重启才能恢复正常

这个时候我们怎么办呢?

此时不要抱怨什么,难到我们作为Android程序员就注定如此的苦逼吗?

答案是否定的。

如何去优化呢?那么我们就应该从UI界面,用户体验上进行操作来实现

  • 做一个定时器,如果在在确定蓝牙设备一打开并且存在的情况系,可以在手机搜索5s内没有搜索到蓝牙设备时重启蓝牙,并且在广播中接收到蓝牙开启后再次搜索

  • 可以在UI上进行对用户进行相对应的提示

    • 当蓝牙为启动时,提示用户去开启器蓝牙
    • 当蓝牙开启后,在处在开启状态后,提示用户蓝牙正在开启...
    • 蓝牙已开启,设备并没有连接上,提示用户去进行连接
    • 设备正在连接上手机,提示用户,正在连接,请等待...
    • 蓝牙设备连接上手机,正在读取,提示数据正在读取中...

    我们不能子在Android系统上来操作什么,我们在体验上做到了我们能做的就可以的。

手机蓝牙连接BLE设备要求

  • 手机Android 4.3以上的系统 SDK>=18
  • 蓝牙版本>=4.0

学习参考道demo下载地址: https://github.com/androidstarjack/Bluetooth_4.3-master

学到这里,关于AndroidBLE蓝牙连接我们已经基本上实现了蓝牙的搜索,连接,读取等。

大家项目中如果经常涉及到硬件比如手环,温度计,汗液仪,心电图,血压计等这些ble的蓝牙设备,就一定会用到蓝相关方面的知识。这里笔者先给大家提前踩一下坑,进行了总结,为后面的小伙伴在研究蓝牙方面尽量的少踩一些坑。如多对蓝牙的历程还未有清楚的认识,请参考深入了解Android蓝牙Bluetooth4.0——《基础篇》

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809    微信公众号:终端研发部

(欢迎关注学习和交流)

深入了解Android蓝牙Bluetooth——《进阶篇》的更多相关文章

  1. 深入了解Android蓝牙Bluetooth ——《总结篇》

    在我的上两篇博文中解说了有关android蓝牙的认识以及API的相关的介绍,蓝牙BLE的搜索,连接以及读取. 没有了解的童鞋们请參考: 深入了解Android蓝牙Bluetooth--<基础篇& ...

  2. android -- 蓝牙 bluetooth (三)搜索蓝牙

    接上篇打开蓝牙继续,来一起看下蓝牙搜索的流程,触发蓝牙搜索的条件形式上有两种,一是在蓝牙设置界面开启蓝牙会直接开始搜索,另一个是先打开蓝牙开关在进入蓝牙设置界面也会触发搜索,也可能还有其它触发方式,但 ...

  3. ZT android -- 蓝牙 bluetooth (三)搜索蓝牙

    android -- 蓝牙 bluetooth (三)搜索蓝牙 分类: Android的原生应用分析 2013-05-31 22:03 2192人阅读 评论(8) 收藏 举报 bluetooth蓝牙s ...

  4. ZT android -- 蓝牙 bluetooth (四)OPP文件传输

    android -- 蓝牙 bluetooth (四)OPP文件传输 分类: Android的原生应用分析 2013-06-22 21:51 2599人阅读 评论(19) 收藏 举报 4.2源码AND ...

  5. ZT android -- 蓝牙 bluetooth (二) 打开蓝牙

    android -- 蓝牙 bluetooth (二) 打开蓝牙 分类: Android的原生应用分析 2013-05-23 23:57 4773人阅读 评论(20) 收藏 举报 androidblu ...

  6. ZT android -- 蓝牙 bluetooth (五)接电话与听音乐

    android -- 蓝牙 bluetooth (五)接电话与听音乐 分类: Android的原生应用分析 2013-07-13 20:53 2165人阅读 评论(9) 收藏 举报 蓝牙android ...

  7. android -- 蓝牙 bluetooth (四)OPP文件传输

    在前面android -- 蓝牙 bluetooth (一) 入门文章结尾中提到了会按四个方面来写这系列的文章,前面已写了蓝牙打开和蓝牙搜索,这次一起来看下蓝牙文件分享的流程,也就是蓝牙应用opp目录 ...

  8. ZT android -- 蓝牙 bluetooth (一) 入门

    android -- 蓝牙 bluetooth (一) 入门 分类: Android的原生应用分析 2013-05-19 21:44 4543人阅读 评论(37) 收藏 举报 bluetooth4.2 ...

  9. 深入了解Android蓝牙Bluetooth——《基础篇》

    什么是蓝牙?   也可以说是蓝牙技术.所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的.利用"蓝牙"技术,能够有效地简化掌上电脑.笔记本电 ...

随机推荐

  1. Hadoop(十一)Hadoop IO之序列化与比较功能实现详解

    前言 上一篇给大家介绍了Hadoop是怎么样保证数据的完整性的,并且使用Java程序来验证了会产生.crc的校验文件.这一篇给大家分享的是Hadoop的序列化! 一.序列化和反序列化概述 1.1.序列 ...

  2. 阿里官方Java代码规范标准《阿里巴巴Java开发手册 终极版 v1.3.0》

    终极版 v1.3.0 2017年开春之际,阿里诚意献上重磅大礼:<阿里巴巴Java开发手册>,首次公开阿里官方Java代码规范标准.这套Java统一规范标准将有助于提高行业编码规范化水平, ...

  3. 使用LINQ TO XML 创建xml文档,以及读取xml文档把内容显示到GridView例子

    首先,准备了一个Model类 using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

  4. Linux入门(5)——Ubuntu16.04安装网易云音乐

    去网易云音乐官网下载deb包: http://music.163.com/#/download 打开终端: cd 下载 .0_amd64_ubuntu16..deb sudo apt-get -f i ...

  5. 单源最短路径问题-Dijkstra算法

    同样是层序遍历,在每次迭代中挑出最小的设置为已知 ===================================== 2017年9月18日10:00:03 dijkstra并不是完全的层序遍历 ...

  6. LINUX 笔记-特定shell变量

    $# 传递到脚本的参数个数 $* 以一个单字符串显示所有向脚本传递的参数.与位置变量不同,此选项参数可超过9个 $$ 脚本运行的当前进程ID号 $! 后台运行的最后一个进程的进程ID号 $@ 与$*相 ...

  7. .Net Core程序的部署(FDD与SCD)

    最近打算做一个公司的代码走查工具,思前想后觉得正好可以当作一个Core的实践机会,于是上官网看了下资料,顺便作了一下笔记方便以后查阅. 注1:这里的Core程序部署指的是.Net Core而非Asp. ...

  8. 数据权限设计——基于EntityFramework的数据权限设计方案:一种设计思路

    前言:“我们有一个订单列表,希望能够根据当前登陆的不同用户看到不同类型的订单数据”.“我们希望不同的用户能看到不同时间段的扫描报表数据”.“我们系统需要不同用户查看不同的生产报表列”.诸如此类,最近经 ...

  9. Model Representation and Cost Function

    Model Representation To establish notation for future use, we’ll use x(i) to denote the “input” vari ...

  10. 中高级JavaScript易错面试题

    写出下题的输出 1.函数的实参与形参length var length = 10; function fn() { console.log(this.length); } var obj = { le ...