精华内容
参与话题
问答
  • Android BLE开发之Android手机与BLE终端通信 程序文件

    千次下载 热门讨论 2014-04-21 20:06:20
    Android 4.3才开始支持BLE API,所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统,另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。 PS:我的i9100刷了4.4系统后,竟然也能跟BLE蓝牙模块通信...
  • android BLE

    万次阅读 2013-12-21 23:03:11
    android4.3 nei内置了ble并为上层app提供相应的接口来使用BLE功能。 BLE主要涉及的协议及术语: GenericAttribute Profile (GATT) BLE上层的协议都是基于GATT,它是一个通用的规范,通过BLE连接发送/接收...

    android4.3 nei内置了ble并为上层app提供相应的接口来使用BLE功能。


    BLE主要涉及的协议及术语:


    GenericAttribute Profile (GATT)

    BLE上层的协议都是基于GATT,它是一个通用的规范,通过BLE连接发送/接收属性值。


    bluetoothSIG定义了很多的ble协议。


    AttributeProtocol (ATT)

    GATT是建立在ATT之上。也被称为GATT/ATT


    ATT运行在ble设备上,所以被优化,尽可能的占用较少的字节。


    每一个属性被指定一个UUID,通过ATT传输的属性被格式化位特性(characteristics)或服务(services)。


    Characteristic

    一个特性包含一个单一的值和0-n个描述符(Descriptor)来描述这个特性值。一个特性可以被看作一个类型。


    Descriptor

    描述符被定义为属性,这些属性用来描述特性的值。

    例如:规定特性值的取值范围,特性值的单位等


    Service

    服务是一组特性的集合。例如:“心率检测”服务包含“心速测量”的特性。


    角色和职责

    中心与外围:被应用于BLE连接本身,中心角色设备扫描/寻找广播,外围设备角色发出广播。


    GATTserver vs. GATT client

    这个决定了两个设备在建立连接之后如何交互。


    android手机和BLE设备的区别:手机支持中心角色(centralrole),BLE设备支持peripheralrole


    一旦建立连接,他们就开始相互传输gatt数据,根据传输的数据的种类其中的一个可能作为服务器。

    如果BLE设备想报告数据给手机,它可能让BLE设备的传感器作为服务器。如果BLE设备准备接收来自手机的数据,手机的传感器就作为服务端。


    以上例子说明:androidapp GATT clientGATTclient GATT server 获取数据。也可以设计android app 作为GATTserver


    BLE权限:

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



    如果想把app提供给不支持BLE的设备需要设置android:required="fasle",然后在运行时进行判断:

    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
        finish();
    }



    设置BLE


    1:获取BluetoothAdapter


    BluetoothAdapter是所有蓝牙功能所必需的,整个系统只有一个BluetoothAdapter,获取BluetoothAdapter之后就可以进行各种蓝牙的操作了。

    // Initializes Bluetooth adapter.
    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();


    2:启动蓝牙

    通过isEnabled()判断是否启动,如果没有启动,通过下面的方式启动:

    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);
    }


    3:查找BLE设备

    通过startLeScan查找LE设备,并实现LeScanCallback作为参数。

    注意事项:1:一旦找到所查找的设备,立即停止扫描

    2:设置扫描超时,避免循环扫描。


    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);
            }
            ...
        }
    ...
    }



    如果需要查找特定类型的LE设备,需要使用startLeScan(UUID[],BluetoothAdapter.LeScanCallback()),提供一个你的设备支持的服务的UUID数组。


    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,两者不能同时搜索。


    连接GATTserver

    使用connectGatt连接到BLE设备的GATT server,

    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);



    将会返回一个BluetoothGatt实例,通过这个实例可以进行Gattclient的各种操作。调用者(androidapp)是GattclientGattCallback用来提供结果给客户端。


    读取BLE的属性

    如果androidapp已经连接了Gatt server并且发现了服务,就能够进行属性的读写了。



    收取Gatt的通知


    通常BLEapp需要被通知,如果BLE设备的特性发生了改变。

    使用setCharacteristicNotification方法为一个特性设置通知:

    private BluetoothGatt mBluetoothGatt;
    BluetoothGattCharacteristic characteristic;
    boolean enabled;
    ...
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    ...
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
            UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
    mBluetoothGatt.writeDescriptor(descriptor);


    一旦一个特性被设置为通知可用,远端设备的特性发生改变就会触发onCharacteristicChanged

    回调。

    @Override
    // Characteristic notification
    public void onCharacteristicChanged(BluetoothGatt gatt,
            BluetoothGattCharacteristic characteristic) {
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }


    关闭clientapp

    结束和BLE设备的通讯后,需要释放资源:

    public void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }


    展开全文
  • Android Ble

    千次阅读 2017-09-20 22:06:39
    蓝牙的历史? 1999年5月20日,索尼爱立信、IBM、英特尔、诺基亚及东芝等业界龙头创立蓝牙特别兴趣组(SIG,Special Interest Group),制订蓝牙技术标准。“蓝牙”(Bluetooth)这名称来自10世纪的丹麦国王哈拉尔德...

    蓝牙的历史?

    1999年5月20日,索尼爱立信、IBM、英特尔、诺基亚及东芝等业界龙头创立蓝牙特别兴趣组(SIG,Special Interest Group),制订蓝牙技术标准。“蓝牙”(Bluetooth)这名称来自10世纪的丹麦国王哈拉尔德(Harald Gormsson)的外号。出身海盗家庭的哈拉尔德统一了北欧四分五裂的国家,成为维京王国的国王。由于他喜欢吃蓝莓,牙齿常常被染成蓝色,而获得“蓝 牙”的绰号,当时蓝莓因为颜色怪异的缘故被认为是不适合食用的东西,因此这位爱尝新的国王也成为创新与勇于尝试的象征。1998年,爱立信公司希望无线通信技术能统一标准而取名“蓝芽”。蓝牙,或称为蓝芽,是一种无线个人局域网(Wireless PAN),最初由爱立信创制,后来由蓝牙技术联盟订定技术标准。据说因为此技术尚在萌芽的阶段,故将Bluetooth以“蓝芽”的中文译名在台湾进行商 业的注册,不过在2006年,该组织已将全球中文统一为“蓝牙”。

    什么是Ble?

    BLE 是Bluetooth Low Energy的缩写,又叫蓝牙4.0,区别于蓝牙3.0和之前的技术。BLE前身是NOKIA开发的Wibree技术,主要用于实现移动智能终端与周边配件之间的持续连接,是功耗极低的短距离无线通信技术,并且有效传输距离被提升到了100米以上,同时只需要一颗纽扣电池就可以工作数年之久。BLE是在蓝牙技术的基础上发展起来的,既同于蓝牙,又区别于传统蓝牙。BLE设备分单模和双模两种,双模简称BR,商标为Bluetooth Smart Ready,单模简称BLE或者LE,商标为Bluetooth Smart。Android是在4.3后才支持BLE,这可以解释不是所有蓝牙手机都支持BLE,而且支持BLE的蓝牙手机一般是双模的。


    Ble的工作原理?

    大概知道ble是什么东西后,我们就来了解下他的工作原理。想要了解原理,先搞清楚蓝牙通信之间的关系——主从关系

    蓝牙技术规定每一对设备之间进行蓝牙通讯时,必须一个为主角色,另一为从角色,才能进行通信,通信时,必须由主端进行查找,发起配对,建链成功后,双方即可收发数据。理论上,一个蓝牙主端设备,可同时与7个蓝牙从端设备进行通讯。一个蓝牙设备以主模式发起呼叫时,需要知道对方的蓝牙地址,配对密码等信息,配对完成后,可直接发起呼叫。这可以解释为什么有时无法连接蓝牙,有可能是连接的蓝牙设备过多。

    蓝牙内部详细的工作原理呢,由于个人能力有限就不详细讲述了,本系列文章主要是介绍下ble在android中的开发。


    Ble在android交互中的角色与职责:

    Android设备与BLE设备交互有两组角色:就是中心设备与周边设备了。如图所示:

    Ble开发的大概原理流程:

    Android ble蓝牙问题

     

    (1)蓝牙回调
    安卓4.4的蓝牙回调是在异步线程中(不在主线程),若要在蓝牙回调中执行更新界面的操作,记得切换到主线程去操作

     

     

    (2)三星手机兼容性问题
    connectGatt()方法在某些三星手机上只能在UI线程调用。

    备注:三星的手机是connet和disconnet还有connectGatt都要在UI线程中操作

     

     

    (3)Android L 新API
    Android L换了一套扫描设备的API:BluetoothLeScanner.startScan(List, ScanSettings, ScanCallback)

     

     

    (4)Android M新的权限(android 6.0 动态权限)
    Android M中必须拥有定位权限才能扫描BLE设备

     

    (4)连接不断开的问题
    别的BLE程序非法保留连接的设备可能会导致连接不能断开

     

    (5)异步问题
    读写Characteristic、Descriptor等几乎所有BLE操作结果都为异步返回,若不等待上一次操作结果返回就执行下一次操作,很可能导致操作失败或者操作无效。onDescriptorWrite()返回的线程与写入线程为同一个线程,别的操作一般在不同的线程回调。

     

     

    (6)设备缓存
    Android会对连接过的BLE设备的Services进行缓存,若设备升级后Services等有改动,则程序会出现通讯失败。此时就得刷新缓存,但是刷新缓存的方法并没有开放,这里只能使用反射来调用BluetoothGatt类中的refresh()方法:

    复制代码
    1 try {
    2   Method localMethod = mBluetoothGatt.getClass().getMethod("refresh");
    3   if (localMethod != null) {
    4       return (Boolean) localMethod.invoke(mBluetoothGatt);
    5   }
    6 } catch (Exception localException) {
    7   Log.e("refreshServices()", "An exception occured while refreshing device");
    8 }
    复制代码

     

    (7)扫描设备
    startLeScan(UUID[], BluetoothAdapter.LeScanCallback)

    在Android4.4及以下手机中似乎只支持16位的短UUID,不支持128位完整的UUID。

    (9)任何出错,超时,用完就马上调用Gatt.disconnect(), Gatt.close()。

    (10)从bindService 到 onServiceConnected 这个回调花费时间较长, onServiceConnected 这个回调很可能在 MainActivity onResume之后才执行, 所以不要指望onResume里去执行扫描,因为此时serviceConnected 回调都尚未执行

    (11)getBtAdapter().enable()是异步,立即返回,但从 off 到 on 的过程需要一个时间所以只能监听系统broadcast发出的intent里的state

    (12) 多次扫描蓝牙,在华为荣耀,魅族M3 NOTE 中有的机型,会发现多次断开–扫描–断开–扫描… 会扫描不到设备,此时需要在断开连接后,不能立即扫描,而是要先停止扫描后,过2秒再扫描才能扫描到设备。

    (13)扫描尽量不要放在主线程进行,可以放入子线程里。不然有些机型会出现 do too many work in main thread.

    (14)设备的gatt在不用时要及时关闭,系统支持的连接句柄数是有限的,当达到上限后无法再建立新的连接了。

    (15)当连接断开后要调closeGatt释放资源,不用调disconnect,也不要下次复用之前的gatt来reconnect,因为有的手机上重连可能会存在问题,比如重连后死活发现不了service。这种情况下,最好只要断开连接就close gatt,下次连接时打开全新的gatt,这样就可以发现service了。

    (16)BLE的特征一次读写最大长度20字节。

     (17)一个主设备(例如Android手机)可以同时连接多个从设备(一般为6个,例如智能硬件。超过就连接不上了),一个从设备只能被一个主设备连接,一旦从设备连接上主设备,就停止广播,断开连接则继续广播。在任何时刻都只能最多一个设备在尝试建立连接。如果同时对多个蓝牙设备发起建立Gatt连接请求。如果前面的设备连接失败了,则后面的设备请求会被永远阻塞住,不会有任何连接回调。所以建议:如果要对多个设备发起连接请求,最好是一个接一个的顺序同步请求管理。

    (18)对蓝牙设备的操作不能并行,只能串行,即每次都要在收到上一个操作的回调后才能继续下一个操作。但是断开连接例外,断开连接要马上closeGatt,不用等任务队列中的其他操作了。而且要给所有正在执行或者准备执行的任务都cancel。

    (19)有时候蓝牙协议栈出现异常可能收不到回调,所以我们要对每个操作做超时检查,否则后面的所有操作都被阻塞了。

    (20)对于超时的任务,最好closeGatt,下次重新连接的时候重开一个gatt。

    (21)蓝牙连接可能不稳定,最好支持失败自动重试机制,尤其是连接和发现服务,因为80%的问题都发生在建立连接和发现服务的时候,而且这一块也是最耗时的。

    (22)Android 从 4.3(API Level 18) 开始支持低功耗蓝牙,但是只支持作为中心设备 (Central) 模式,这就意味着 Android 设备只能主动扫描和链接其他外围设备 (Peripheral)。从Android 5.0(API Level 21)开始两种模式都支持。BLE 官方文档在  这里 。 

    (23)

    在  BluetoothAdapter.startLeScan() 的时候,在 BluetoothAdapter.LeScanCallback.onLeScan() 中不能做太多事情,特别是周围的BLE设备多的时候

    开发建议:在  onLeScan() 回调中只做尽量少的工作,可以把扫描到的设备,扔到另外一个线程中去处理,让  onLeScan() 尽快返回。 

    (24)BLE 设备的建立和断开连接的操作,例如 BluetoothDevice.connectGatt() ,  BluetoothGatt.connect() , BluetoothGatt.disconnect() 等操作最好都放在主线程中,否则你会遇到很多意想不到的麻烦。 

    开发建议:对  BluetoothGatt 的连接和断开请求,都通过发送消息到 Android 的主线程中,让主线程来执行具体的操作。例如创建一个  new Handler(context.getMainLooper()); ,把消息发送到这个  Handler中。 

     (25)

    如果你在开发 BLE 应用的时候,有时候会发现系统的功耗明显增加了,查看电量使用情况,蓝牙功耗占比非常高,好像低功耗是徒有虚名。使用  adb bugreport 获取的了系统信息,分析发现一个名叫 BluetoothRemoteDevices 的  WakeLock 锁持有时间非常长,导致系统进入不了休眠。分析源代码发现,在连接 BLE 设备的过程中,系统会持有 (Aquire) 这个  WakeLock ,直到连接上或者主动断开连接(调用  disconnect() )才会释放。如果BLE设备不在范围内,这个超时时间大约为30s,而这时你可能又要尝试重新连接,这个  WakeLock 有被重新持有,这样系统就永远不能休眠了。 

    开发建议:对BLE设备连接,连接过程要尽量短,如果连接不上,不要盲目进行重连,否这你的电池会很快被消耗掉。这个情况,实际上对传统蓝牙设备连接也是一样。  [  参考帖子 ] 

    (26)

    Android 作为中心设备,最多只能同时连接 6 个 BLE 外围设备(可能不同的设备这个数字不一样),超过 6 个,就会连接不上了。现在 BLE 设备越来越多,其实并不够用,所以在开发的过程中,需要特别的谨慎使用。

    开发建议:按照需要连接设备,如果设备使用完了,应该马上释放连接(调用 BluetoothGatt.close() ),腾出系统资源给其他可能的设备连接。  













    展开全文
  • Android BLE

    千次阅读 2015-08-15 17:21:58
    Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的API,应用程序通过这些api可以扫描设备、查询services,读写设备的characteristics(属性特征)。对比传统的...

    Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的API,应用程序通过这些api可以扫描设备、查询services,读写设备的characteristics(属性特征)。对比传统的蓝牙,BLE的设计能够显著减低功耗。这让Android应用程序与BLE设备之间的低功耗通讯成为可能,例如距离传感器、心率监视器、健身设备等等。


    1、关键术语和概念


    1.1 下面是一些BLE关键术语和概念的摘要:


    * Generic Attribute Profile(GATT):GATT profile是一种关于发送和接收简短数据片段的一般规范,这种简短数据片段例如在BLE的连接上众所周知的“attribute(属性)”等。当前所有低功耗应用程序的profile都基于GATT。另外,蓝牙技术联盟(Bluetooth SIG)已经为很多BLE设备定义了profile。profile就是一种在指定的应用程序中定义设备如何工作的规范。注意,一台设备可以实现多个profile。例如,一台设备可以包含心率监视器和电池电量探测器。
    * Attribute Protocol(ATT,属性协议):GATT构建在ATT的基础之上,因此也总被成为GATT/ATT。ATT针对BLE设备的运行进行了优化。为此,它会尽可能的使用更少的字节数据。每一个属性都通过UUID来唯一确定。UUID就是一个标准128位格式的字符串ID,用于唯一确定一个信息。属性通过ATT协议格式化为characteristics和services后进行传输。
    * Characteristic:一个characteristic中包含一个值,以及0个或多个用于描述characteristic值的descriptor。可以将characteristic认为是一种类型,类似于一个类。
    * Descriptor:Descriptor(描述符)中定义的属性用于描述一个characteristic值。例如,一个descriptor可以为一个characteristic的值指定一个在可接受范围内的可读性描述,或者为一个characteristic的值指定一个计量单位。
    * Service:
    一个service是一个characteristic的集合。例如,你可以持有一个名为“心率监视器”的service,它包含的characteristic例如“心率测量”。你可以在bluetooth.org上找到一系列基于GATT的profile和service。


    1.2 角色和职能


    以下是一台Android设备与BLE设备交互时的一些适用角色和职能:


    * 中央设备和外围设备。这适用于BLE自身的连接。担任中央设备角色的设备负责扫描和搜索广告,担任外围设备的角色负责发送广告。

    * GATT服务端和GATT客户端。这取决于两台设备在建立连接后如何互相通信。


    为了理解这之间的区别,想象你有一台Android手机和一台BLE设备作为活动追踪器。手机将担任中央设备角色;活动追踪器将担任外围设备角色(你需要具备两种角色才能建立一个BLE连接,两者都担任外围设备角色不能互相通信,同样两者都担任中央设备角色也不能互相通信)。


    一旦手机和活动追踪器建立连接,它们就可以互相传输GATT媒体数据。根据它们传输的数据,其中一方需要担任服务端的角色。例如,如果活动追踪器想要发送传感器数据给手机,活动追踪器就需要担任服务端的角色。如果活动追踪器想要接收手机的数据,手机就需要担任服务端的角色。


    在本片文档的例子中,Android应用程序(运行在Android设备上)是GATT客户端。应用程序从GATT服务端获取数据,这个服务端由支持Heart Rate Profile的BLE心率监视器设备担任。但是你可以交替让你的Android应用程序扮演GATT服务端的角色。具体参考BluetoothGattService


    2、BLE Permissions(BLE权限)


    为了在你的应用程序中使用Bluetooth的功能,你必须声明android.permission.BLUETOOTH权限。你需要这个权限来执行一些蓝牙通信的操作,例如请求链接,接受连接,还有传输数据。


    如果你想让你的应用程序进行设备扫描或者管理蓝牙设置,你必须同时声明android.permission.BLUETOOTH_ADMIN权限。注意,如果你使用BLUETOOTH_ADMIN权限,你必须同时声明BLUETOOTH权限。


    在你的应用程序manifest文件中声明蓝牙权限,例如:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    1. <uses-permission android:name="android.permission.BLUETOOTH"/>  
    2. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>  

    如果你想声明你的应用程序只能在支持BLE的设备上运行,可以将下面声明包含进你的应用程序manifest文件中:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    1. <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>  

    然而,如果你想让你的应用程序也能够在不支持BLE的设备上运行,你就应该将上面标签中的属性设置为required="false"。然后在运行的过程中使用PackageManager.hasSystemFeature()方法来判断设备是否支持BLE:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. // 使用下面的方法来确定设备是否支持BLE, 然后你可以选择禁用BLE的功能  
    2. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {  
    3.     Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();  
    4.     finish();  
    5. }  

    3、Setting Up BLE(设置BLE)


    在你的应用程序通过BLE进行通信之前,你需要确认设备是否支持BLE。如果支持,还要再确认是否已经启用。注意这个检查步骤只有在<uses-festure.../>设置为false的情况下才需要执行。


    如果不支持BLE,你应该优雅的禁止一些使用BLE的功能。如果支持BLE,但是目前禁用了,那么你需要在不离开你的应用程序状态下,请求用户启用蓝牙用能。这个过程需要使用BluetoothAdapter,分两个步骤完成:


    3.1 获取BluetoothAdapter。


    基本上所有使用蓝牙的activity都需要BluetoothAdapter。BluetoothAdapter代表了设备本身的蓝牙适配器(蓝牙发送接收器)。在整个系统中有一个BluetoothAdapter对象,你的应用程序可以使用这个对象进行交互。下面的代码片段展示了如果获取这个适配器。注意下面的这种方法使用getSystemService()方法来获取一个BluetoothManager实例,之后再通过BluetoothManager获取BluetoothAdapter。Android 4.3(API Level 18)才开始支持BluetoothManager:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. // 初始化蓝牙适配器.  
    2. final BluetoothManager bluetoothManager =  
    3.         (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);  
    4. mBluetoothAdapter = bluetoothManager.getAdapter();  

    3.2 启用蓝牙


    下一步,你需要确保蓝牙已经启动。调用isEnable()方法来检查蓝牙当前是否已经启用。如果方法返回false,说明蓝牙被禁用了。下面的代码片段中检查蓝牙是否已经启用。如果没有启用,代码片段会显示一个错误提示用户去设置中启用蓝牙:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. private BluetoothAdapter mBluetoothAdapter;  
    2. ...  
    3. // 确认设备支持蓝牙并且已经启用. 如果没有,  
    4. // 显示一个对话框要求用户授权启用蓝牙.  
    5. if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {  
    6.     Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
    7.     startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);  
    8. }  

    4、Finding BLE Devices(搜索BLE设备)


    搜索BLE设备,你可以使用startLeScan()方法。这个方法需要一个BluetoothAdapter.LeScanCallback对象作为参数。你必须实现这个callback接口,因为扫描的结果会通过这个接口返回。由于搜索设备是比较耗电的操作,你应该遵循以下指南使用:


     一旦你找到目标设备,应该马上停止搜索。

    *  不要死循环搜索,并设置搜索的最长时间。一台以前可以访问的设备可能已经移出了可检测范围,继续扫描只会消耗电量。


    下面的代码片段展示了如何开始和停止搜索:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. /** 
    2.  * 扫描和显示可访问BLE设备的Activity. 
    3.  */  
    4. public class DeviceScanActivity extends ListActivity {  
    5.   
    6.     private BluetoothAdapter mBluetoothAdapter;  
    7.     private boolean mScanning;  
    8.     private Handler mHandler;  
    9.   
    10.     // 10秒钟后停止扫描.  
    11.     private static final long SCAN_PERIOD = 10000;  
    12.     ...  
    13.     private void scanLeDevice(final boolean enable) {  
    14.         if (enable) {  
    15.             // 在预定义的扫描时间周期后停止扫描.  
    16.             mHandler.postDelayed(new Runnable() {  
    17.                 @Override  
    18.                 public void run() {  
    19.                     mScanning = false;  
    20.                     mBluetoothAdapter.stopLeScan(mLeScanCallback);  
    21.                 }  
    22.             }, SCAN_PERIOD);  
    23.   
    24.             mScanning = true;  
    25.             mBluetoothAdapter.startLeScan(mLeScanCallback);  
    26.         } else {  
    27.             mScanning = false;  
    28.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
    29.         }  
    30.         ...  
    31.     }  
    32. ...  
    33. }  

    如果你只想搜索指定类型的外围设备,你可以替换成startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法,并提供一个你的应用程序所支持的GATT服务的UUID对象数组。


    下面是一个BluetoothAdapter.LeScanCallback的实现,它是一个用于接收BLE搜索结果的接口:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. private LeDeviceListAdapter mLeDeviceListAdapter;  
    2. ...  
    3. // 设备搜索回调接口.  
    4. private BluetoothAdapter.LeScanCallback mLeScanCallback =  
    5.         new BluetoothAdapter.LeScanCallback() {  
    6.     @Override  
    7.     public void onLeScan(final BluetoothDevice device, int rssi,  
    8.             byte[] scanRecord) {  
    9.         runOnUiThread(new Runnable() {  
    10.            @Override  
    11.            public void run() {  
    12.                mLeDeviceListAdapter.addDevice(device);  
    13.                mLeDeviceListAdapter.notifyDataSetChanged();  
    14.            }  
    15.        });  
    16.    }  
    17. };  

    注意:正如Bluetooth文档中所描述的,在同一个时间你只能搜索BLE设备或者搜索传统蓝牙设备。你不能同时搜索BLE设备和传统蓝牙设备。


    5、Connecting to a GATT Server(连接一个GATT服务)


    与BLE设备交互的第一步就是要连接上它——更准确的说,是连接设备上的GATT服务。连接BLE设备上的GATT服务,你可以使用connectGatt()方法。这个方法需要三个参数:一个Context对象,autoConnect(一个表示是否当BLE设备可访问时马上自动连接的boolean值),还有一个BluetoothGattCallbackduixiang:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. mBluetoothGatt = device.connectGatt(thisfalse, mGattCallback);  

    上面的代码会连接BLE设备管理的GATT服务,并返回一个BluetoothGatt实例,通过这个实例就可以执行GATT客户端的相关操作。这个调用者(Android应用程序)就是GATT客户端。里面的BluetoothGattCallback对象用于交付操作结果给客户端,例如连接状态,还有将来一些GATT客户端操作的结果。


    在这个例子中,BLE应用程序提供了一个activity(DeviceControlActivity)来连接、显示数据,和显示BLE设备所支持的GATT的service以及characteristic。基于用户的输入,这个activity会和一个名为BluetoothLeService的Service通信,这个service通过Android BLE的API与BLE设备进行交互。

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. // 一个通过Android BLE API与BLE设备进行交互的service.  
    2. public class BluetoothLeService extends Service {  
    3.     private final static String TAG = BluetoothLeService.class.getSimpleName();  
    4.   
    5.     private BluetoothManager mBluetoothManager;  
    6.     private BluetoothAdapter mBluetoothAdapter;  
    7.     private String mBluetoothDeviceAddress;  
    8.     private BluetoothGatt mBluetoothGatt;  
    9.     private int mConnectionState = STATE_DISCONNECTED;  
    10.   
    11.     private static final int STATE_DISCONNECTED = 0;  
    12.     private static final int STATE_CONNECTING = 1;  
    13.     private static final int STATE_CONNECTED = 2;  
    14.   
    15.     public final static String ACTION_GATT_CONNECTED =  
    16.             "com.example.bluetooth.le.ACTION_GATT_CONNECTED";  
    17.     public final static String ACTION_GATT_DISCONNECTED =  
    18.             "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";  
    19.     public final static String ACTION_GATT_SERVICES_DISCOVERED =  
    20.             "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";  
    21.     public final static String ACTION_DATA_AVAILABLE =  
    22.             "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";  
    23.     public final static String EXTRA_DATA =  
    24.             "com.example.bluetooth.le.EXTRA_DATA";  
    25.   
    26.     public final static UUID UUID_HEART_RATE_MEASUREMENT =  
    27.             UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);  
    28.   
    29.     // BLE API定义的各个回调方法.  
    30.     private final BluetoothGattCallback mGattCallback =  
    31.             new BluetoothGattCallback() {  
    32.         @Override  
    33.         public void onConnectionStateChange(BluetoothGatt gatt, int status,  
    34.                 int newState) {  
    35.             String intentAction;  
    36.             if (newState == BluetoothProfile.STATE_CONNECTED) {  
    37.                 intentAction = ACTION_GATT_CONNECTED;  
    38.                 mConnectionState = STATE_CONNECTED;  
    39.                 broadcastUpdate(intentAction);  
    40.                 Log.i(TAG, "连接GATT服务.");  
    41.                 Log.i(TAG, "尝试开始service搜索:" +  
    42.                         mBluetoothGatt.discoverServices());  
    43.   
    44.             } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {  
    45.                 intentAction = ACTION_GATT_DISCONNECTED;  
    46.                 mConnectionState = STATE_DISCONNECTED;  
    47.                 Log.i(TAG, "断开GATT server连接.");  
    48.                 broadcastUpdate(intentAction);  
    49.             }  
    50.         }  
    51.   
    52.         @Override  
    53.         // New services discovered  
    54.         public void onServicesDiscovered(BluetoothGatt gatt, int status) {  
    55.             if (status == BluetoothGatt.GATT_SUCCESS) {  
    56.                 broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);  
    57.             } else {  
    58.                 Log.w(TAG, "onServicesDiscovered received: " + status);  
    59.             }  
    60.         }  
    61.   
    62.         @Override  
    63.         // Result of a characteristic read operation  
    64.         public void onCharacteristicRead(BluetoothGatt gatt,  
    65.                 BluetoothGattCharacteristic characteristic,  
    66.                 int status) {  
    67.             if (status == BluetoothGatt.GATT_SUCCESS) {  
    68.                 broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);  
    69.             }  
    70.         }  
    71.      ...  
    72.     };  
    73. ...  
    74. }  

    当一个特定的的回调方法被调用的时候,它就会适当调用broadcastUpdate()帮助方法并传递一个操作标识。注意本节中的数据是根据蓝牙心率测量的profile规范解析的:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. private void broadcastUpdate(final String action) {  
    2.     final Intent intent = new Intent(action);  
    3.     sendBroadcast(intent);  
    4. }  
    5.   
    6. private void broadcastUpdate(final String action,  
    7.                              final BluetoothGattCharacteristic characteristic) {  
    8.     final Intent intent = new Intent(action);  
    9.   
    10.     // 按照心率测量的profile进行的特定处理.  
    11.     // 按照么一个profile规范进行数据解析.  
    12.     if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {  
    13.         int flag = characteristic.getProperties();  
    14.         int format = -1;  
    15.         if ((flag & 0x01) != 0) {  
    16.             format = BluetoothGattCharacteristic.FORMAT_UINT16;  
    17.             Log.d(TAG, "Heart rate format UINT16.");  
    18.         } else {  
    19.             format = BluetoothGattCharacteristic.FORMAT_UINT8;  
    20.             Log.d(TAG, "Heart rate format UINT8.");  
    21.         }  
    22.         final int heartRate = characteristic.getIntValue(format, 1);  
    23.         Log.d(TAG, String.format("Received heart rate: %d", heartRate));  
    24.         intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));  
    25.     } else {  
    26.         // 针对其他profiles, 将数据格式化为16禁止数据.  
    27.         final byte[] data = characteristic.getValue();  
    28.         if (data != null && data.length > 0) {  
    29.             final StringBuilder stringBuilder = new StringBuilder(data.length);  
    30.             for(byte byteChar : data)  
    31.                 stringBuilder.append(String.format("%02X ", byteChar));  
    32.             intent.putExtra(EXTRA_DATA, new String(data) + "\n" +  
    33.                     stringBuilder.toString());  
    34.         }  
    35.     }  
    36.     sendBroadcast(intent);  
    37. }  


    回到DeviceControlActivity,下面的事件通过一个BroadcaseReceiver处理:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. // 处理Service发送过来的各种时间.  
    2. // ACTION_GATT_CONNECTED: 连接上了一个GATT服务.  
    3. // ACTION_GATT_DISCONNECTED: 断开了一个GATT服务.  
    4. // ACTION_GATT_SERVICES_DISCOVERED: 发现了GATT服务.  
    5. // ACTION_DATA_AVAILABLE: 从设备接收到数据. 这里可能是一个读取或者通知操作的结果。  
    6. private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {  
    7.     @Override  
    8.     public void onReceive(Context context, Intent intent) {  
    9.         final String action = intent.getAction();  
    10.         if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {  
    11.             mConnected = true;  
    12.             updateConnectionState(R.string.connected);  
    13.             invalidateOptionsMenu();  
    14.         } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {  
    15.             mConnected = false;  
    16.             updateConnectionState(R.string.disconnected);  
    17.             invalidateOptionsMenu();  
    18.             clearUI();  
    19.         } else if (BluetoothLeService.  
    20.                 ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {  
    21.             // 显示所有支持的service和characteristic。  
    22.             displayGattServices(mBluetoothLeService.getSupportedGattServices());  
    23.         } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {  
    24.             displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));  
    25.         }  
    26.     }  
    27. };  

    6、Reading BLE Attribute(读取BLE属性)


    一旦你的Android应用程序连接上了一个GATT服务并且发现了设备上的service,就可以在支持读写的地方读写属性。例如,下面的代码片段通过迭代服务的service和characteristic,并将它们显示在界面上:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. public class DeviceControlActivity extends Activity {  
    2.     ...  
    3.     // 演示如何迭代所支持的GATT Services/Characteristics.  
    4.     // 在这个例子中,我们填充绑定到ExpandableListView的数据结构。  
    5.     private void displayGattServices(List<BluetoothGattService> gattServices) {  
    6.         if (gattServices == nullreturn;  
    7.         String uuid = null;  
    8.         String unknownServiceString = getResources().  
    9.                 getString(R.string.unknown_service);  
    10.         String unknownCharaString = getResources().  
    11.                 getString(R.string.unknown_characteristic);  
    12.         ArrayList<HashMap<String, String>> gattServiceData =  
    13.                 new ArrayList<HashMap<String, String>>();  
    14.         ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData  
    15.                 = new ArrayList<ArrayList<HashMap<String, String>>>();  
    16.         mGattCharacteristics =  
    17.                 new ArrayList<ArrayList<BluetoothGattCharacteristic>>();  
    18.   
    19.         // 循环迭代可访问的GATT Services.  
    20.         for (BluetoothGattService gattService : gattServices) {  
    21.             HashMap<String, String> currentServiceData =  
    22.                     new HashMap<String, String>();  
    23.             uuid = gattService.getUuid().toString();  
    24.             currentServiceData.put(  
    25.                     LIST_NAME, SampleGattAttributes.  
    26.                             lookup(uuid, unknownServiceString));  
    27.             currentServiceData.put(LIST_UUID, uuid);  
    28.             gattServiceData.add(currentServiceData);  
    29.   
    30.             ArrayList<HashMap<String, String>> gattCharacteristicGroupData =  
    31.                     new ArrayList<HashMap<String, String>>();  
    32.             List<BluetoothGattCharacteristic> gattCharacteristics =  
    33.                     gattService.getCharacteristics();  
    34.             ArrayList<BluetoothGattCharacteristic> charas =  
    35.                     new ArrayList<BluetoothGattCharacteristic>();  
    36.            // 循环迭代可访问的Characteristics.  
    37.             for (BluetoothGattCharacteristic gattCharacteristic :  
    38.                     gattCharacteristics) {  
    39.                 charas.add(gattCharacteristic);  
    40.                 HashMap<String, String> currentCharaData =  
    41.                         new HashMap<String, String>();  
    42.                 uuid = gattCharacteristic.getUuid().toString();  
    43.                 currentCharaData.put(  
    44.                         LIST_NAME, SampleGattAttributes.lookup(uuid,  
    45.                                 unknownCharaString));  
    46.                 currentCharaData.put(LIST_UUID, uuid);  
    47.                 gattCharacteristicGroupData.add(currentCharaData);  
    48.             }  
    49.             mGattCharacteristics.add(charas);  
    50.             gattCharacteristicData.add(gattCharacteristicGroupData);  
    51.          }  
    52.     ...  
    53.     }  
    54. ...  
    55. }  


    7、Receiving GATT Notification(接收GATT通知)


    BLE应用程序要求在设备的某个指定characteristic改变的时候接收到通知是很常见。下面的代码片段展示了如何通过使用setCharacteristicNotification()为一个characteristic设置通知:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. private BluetoothGatt mBluetoothGatt;  
    2. BluetoothGattCharacteristic characteristic;  
    3. boolean enabled;  
    4. ...  
    5. mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);  
    6. ...  
    7. BluetoothGattDescriptor descriptor = characteristic.getDescriptor(  
    8.         UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));  
    9. descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);  
    10. mBluetoothGatt.writeDescriptor(descriptor);  

    一旦为一个characteristic启用了通知,当远程设备上的characteristic改变的时候就会触发onCharacteristicChanged()方法:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. @Override  
    2. // Characteristic notification  
    3. public void onCharacteristicChanged(BluetoothGatt gatt,  
    4.         BluetoothGattCharacteristic characteristic) {  
    5.     broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);  
    6. }  

    8、Closing the Client App(关闭客户端应用程序)


    一旦你的应用程序使用完BLE设备,你应该调用close()方法,这样系统才能适当释放占用的资源:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. public void close() {  
    2.     if (mBluetoothGatt == null) {  
    3.         return;  
    4.     }  
    5.     mBluetoothGatt
    展开全文
  • android ble

    2016-08-14 23:19:57
    Android-ble Android蓝牙4.0操作demo 最近,随着智能穿戴式设备、智能医疗以及智能家居的普及,蓝牙开发在移动开中显得非常的重要。由于公司需要,研究了一下,蓝牙4.0在Android中的应用。以下是我的一些总结。 ...

    Android-ble

    Android蓝牙4.0操作demo 最近,随着智能穿戴式设备、智能医疗以及智能家居的普及,蓝牙开发在移动开中显得非常的重要。由于公司需要,研究了一下,蓝牙4.0在Android中的应用。以下是我的一些总结。

          #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
    

    BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    # 2.2获取BluetoothAdapter

    BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();

     # 2.3创建BluetoothAdapter.LeScanCallback
    

    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

        @Override  
        public void onLeScan(final BluetoothDevice device, int rssi, final byte[] scanRecord) {  
    
            runOnUiThread(new Runnable() {  
                @Override  
                public void run() {  
                    try {  
                        String struuid = NumberUtils.bytes2HexString(NumberUtils.reverseBytes(scanRecord)).replace("-", "").toLowerCase();  
                        if (device!=null && struuid.contains(DEVICE_UUID_PREFIX.toLowerCase())) {  
                            mBluetoothDevices.add(device);  
                        }  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            });  
        }  
    };  
    
    # 2.4.开始搜索设备。
    

    mBluetoothAdapter.startLeScan(mLeScanCallback);

    #2.5.BluetoothDevice 描述了一个蓝牙设备 提供了getAddress()设备Mac地址,getName()设备的名称。 #2.6开始连接设备

    /** * Connects to the GATT server hosted on the Bluetooth LE device. *
    * @param address * The device address of the destination device. *
    * @return Return true if the connection is initiated successfully. The * connection result is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */
    public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
    Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
    return false;
    }

        // Previously connected device. Try to reconnect. (先前连接的设备。 尝试重新连接)  
        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {  
            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");  
            if (mBluetoothGatt.connect()) {  
                mConnectionState = STATE_CONNECTING;  
                return true;  
            } else {  
                return false;  
            }  
        }  
    
        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);  
        Log.d(TAG, "Trying to create a new connection.");  
        mBluetoothDeviceAddress = address;  
        mConnectionState = STATE_CONNECTING;  
        return true;  
    }  
    

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

    // Demonstrates how to iterate through the supported GATT
    // Services/Characteristics.
    // In this sample, we populate the data structure that is bound to the
    // ExpandableListView
    // on the UI.
    private void displayGattServices(List gattServices) {
    if (gattServices == null)
    return;
    String uuid = null;
    ArrayList> gattServiceData = new ArrayList<>();
    ArrayList>> gattCharacteristicData = new ArrayList<>();

    mGattCharacteristics = new ArrayList<>();  
    
    // Loops through available GATT Services.  
    for (BluetoothGattService gattService : gattServices) {  
        HashMap<String, String> currentServiceData = new HashMap<>();  
        uuid = gattService.getUuid().toString();  
        if (uuid.contains("ba11f08c-5f14-0b0d-1080")) {//服务的uuid  
            //System.out.println("this gattService UUID is:" + gattService.getUuid().toString());  
            currentServiceData.put(LIST_NAME, "Service_OX100");  
            currentServiceData.put(LIST_UUID, uuid);  
            gattServiceData.add(currentServiceData);  
            ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<>();  
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();  
            ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<>();  
    
            // Loops through available Characteristics.  
            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {  
                charas.add(gattCharacteristic);  
                HashMap<String, String> currentCharaData = new HashMap<>();  
                uuid = gattCharacteristic.getUuid().toString();  
                if (uuid.toLowerCase().contains("cd01")) {  
                    currentCharaData.put(LIST_NAME, "cd01");  
                } else if (uuid.toLowerCase().contains("cd02")) {  
                    currentCharaData.put(LIST_NAME, "cd02");  
                } else if (uuid.toLowerCase().contains("cd03")) {  
                    currentCharaData.put(LIST_NAME, "cd03");  
                } else if (uuid.toLowerCase().contains("cd04")) {  
                    currentCharaData.put(LIST_NAME, "cd04");  
                } else {  
                    currentCharaData.put(LIST_NAME, "write");  
                }  
    
                currentCharaData.put(LIST_UUID, uuid);  
                gattCharacteristicGroupData.add(currentCharaData);  
            }  
    
            mGattCharacteristics.add(charas);  
    
            gattCharacteristicData.add(gattCharacteristicGroupData);  
    
            mCharacteristicCD01 = gattService.getCharacteristic(UUID.fromString("0000cd01-0000-1000-8000-00805f9b34fb"));  
            mCharacteristicCD02 = gattService.getCharacteristic(UUID.fromString("0000cd02-0000-1000-8000-00805f9b34fb"));  
            mCharacteristicCD03 = gattService.getCharacteristic(UUID.fromString("0000cd03-0000-1000-8000-00805f9b34fb"));  
            mCharacteristicCD04 = gattService.getCharacteristic(UUID.fromString("0000cd04-0000-1000-8000-00805f9b34fb"));  
            mCharacteristicWrite = gattService.getCharacteristic(UUID.fromString("0000cd20-0000-1000-8000-00805f9b34fb"));  
    
            //System.out.println("=======================Set Notification==========================");  
            // 开始顺序监听,第一个:CD01  
            mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD01, true);  
            mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD02, true);  
            mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD03, true);  
            mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD04, true);  
        }  
    }  
    

    }

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

    public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {  
            Log.w(TAG, "BluetoothAdapter not initialized");  
            return;  
        }  
    
        mBluetoothGatt.writeCharacteristic(characteristic);  
    
    }  
    

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

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    String intentAction;
    //System.out.println("=======status:" + status);
    if (newState == BluetoothProfile.STATE_CONNECTED) {
    intentAction = ACTION_GATT_CONNECTED;
    mConnectionState = STATE_CONNECTED;
    broadcastUpdate(intentAction);
    Log.i(TAG, "Connected to GATT server.");
    // Attempts to discover services after successful connection.
    Log.i(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {  
                intentAction = ACTION_GATT_DISCONNECTED;  
                mConnectionState = STATE_DISCONNECTED;  
                Log.i(TAG, "Disconnected from GATT server.");  
                broadcastUpdate(intentAction);  
            }  
        }  
    
        @Override  
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {  
            if (status == BluetoothGatt.GATT_SUCCESS) {  
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);  
            } else {  
                Log.w(TAG, "onServicesDiscovered received: " + status);  
            }  
        }  
        //从特征中读取数据  
        @Override  
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {  
            //System.out.println("onCharacteristicRead");  
            if (status == BluetoothGatt.GATT_SUCCESS) {  
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);  
            }  
        }  
        //向特征中写入数据  
        @Override  
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {  
            //System.out.println("--------write success----- status:" + status);  
        }  
    
        /* 
         * when connected successfully will callback this method this method can 
         * dealwith send password or data analyze 
    
         *当连接成功将回调该方法 
         */  
        @Override  
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {  
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);  
            if (characteristic.getValue() != null) {  
    
                //System.out.println(characteristic.getStringValue(0));  
            }  
            //System.out.println("--------onCharacteristicChanged-----");  
        }  
    
        @Override  
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {  
    
            //System.out.println("onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + descriptor.getUuid().toString());  
    
            UUID uuid = descriptor.getCharacteristic().getUuid();  
            if (uuid.equals(UUID.fromString("0000cd01-0000-1000-8000-00805f9b34fb"))) {  
                broadcastUpdate(ACTION_CD01NOTIDIED);  
            } else if (uuid.equals(UUID.fromString("0000cd02-0000-1000-8000-00805f9b34fb"))) {  
                broadcastUpdate(ACTION_CD02NOTIDIED);  
            } else if (uuid.equals(UUID.fromString("0000cd03-0000-1000-8000-00805f9b34fb"))) {  
                broadcastUpdate(ACTION_CD03NOTIDIED);  
            } else if (uuid.equals(UUID.fromString("0000cd04-0000-1000-8000-00805f9b34fb"))) {  
                broadcastUpdate(ACTION_CD04NOTIDIED);  
            }  
        }  
    
        @Override  
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {  
            //System.out.println("rssi = " + rssi);  
        }  
    };  
    
    ----------------------------------------------  
      //从特征中读取数据  
        @Override  
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {  
            //System.out.println("onCharacteristicRead");  
            if (status == BluetoothGatt.GATT_SUCCESS) {  
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);  
            }  
        }  
    

    2.10、断开连接

    /** * Disconnects an existing connection or cancel a pending connection. The * disconnection result is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */
    public void disconnect() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    Log.w(TAG, "BluetoothAdapter not initialized");
    return;
    }
    mBluetoothGatt.disconnect();
    }

    2.11、数据的转换方法

    // byte转十六进制字符串
    public static String bytes2HexString(byte[] bytes) {
    String ret = "";
    for (byte aByte : bytes) {
    String hex = Integer.toHexString(aByte & 0xFF);
    if (hex.length() == 1) {
    hex = '0' + hex;
    }
    ret += hex.toUpperCase(Locale.CHINA);
    }
    return ret;
    }

    /** * 将16进制的字符串转换为字节数组 *
    * @param message * @return 字节数组 */
    public static byte[] getHexBytes(String message) {
    int len = message.length() / 2;
    char[] chars = message.toCharArray();
    String[] hexStr = new String[len];
    byte[] bytes = new byte[len];
    for (int i = 0, j = 0; j < len; i += 2, j++) {
    hexStr[j] = "" + chars[i] + chars[i + 1];
    bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
    }
    return bytes;
    }

    总结

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

    就那一个我们项目中的demo说一下。 一个蓝牙ble的血压计。 上位机---手机 下位机 -- 血压计 1.血压计与手机连接蓝牙之后。 2.上位机主动向下位机发送一个身份验证指令,下位机收到指令后开始给上位做应答, 3.应答成功,下位机会将测量的血压数据传送到上位机。 4.最后断开连接。

    展开全文
  • Android BLE开发之Android手机与BLE终端通信

    万次阅读 多人点赞 2014-04-21 20:22:28
    最近穿戴设备发展得很火,把相关技术也带旺了,其中一项是...Android 4.3才开始支持BLE API,所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统,另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。
  • Android BLE开发之Android手机搜索iBeacon基站

    千次下载 热门讨论 2014-04-29 10:37:29
    上次讲了Android手机与BLE终端之间的通信(http://blog.csdn.net/hellogv/article/details/24267685),而最常见的BLE终端应该是苹果公司倡导的iBeacon基站了。iBeacon技术基于BLE,目前主要用来做室内定位和营销...
  • Android BLE Demo

    千次下载 热门讨论 2014-03-20 16:52:41
    BLE协议中,有两个角色,周边(Periphery)和中央(Central);周边是数据提供者,中央是数据使用/处理者。该资源包含两个工程,一个实现了周边,一个实现了中央。详细说明在这儿:...
  • Android BLE 通信

    2016-03-15 17:11:20
    Android ble通信,本地能成功跑起来。只要将里面的service uuid与Characteristic uuid换成自己要通信的ble板中的uuid即可。获取你的uuid代码中有写,看Log信息即可
  • Android Ble 开发

    2018-08-13 11:10:15
    Android Ble 开发, 功能包括扫描、连接、发送等,分为中央设备和外设蓝牙,有客户端和服务端2个apk源码
  • Android BLE蓝牙例子(包括android版Lightblue)实例源码

    千次下载 热门讨论 2016-01-14 10:20:50
    Android_Lightblue.apk是Android版的lightblue,在进行ble开发的时候用该app作为辅助工具还是非常不错的,功能较Bluetooth4_3 BLEDemo 这两个demo都强大。不过Android_Lightblue.apk在android5.0以上的版本手机上...
  • Android BLE OAD

    2018-07-31 11:08:47
    Android BLE OAD升级的官方源码包,最新android studio编译项目,已经测试验证通过。
  • Android BLE 开发

    2014-10-27 19:23:21
    Android ble开发指南,参考官方例程,实测好用,希望能够帮助需要者。
  • 通过Android BLE 实现服务端、客户端通讯。一个简单的聊天案例
  • Android BLE 源码

    2018-07-12 17:05:01
    网上找到的蓝牙安卓BLE的APP源码,解决了安卓手机BLE连接难或连接不上的问题,比安卓BLE调试助手好。
  • android ble4.0

    2017-01-05 14:13:50
    android ble4.0
  • Android BLE蓝牙4.0开发详解

    万次阅读 多人点赞 2016-01-12 15:16:58
    这篇博客主要讲解蓝牙 BLE的用法。在讲解之前先讲一些概念性的东西,对于之前没接触过蓝牙开发,现在手上又有个蓝牙BLE项目需要做的人,先看下这些概念还是很重要的。因为我之前就是这样,之前没有接触过蓝牙方面的...
  • Android BLE开发概要

    热门讨论 2014-09-05 12:47:52
    该文档主要涉及到android平台上的ble开发,为本人开发过程的总结,本着分享的原则,奉献给大家。其中第一章节涉及到ble协议栈的介绍、gap和gatt这两个和上层应用开发密切相关的协议介绍;第二章节涉及到整个ble连接...
  • BLE简介和Android BLE编程

    万次阅读 2014-11-22 16:17:24
    一.BLE和BT区别其实我知道许多程序员不太喜欢阅读除了代码以外的文档,因为有时这些过于冗长的文档对编程并没有更多的好处,有了协议,接口,demo差不多很多人就能写出很好质量的代码了。但其实更深入的编程是少了...
  • AndroidBLE.rar

    2019-11-27 16:50:25
    Android 蓝牙BLE开发,主要涉及扫描设备、连接/断开、数据通讯。本案例是通过实际蓝牙设备测试没有问题的,所以使用本代码案例前,请确保你自己的蓝牙设备是可用的。
  • android Ble peripheral demo

    热门讨论 2014-07-11 11:27:35
    谷歌刚刚前不久发布的androidL,在蓝牙低功耗这块改动,目前支持peripheral 模式,让手机广播,由于目前还未正式发布api,现居于预览版信息,写了个demo,有需要的可以看看(运行环境 android L)
  • android ble 项目源码

    2016-02-21 21:35:08
    这是一份android防丢器开发案例,现在分享出来,涉及到的知识有多连接,读写等等所有关于BLE相关的知识,如有需要可以下载
  • Android BLE 官方DEMO

    2015-09-23 14:40:42
    本人是在AndroidStuido上导入的,此代码提供源码及本人运行后的代码。注意源码导入容易出现错误不过很容易处理。代码支持android系统4.3以上,手机支持蓝牙4.0,搜索,配对,连接,发现服务及特征值,断开连接等功能...
  • Android BLE update

    2020-11-29 14:18:05
    use the discovery agent to find BLE devices that can't be bonded/paried <h3>Related issues: <p>Fixes #2974 <h3>Mentions: 该提问来源于开源项目:subsurface/subsurface</p></div>
  • Android BLE 开发源码

    2014-04-10 20:33:16
    基于Android4.3 API 低功耗 Bluetooth4.0 蓝牙开发示例源码。
  • Android BLE新手进入

    2018-12-20 23:46:57
    我们提到了中央设备(central)和外围设备(peripheral),在这里我们可以这样简单的理解: 中央设备(central): 收到外围设备发出的广播信号后能主动发起连接的主设备, 例如我们给摩拜单车开锁时我们的手机就是作为中央...

空空如也

1 2 3 4 5 ... 20
收藏数 3,667
精华内容 1,466
关键字:

android ble