To build a better world !

Android4.3 蓝牙BLE初步


Android4.3 蓝牙BLE初步

一、关键概念:

Generic Attribute Profile (GATT)
通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。
 
Attribute Protocol (ATT)
GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。
 
Characteristic
Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。
 
Descriptor
对Characteristic的描述,例如范围、计量单位等。
 
Service
Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。
 

二、角色和职责:

Android设备与BLE设备交互有两组角色:
 
中心设备和外围设备(Central vs. peripheral);
GATT server vs. GATT client.
 
Central vs. peripheral:
中心设备和外围设备的概念针对的是BLE连接本身。Central角色负责scan advertisement。而peripheral角色负责make advertisement。
 
GATT server vs. GATT client:
这两种角色取决于BLE连接成功后,两个设备间通信的方式。
 
举例说明:
现有一个活动追踪的BLE设备和一个支持BLE的Android设备。Android设备支持Central角色,而BLE设备支持peripheral角色。创建一个BLE连接需要这两个角色都存在,都仅支持Central角色或者都仅支持peripheral角色则无法建立连接。
 
当连接建立后,它们之间就需要传输GATT数据。谁做server,谁做client,则取决于具体数据传输的情况。例如,如果活动追踪的BLE设备需要向Android设备传输sensor数据,则活动追踪器自然成为了server端;而如果活动追踪器需要从Android设备获取更新信息,则Android设备作为server端可能更合适。
 
 

三、权限及feature:

和经典蓝牙一样,应用使用蓝牙,需要声明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();
}
 
 

四、启动蓝牙:

在使用蓝牙BLE之前,需要确认Android设备是否支持BLE feature(required为false时),另外要需要确认蓝牙是否打开。 
如果发现不支持BLE,则不能使用BLE相关的功能。如果支持BLE,但是蓝牙没打开,则需要打开蓝牙。
 
打开蓝牙的步骤:
 
1、获取BluetoothAdapter
 
BluetoothAdapter是Android系统中所有蓝牙操作都需要的,它对应本地Android设备的蓝牙模块,在整个系统中BluetoothAdapter是单例的。当你获取到它的示例之后,就能进行相关的蓝牙操作了。
 
获取BluetoothAdapter代码示例如下:
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
 
注:这里通过getSystemService获取BluetoothManager,再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。
 
2、判断是否支持蓝牙,并打开蓝牙
 
获取到BluetoothAdapter之后,还需要判断是否支持蓝牙,以及蓝牙是否打开。
如果没打开,需要让用户打开蓝牙:
private BluetoothAdapter mBluetoothAdapter;
...
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
 
 

五、搜索BLE设备:

通过调用BluetoothAdapter的startLeScan()搜索BLE设备。调用此方法时需要传入 BluetoothAdapter.LeScanCallback参数。
因此你需要实现 BluetoothAdapter.LeScanCallback接口,BLE设备的搜索结果将通过这个callback返回。
 
由于搜索需要尽量减少功耗,因此在实际使用时需要注意:
 
1、当找到对应的设备后,立即停止扫描;
2、不要循环搜索设备,为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描,消耗电量。
 
搜索的示例代码如下:
/**
 * Activity for scanning and displaying available BLE devices.
 */
public class DeviceScanActivity extends ListActivity {

    private BluetoothAdapter mBluetoothAdapter;
    private boolean mScanning;
    private Handler mHandler;

    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;
    ...
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
        ...
    }
...
}
 
如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。
其中UUID数组指定你的应用程序所支持的GATT Services的UUID。
 
 
BluetoothAdapter.LeScanCallback的实现示例如下:
private LeDeviceListAdapter mLeDeviceListAdapter;
...
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
        new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi,
            byte[] scanRecord) {
        runOnUiThread(new Runnable() {
           @Override
           public void run() {
               mLeDeviceListAdapter.addDevice(device);
               mLeDeviceListAdapter.notifyDataSetChanged();
           }
       });
   }
};
 
注意:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索。
 
 

六、连接GATT Server:

两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。
连接GATT Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:
 
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
 
函数成功,返回BluetoothGatt对象,它是GATT profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。
 
BluetoothGatt常规用到的几个操作示例:
 
connect() :连接远程设备。
discoverServices() : 搜索连接设备所支持的service。
disconnect():断开与远程设备的GATT连接。
close():关闭GATT Client端。
readCharacteristic(characteristic) :读取指定的characteristic。
setCharacteristicNotification(characteristic, enabled) :设置当指定characteristic值变化时,发出通知。
getServices() :获取远程设备所支持的services。
 
等等。
 
注:
1、某些函数调用之间存在先后关系。例如首先需要connect上才能discoverServices。
2、一些函数调用是异步的,需要得到的值不会立即返回,而会在BluetoothGattCallback的回调函数中返回。例如discoverServices与onServicesDiscovered回调,readCharacteristic与onCharacteristicRead回调,setCharacteristicNotification与onCharacteristicChanged回调等。
 
 

posted on 2013-12-09 20:27 zh.weir 阅读(60712) 评论(27)  编辑  收藏 所属分类: Android应用秘技

评论

# re: Android4.3 蓝牙BLE初步 2013-12-11 12:56 鹏达锁业

谢谢博主分享  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2013-12-23 20:20 yusy

我现在有个功能是 手机APP 向 硬件发送指令!
现在我使用上述方法链接上了设备 但是怎么去发送指令呢?
BluetoothGatt bluetoothGatt = DeviceActivity.bluetoothGatt;
BluetoothGattService service = bluetoothGatt.getService(
UUID.fromString("xx"));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("oo"));
characteristic.setValue(bytes);
bluetoothGatt.writeCharacteristic(characteristic);
这样可以吗? 如果可以 UUID 我要如何获得,不能随便找个UUID我试过了!
求博主解答,十万火急,真心感激不尽@鹏达锁业

  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2013-12-23 21:15 zh.weir

@yusy

肯定不能随便用个UUID啊。。。

建议你先看看你的BLE外设支持的service是什么,如果是用的Bluetooth SIG标准的Profile,你可以在https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx 这个网站找到对应的service和characteristic的UUID。如果不是标准的,你需要和对应的BLE外设方案商交流,以获得相关资料。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2014-02-04 23:20 Chris

您好
我現在正在嘗試要用Android手機讀取多個BLE設備的值
看完您的文章後
我發覺我原本的做法是Android爲Client端去向設備(Server)要資料
不過當我連線好兩個設備時
當其中一方開始傳送資料時
另一方就會自動斷線
不過單獨連線一個設備取資料都是沒問題的
想請問是不是Client端沒辦法同時連線多個Server?
感謝!  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2014-02-21 11:39 zh.weir

@Chris

应该是可以同时连接多个Server的。而且你也已经连上了。
BLE最好不用于传输较大的数据,只是简单的属性读写。大数据传输过程中,引起连接断开的情况经常发生,你可以抓下HCI log,看看连接断开的原因是什么。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-03-15 12:45 xchen

android设备可以作为 Periphreal role么  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2014-03-17 11:17 zh.weir

@xchen

目前还不支持。硬件应该是支持的,软件不支持。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-03-29 10:37 xchen

楼主 我用Android 设备作为中心设备 ,作为一个GATT Client端,去连接Ble设备。第一次是可以成功的,但是蓝牙断开后再次重连,发现连不上,从打印的状态看是已绑定状态。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2014-04-02 14:58 zh.weir

@xchen

这个应该是你程序逻辑的问题了。应该在蓝牙关闭时将ble设备断开。你可以看看onDisconnect回调是否有被正常调起。另外,一些Android手机在这一块确实存在系统稳定性的问题。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-04-15 22:46 xchen

@zh.weir
一直没解决 是协议层的问题 。谢谢了  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-04-30 16:00 cjolinss

请问 yusy 后来搞定了吗 我遇到同样问题能连上,但是不知道该法什么命令@zh.weir  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-07-05 13:49 zhangguangyuan

怎么一次读取多个UUID的值呢  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-07-05 13:51 zhangguangyuan

求指点
我是先写01 到下位机
这是会读取一个数据包
紧接着写02 到下位机,再度去一个数据包

可是第二个独步到?  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-08-09 16:50 龙xy

我能不能接收到蓝牙广播时的数据包,怎么接收。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2014-08-12 22:23 yang

楼主您好,请问有没有android移动设备作为服务端的程序说明,如果有请多多指教!  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2014-09-05 00:29 claymore

你好,楼主,我是一个Android开发新手,我想请教一个问题,就是GATT协议 Android是需要API19的,但是如何去兼容其他低版本的手机呢?  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-09-27 16:10 ming@

@xchen
我遇到和你一样的问题,请问你解决了没有?苦恼,一直解决不了  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-09-28 16:19 hewuhai

楼主好:
想做一个手机更新从机设备数据,手机作为主机连接从机,然后向从机发送400字节的数据,21byte数据包单包发送已经调通,我想采用分包的方式发送这400个字节,但是我不知道怎么确定每一包发送完成且收到正确,对于分包发送400byte的思路不会,请楼主多多指点哈!  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-11-24 10:33 Scienve

@hewuhai
可以把在每个数据包的包头前加上序号,主机收到一个校验序号是否连续,即可。  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2014-12-02 17:00 陈导

请问你如何实现一个client端与两个设备进行连接的??@Chris
  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2015-04-27 10:51 channing

请问 我现在需要将硬件设备的操作数据(比如按上键会发送11数据)传送到app上,如何调用方法呢?我现在已经可以通过app完成对硬件设备基本属性(比如电量等等)的读写。跪求大神指导!!  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2015-04-27 10:53 channing

@channing
简单来说就是用硬件对app进行操作,如何实现~麻烦你了~  回复  更多评论   

# re: Android4.3 蓝牙BLE初步[未登录] 2015-06-01 15:42 rock

@ming@
请问大神 有方法可以获得与手机连接的蓝牙设备的距离吗?  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2015-07-01 16:16 陆小安

我也试着用你的方法写,但是依旧只是能搜索出来但是连接不上,而且用官方的demo搜索出来了连接不上 手机用的是三星note4,那个蓝牙模块用ios的可以连上,Android就不行求助  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2015-07-26 06:56 jjxxjnzy

@陆小安
和你碰到了同样的问题,ios上完全是正常的,但是在android就存在问题,第一次扫描过后,可以正常连接,连接成功以后,给设备发送数据,之后设备断开,再次开启搜索,此时设备再也不能被搜索到了,请问你有解决这个问题吗  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2015-09-26 17:45 qishuai

@channing
@rock
@jjxxjnzy
同志们都遇到这样的问题了,,加个qq一起讨论下吧644172593  回复  更多评论   

# re: Android4.3 蓝牙BLE初步 2016-01-12 17:17 crystrl

您好 我是个新手 刚刚接触蓝牙4.3 我是在做物联网的项目 现在我的设备用listview把搜索到的蓝牙设备装起来了 现在设置了OnItemClickListener 在这个里面 我要怎么和item的蓝牙设备建立连接呢   回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

公告

大家好!欢迎光临我的 Android 技术博客!



本博客旨在交流与 Android 操作系统相关的各种技术及信息。

博客内的文章会尽量以开源的形式提供给大家,希望我们能相互交流,共同提高!

有不足之处,请不吝赐教!

我的邮箱:zh.weir@gmail.com
我的新浪微博:@囧虎张建伟

 

导航

<2016年1月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

留言簿(19)

随笔分类(24)

随笔档案(18)

文章档案(1)

搜索

最新评论

阅读排行榜

评论排行榜