精华内容
下载资源
问答
  • (关于蓝牙的搜索,连接,获取服务,获取特征值等方法这里就不再赘述了,网上很多前辈总结的很全面,可以自行搜索。 这几个操作的共同特性都是通过调用回调方法进行数据的获取和交换,所以进行相关操作之前熟悉每个...

    这段时间一直在进行手机与BLE的相关项目开发,其中对读数据、写数据、接收通知消息、接收指示型消息这几种操作有了一些了解,今天贴出来跟大家分享一下。(关于蓝牙的搜索,连接,获取服务,获取特征值等方法这里就不再赘述了,网上很多前辈总结的很全面,可以自行搜索。

    这几个操作的共同特性都是通过调用回调方法进行数据的获取和交换,所以进行相关操作之前熟悉每个操作相关的回调方法是很有必要的。

    1.接收通知消息(setCharacteristicNotification):

    前期进行BLE开发或许很容易混淆读操作和接收通知消息,这里我按自己的理解粗糙的讲解一下。通知是BLE终端主动或是相关操作触发而发出的数据,任何一个用于权限的主机都可以读取到这个数据。
    而读操作时谁进行读数据操作,然后BLE终端才会被动的发出一个数据,而这个数据只能是读操作的对象才有资格获得到这个数据。

                //首先必须获取通知通道(这里的UUID根据自己BLE终端,自己进行读取操作获得)
                service = mBluetoothGatt.getService(uuid_s);
                characteristic = service.getCharacteristic(uuid_c);
                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(uuid_d);
                if (descriptor != null) {
                            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                            mBluetoothGatt.writeDescriptor(descriptor);
                 }
                 mBluetoothGatt.setCharacteristicNotification(characteristic, true);
    
    
                 //然后重写回调方法,跟根据通知数据的类型进行解析操作,判断是否接收到通知利用Log日志可以观察到。
                 @Override
            public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
                Log.i(TAG, "onCharacteristicChanged!");
                //进行接收数据的相关操作
                String data = characteristic.getValue();
                }
                super.onCharacteristicChanged(gatt, characteristic);
            }

    2.读数据(readCharacteristic):

    读数据,顾名思义是对BLE进行读取数据的操作,这个数据

                    //首先获取读数据相关的通道
                    service = mBluetoothGatt.getService(uuid_s);
                    characteristic = service.getCharacteristic(uuid_c);
                    mBluetoothGatt.readCharacteristic(characteristic);

    3.写数据(readCharacteristic):

                    if (mBluetoothGatt != null){
                        if (characteristic != null){
                            characteristic.setValue(data);
                            mBluetoothGatt.writeCharacteristic(characteristic);
                            Log.i(TAG, "writeData:写了一次数据!");
                        }
                    }

    4.指示(readCharacteristic):

                        //获取指示通道
                        characteristic = service.getCharacteristic(uuid2_c_n);
                        if (characteristic != null){
                            BluetoothGattDescriptor descriptor = characteristic_notify.getDescriptor(uuid_d);
                            if (descriptor != null) {
                                descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                                Log.i(TAG, "Descriptor write: " + mBluetoothGatt.writeDescriptor(descriptor));
                                mBluetoothGatt.setCharacteristicNotification(characteristic , true);
                            }
                        }

    以上几种操作都需要对应的uuid,uuid的值一般对应的蓝牙工程会在接口文档中给出,我们按照文档进行相关的操作。——一篇在草稿中躺了两年的博客,还是发出来日后温习一遍把。

    展开全文
  • 掌握Android低功耗蓝牙的通讯过程以及了解温度传感器读写数据 Android低功耗蓝牙 蓝牙4.0 • 蓝牙4.0 = BLE • 特性 • 超低的峰值、平均和待机功耗• 低成本 • 不同厂商设备交互性• 无线覆盖范围增强 ...

    掌握Android低功耗蓝牙的通讯过程以及了解温度传感器读写数据

    Android低功耗蓝牙

    蓝牙4.0

    • 蓝牙4.0 = BLE
    • 特性
    • 超低的峰值、平均和待机功耗• 低成本

    • 不同厂商设备交互性• 无线覆盖范围增强
    • 完全向下兼容
    • 低延时

    Android 蓝牙4.0

    • BLE是蓝牙4.0的核心Profile,主打功能是快速搜索,快速连接, 超低功耗保持连接和传输数据

    • 弱点是数据传输速率低,由于BLE的低功耗特点,因此普遍用于 穿戴设备。

    应用场景 – iBeacon技术

    • 在2013年9月苹果公司发布了iBeacon技术

    • ShellBeacon, BrightBeacon在基于iBeacon技术,和运用蓝 牙4.0标准为通信方式的前提下,提供了一整套基于ibeacon的 技术解决方案和供便于开发的SDK。

    蓝牙防丢器

    • 蓝牙4.0防丢器即智能蓝牙(Smart Bluetooth)防丢器
    • 采用最新蓝牙4.0技术,专门为iphone/ipad设计的防丢器• 简单轻巧的设计,方便携带
    • 工作原理主要是通过距离变化来判断物品是否 还控制在你的安全范围。

    SensorTag

    • IR Temperature, both object and ambient temperature

    • Movement, 9 axis (accelerometer, gyroscope,magnetometer)

    • Humidity, both relative humidity and temperature

    • Barometer, both pressure and temperature

    • Optical, light intensity

    使用蓝牙设备

    • 申请使用蓝牙设备权限
    • 查看手机是否支持蓝牙设备和蓝牙4.0功能• 打开蓝牙功能
    • 扫描附近的设备

    使用蓝牙设备权限

    android.permission.ACCESS_COARSE_LOCATION    在Android 6.0上需要动态申请权限

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

    蓝牙4.0 Feature

    清单文件里添加BLE的feature

    <uses-featureandroid:name="android.hardware.bluetooth.le"android:required="true"/>
    

    蓝牙4.0 Feature

    查看设备是否支持BLE功能

    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(MainActivity.this, "Not support BLE", Toast.LENGTH_SHORT).show(); finish();
    
    }

    1-打开蓝牙

    检测如果蓝牙没有打开的话,需要申请打开蓝牙开关
    
    if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(enableBtIntent);
    
    }

    2-扫描附近蓝牙4.0设备

    通过ScanCallback 来获取附近蓝牙设备

    public void scan(boolean enable) {
    final ScanCallback mScanCallback = new ScanCallback() {
    
    @Override
    
    public void onScanResult(int callbackType, ScanResult result) { }
    
    };
    
    if(enable) {mLeScanner.startScan(mScanCallback);
    
    } else {mLeScanner.stopScan(mScanCallback);
    
    }
    
    }

    GattCallback

    • BluetoothGattCallback 是BLE设备连接以及通信过冲中状态 变化的主要返回调函数。

    连接/断开 BLE设备

    连接:

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);if (device == null) {
    
    Log.w(TAG, "Device not found, cannot to connect");
    
        return false;
    }
    mBluetoothGatt = device.connectGatt(this, false, mGattCallback); Log.d(TAG, "Trying to create a new connection");

    连接/断开 BLE设备

    断开:

    if (mBluetoothGatt != null) mBluetoothGatt.disconnect();

    BLE连接状态变化

    @Override
    
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);
    Log.d(TAG, "+onConnectionStateChange+ status = " + status +
    
    ", newState = " + newState);mMainHandler.sendEmptyMessage(newState);
    
    }

    注意:

    在onConnectionStateChange返回调函数里面不能直接操作刷新UI控件, 需要使用Handler来通知主线程来刷新UI界面。

    发现蓝牙设备的Service和特征值

    每一个Service和Characteristic对应一个UUID,通过这个UUID来设备不同设备中不同数据的协议。

    比如在SensorTag里面的温度传感器的Service UUID为:

    f000aa00-0451-4000-b000-000000000000

    温度传感器数据特征值的UUID为:

    f000aa01-0451-4000-b000-000000000000

    Android对BLE设备的数据操作

    • readValue

    • writeValue

    • notify

    读/写数据

    • 通过Service里面的特征值来读/写数据

    • byte[] data = characteristic.getValue();

    • gattCharacteristic.setValue(new byte[] {0x01});

    mBluetoothGatt.writeCharacteristic(gattCharacteristic);

    具体看demo

    展开全文
  • android BLE蓝牙

    2016-08-14 23:12:20
    这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范

    安卓4.3(API 18)为BLE的核心功能提供平台支持和API,App可以利用它来发现设备、查询服务和读写特性。相比传统的蓝牙,BLE更显著的特点是低功耗。这一优点使android App可以与具有低功耗要求的BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。

    关键术语和概念


    • Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范,用于在BLE链路上发送和接收被称为“属性”的数据块。目前所有的BLE应用都基于GATT。 蓝牙SIG规定了许多低功耗设备的配置文件。配置文件是设备如何在特定的应用程序中工作的规格说明。注意一个设备可以实现多个配置文件。例如,一个设备可能包括心率监测仪和电量检测。
    • Attribute Protocol(ATT)—GATT在ATT协议基础上建立,也被称为GATT/ATT。ATT对在BLE设备上运行进行了优化,为此,它使用了尽可能少的字节。每个属性通过一个唯一的的统一标识符(UUID)来标识,每个String类型UUID使用128 bit标准格式。属性通过ATT被格式化为characteristics和services。
    • Characteristic 一个characteristic包括一个单一变量和0-n个用来描述characteristic变量的descriptor,characteristic可以被认为是一个类型,类似于类。
    • Descriptor Descriptor用来描述characteristic变量的属性。例如,一个descriptor可以规定一个可读的描述,或者一个characteristic变量可接受的范围,或者一个characteristic变量特定的测量单位。
    • Service service是characteristic的集合。例如,你可能有一个叫“Heart Rate Monitor(心率监测仪)”的service,它包括了很多characteristics,如“heart rate measurement(心率测量)”等。你可以在bluetooth.org 找到一个目前支持的基于GATT的配置文件和服务列表。

    角色和责任

    以下是Android设备与BLE设备交互时的角色和责任:

    • 中央 VS 外围设备。 适用于BLE连接本身。中央设备扫描,寻找广播;外围设备发出广播。
    • GATT 服务端 VS GATT 客户端。决定了两个设备在建立连接后如何互相交流。

    为了方便理解,想象你有一个Android手机和一个用于活动跟踪BLE设备,手机支持中央角色,活动跟踪器支持外围(为了建立BLE连接你需要注意两件事,只支持外围设备的两方或者只支持中央设备的两方不能互相通信)。

    当手机和运动追踪器建立连接后,他们开始向另一方传输GATT数据。哪一方作为服务器取决于他们传输数据的种类。例如,如果运动追踪器想向手机报告传感器数据,运动追踪器是服务端。如果运动追踪器更新来自手机的数据,手机会作为服务端。

    在这份文档的例子中,android app(运行在android设备上)作为GATT客户端。app从gatt服务端获得数据,gatt服务端即支持Heart Rate Profile(心率配置)的BLE心率监测仪。但是你可以自己设计android app去扮演GATT服务端角色。更多信息见BluetoothGattServer

    BLE权限


    为了在app中使用蓝牙功能,必须声明蓝牙权限BLUETOOTH。利用这个权限去执行蓝牙通信,例如请求连接、接受连接、和传输数据。

    如果想让你的app启动设备发现或操纵蓝牙设置,必须声明BLUETOOTH_ADMIN权限。注意:如果你使用BLUETOOTH_ADMIN权限,你也必须声明BLUETOOTH权限。

    在你的app manifest文件中声明蓝牙权限。

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

    如果想声明你的app只为具有BLE的设备提供,在manifest文件中包括:

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

    但是如果想让你的app提供给那些不支持BLE的设备,需要在manifest中包括上面代码并设置required="false",然后在运行时可以通过使用PackageManager.hasSystemFeature()确定BLE的可用性。

    1
    2
    3
    4
    5
    // 使用此检查确定BLE是否支持在设备上,然后你可以有选择性禁用BLE相关的功能
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
    finish();
    }

    设置BLE


    你的app能与BLE通信之前,你需要确认设备是否支持BLE,如果支持,确认已经启用。注意如果<uses-feature.../>设置为false,这个检查才是必需的。

    如果不支持BLE,那么你应该适当地禁用部分BLE功能。如果支持BLE但被禁用,你可以无需离开应用程序而要求用户启动蓝牙。使用BluetoothAdapter两步完成该设置。

    1. 获取 BluetoothAdapter

      所有的蓝牙活动都需要蓝牙适配器。BluetoothAdapter代表设备本身的蓝牙适配器(蓝牙无线)。整个系统只有一个蓝牙适配器,而且你的app使用它与系统交互。下面的代码片段显示了如何得到适配器。注意该方法使用getSystemService()]返回BluetoothManager,然后将其用于获取适配器的一个实例。Android 4.3(API 18)引入BluetoothManager。

    1
    2
    3
    4
    // 初始化蓝牙适配器
    final BluetoothManager bluetoothManager =
    (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
    1. 开启蓝牙

      接下来,你需要确认蓝牙是否开启。调用isEnabled())去检测蓝牙当前是否开启。如果该方法返回false,蓝牙被禁用。下面的代码检查蓝牙是否开启,如果没有开启,将显示错误提示用户去设置开启蓝牙。

    1
    2
    3
    4
    5
    // 确保蓝牙在设备上可以开启
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }

    发现BLE设备


    为了发现BLE设备,使用startLeScan())方法。这个方法需要一个参数BluetoothAdapter.LeScanCallback。你必须实现它的回调函数,那就是返回的扫描结果。因为扫描非常消耗电量,你应当遵守以下准则:

    • 只要找到所需的设备,停止扫描。
    • 不要在循环里扫描,并且对扫描设置时间限制。以前可用的设备可能已经移出范围,继续扫描消耗电池电量。

    下面代码显示了如何开始和停止一个扫描:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    /**
    * 扫描和显示可以提供的蓝牙设备.
    */
    public class DeviceScanActivity extends ListActivity {
    private BluetoothAdapter mBluetoothAdapter;
    private boolean mScanning;
    private Handler mHandler;
    // 10秒后停止寻找.
    private static final long SCAN_PERIOD = 10000;
    ...
    private void scanLeDevice(final boolean enable) {
    if (enable) {
    // 经过预定扫描期后停止扫描
    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);
    }
    ...
    }
    ...
    }

    如果你只想扫描指定类型的外围设备,可以改为调用startLeScan(UUID[], BluetoothAdapter.LeScanCallback)),需要提供你的app支持的GATT services的UUID对象数组。

    作为BLE扫描结果的接口,下面是BluetoothAdapter.LeScanCallback的实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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设备或者扫描传统蓝牙设备,不能同时扫描BLE和传统蓝牙设备。

    连接到GATT服务端


    与一个BLE设备交互的第一步就是连接它——更具体的,连接到BLE设备上的GATT服务端。为了连接到BLE设备上的GATT服务端,需要使用connectGatt( )方法。这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接到它),和BluetoothGattCallback调用。

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

    连接到GATT服务端时,由BLE设备做主机,并返回一个BluetoothGatt实例,然后你可以使用这个实例来进行GATT客户端操作。请求方(Android app)是GATT客户端。BluetoothGattCallback用于传递结果给用户,例如连接状态,以及任何进一步GATT客户端操作。

    在这个例子中,这个BLE APP提供了一个activity(DeviceControlActivity)来连接,显示数据,显示该设备支持的GATT services和characteristics。根据用户的输入,这个activity与BluetoothLeService通信,通过Android BLE API实现与BLE设备交互。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    //通过BLE API服务端与BLE设备交互
    public class BluetoothLeService extends Service {
    private final static String TAG = BluetoothLeService.class.getSimpleName();
    private BluetoothManager mBluetoothManager; //蓝牙管理器
    private BluetoothAdapter mBluetoothAdapter; //蓝牙适配器
    private String mBluetoothDeviceAddress; //蓝牙设备地址
    private BluetoothGatt mBluetoothGatt;
    private int mConnectionState = STATE_DISCONNECTED;
    private static final int STATE_DISCONNECTED = 0; //设备无法连接
    private static final int STATE_CONNECTING = 1; //设备正在连接状态
    private static final int STATE_CONNECTED = 2; //设备连接完毕
    public final static String ACTION_GATT_CONNECTED =
    "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED =
    "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED =
    "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE =
    "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
    public final static String EXTRA_DATA =
    "com.example.bluetooth.le.EXTRA_DATA";
    public final static UUID UUID_HEART_RATE_MEASUREMENT =
    UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
    //通过BLE API的不同类型的回调方法
    private final BluetoothGattCallback mGattCallback =
    new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status,
    int newState) {//当连接状态发生改变
    String intentAction;
    if (newState == BluetoothProfile.STATE_CONNECTED) {//当蓝牙设备已经连接
    intentAction = ACTION_GATT_CONNECTED;
    mConnectionState = STATE_CONNECTED;
    broadcastUpdate(intentAction);
    Log.i(TAG, "Connected to GATT server.");
    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) {
    if (status == BluetoothGatt.GATT_SUCCESS) {
    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }
    }
    ...
    };
    ...
    }

    当一个特定的回调被触发的时候,它会调用相应的broadcastUpdate()辅助方法并且传递给它一个action。注意在该部分中的数据解析按照蓝牙心率测量配置文件规格进行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
    }
    private void broadcastUpdate(final String action,
    final BluetoothGattCharacteristic characteristic) {
    final Intent intent = new Intent(action);
    // 这是心率测量配置文件。
    if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
    int flag = characteristic.getProperties();
    int format = -1;
    if ((flag & 0x01) != 0) {
    format = BluetoothGattCharacteristic.FORMAT_UINT16;
    Log.d(TAG, "Heart rate format UINT16.");
    } else {
    format = BluetoothGattCharacteristic.FORMAT_UINT8;
    Log.d(TAG, "Heart rate format UINT8.");
    }
    final int heartRate = characteristic.getIntValue(format, 1);
    Log.d(TAG, String.format("Received heart rate: %d", heartRate));
    intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
    } else {
    // 对于所有其他的配置文件,用十六进制格式写数据
    final byte[] data = characteristic.getValue();
    if (data != null && data.length > 0) {
    final StringBuilder stringBuilder = new StringBuilder(data.length);
    for(byte byteChar : data)
    stringBuilder.append(String.format("%02X ", byteChar));
    intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
    stringBuilder.toString());
    }
    }
    sendBroadcast(intent);
    }

    返回DeviceControlActivity, 这些事件由一个BroadcastReceiver来处理:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 通过服务控制不同的事件
    // ACTION_GATT_CONNECTED: 连接到GATT服务端
    // ACTION_GATT_DISCONNECTED: 未连接GATT服务端.
    // ACTION_GATT_SERVICES_DISCOVERED: 未发现GATT服务.
    // ACTION_DATA_AVAILABLE: 接受来自设备的数据,可以通过读或通知操作获得。
    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
    final String action = intent.getAction();
    if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
    mConnected = true;
    updateConnectionState(R.string.connected);
    invalidateOptionsMenu();
    } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
    mConnected = false;
    updateConnectionState(R.string.disconnected);
    invalidateOptionsMenu();
    clearUI();
    } else if (BluetoothLeService.
    ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
    // 在用户接口上展示所有的services and characteristics
    displayGattServices(mBluetoothLeService.getSupportedGattServices());
    } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
    displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
    }
    }
    };

    读取BLE变量


    你的android app完成与GATT服务端连接和发现services后,就可以读写支持的属性。例如,这段代码通过服务端的services和 characteristics迭代,并且将它们显示在UI上。

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

    接收GATT通知


    当设备上的特性改变时会通知BLE应用程序。这段代码显示了如何使用setCharacteristicNotification( )给一个特性设置通知。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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( ))被触发。

    1
    2
    3
    4
    5
    6
    @Override
    // 广播更新
    public void onCharacteristicChanged(BluetoothGatt gatt,
    BluetoothGattCharacteristic characteristic) {
    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }

    关闭客户端App


    当你的app完成BLE设备的使用后,应该调用close( )),系统可以合理释放占用资源。

    1
    2
    3
    4
    5
    6
    7
    public void close() {
    if (mBluetoothGatt == null) {
    return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt = null;
    }
    展开全文
  • Android ble蓝牙开发介绍以及遇到

    千次阅读 2017-08-19 17:18:22
    Android ble蓝牙开发 ...这一优点使AndroidApp可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 BLE开发 BLE权限添加 为了在app中使用蓝牙功能,必须声明蓝牙权限B

    Android ble蓝牙开发

    BLE介绍

    安卓4.3(API 18)BLE的核心功能提供平台支持和APIApp可以利用它来发现设备、查询服务和读写特性。相比传统的蓝牙,BLE更显著的特点是低功耗。这一优点使AndroidApp可以与具有低功耗要求的BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。

    BLE开发

    BLE权限添加

    为了在app中使用蓝牙功能,必须声明蓝牙权限BLUETOOTH。利用这个权限去执行蓝牙通信,例如请求连接、接受连接、和传输数据。如果想让你的app启动设备发现或操纵蓝牙设置,必须声明BLUETOOTH_ADMIN权限。注意:如果你使用BLUETOOTH_ADMIN权限,你也必须声明BLUETOOTH权限。在你的app manifest文件中声明蓝牙权限。

    设置BLE

    你的app能与BLE通信之前,你需要确认设备是否支持BLE,如果支持,确认已经启用。虽然现在的手机基本都支持BLE,但是考虑到程序的健硕性,如果设置为false,这个检查是必需的。

    BluetoothAdapter类介绍

    获取:所有的蓝牙活动都需要蓝牙适配器。BluetoothAdapter代表设备本身的蓝牙适配器(蓝牙无线)。整个系统只有一个蓝牙适配器,而且你的app使用它与系统交互。下面的代码片段显示了如何得到适配器。注意该方法使用getSystemService()]返回BluetoothManager,然后将其用于获取适配器的一个实例。Android 4.3API 18)引入BluetoothManager

    // 初始化蓝牙适配器

    final BluetoothManager bluetoothManager =

    (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

    mBluetoothAdapter = bluetoothManager.getAdapter();

    有了mBluetoothAdapter之后就可以判断当前蓝牙开关状态、蓝牙未开启情况下代码里面自动开启蓝牙、以及扫描周边的ble设备

    开启蓝牙

    接下来,你需要确认蓝牙是否开启。调用isEnabled())去检测蓝牙当前是否开启。如果该方法返回false,蓝牙被禁用。下面的代码检查蓝牙是否开启,如果没有开启,可以提示用户去设置开启蓝牙。

    // 确保蓝牙在设备上可以开启

    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {

    //蓝牙未开启

    }

    发现BLE设备

    为了发现BLE设备,使用startLeScan())方法。这个方法需要一个参数BluetoothAdapter.LeScanCallback。你必须实现它的回调函数,那就是返回的扫描结果。因为扫描非常消耗电量,你应当遵守以下准则:

    只要找到所需的设备,停止扫描。

    不要在循环里扫描,并且对扫描设置时间限制。以前可用的设备可能已经移出范围,继续扫描消耗电池电量。

    以下代码显示如何扫描设备和停止扫描设备

    // 10秒后停止寻找.

    private static final long SCAN_PERIOD = 10000;

    private void scanLeDevice(final boolean enable) {

    if (enable) {

    // 经过预定扫描期后停止扫描

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

    }

    ...

    }

    ...

    }

    如果你只想扫描指定类型的外围设备,可以改为调用startLeScan(UUID[], BluetoothAdapter.LeScanCallback)),需要提供你的app支持的GATT servicesUUID对象数组。

    扫描的信息在LeScallCallback里面返回

    private BluetoothAdapter.LeScanCallback mLeScanCallback =

    new BluetoothAdapter.LeScanCallback() {

    //device 里面包含设备的mac地址和设备的名称

    //scanRecord里面就是ble设备发出的广播包数据

    //rssi表示ble设备的信号值,该值为负数,值越大表示信号值越好

    @Override

    public void onLeScan(final BluetoothDevice device, int rssi,

    byte[] scanRecord) {

    runOnUiThread(new Runnable() {

    @Override

    public void run() {

    mLeDeviceListAdapter.addDevice(device);

    mLeDeviceListAdapter.notifyDataSetChanged();

    }

    });

    }

    };

    连接到GATT服务端

    与一个BLE设备交互的第一步就是连接它——更具体的,连接到BLE设备上的GATT服务端。为了连接到BLE设备上的GATT服务端,需要使用connectGatt( )方法。这个方法需要三个参数:一个Context对象,自动连接(boolean,表示只要BLE设备可用是否自动连接到它),和BluetoothGattCallback调用。

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

    连接到GATT服务端时,由BLE设备做主机,并返回一个BluetoothGatt实例,然后你可以使用这个实例来进行GATT客户端操作。请求方(Android app)GATT客户端。BluetoothGattCallback用于传递结果给用户,例如连接状态,以及任何进一步GATT客户端操作。

    private final BluetoothGattCallback mGattCallback =

    new BluetoothGattCallback() {

    @Override

    public void onConnectionStateChange(BluetoothGatt gatt, int status,

    int newState) {//当连接状态发生改变

    String intentAction;

    if (newState == BluetoothProfile.STATE_CONNECTED) {//当蓝牙设备已经连接

    //获取ble设备上面的服务

    Log.i(TAG, "Attempting to start service discovery:" +

    mBluetoothGatt.discoverServices());

    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//当设备无法连接

    }

    }

    @Override

    //调用discoverServices后的回调

    public void onServicesDiscovered(BluetoothGatt gatt, int status) {

    if (status == BluetoothGatt.GATT_SUCCESS) {

    //获取服务成功

    } else {

    Log.w(TAG, "onServicesDiscovered received: " + status);

    }

    }

    @Override

    // 读写特性

    public void onCharacteristicRead(BluetoothGatt gatt,

    BluetoothGattCharacteristic characteristic,

    int status) {

    if (status == BluetoothGatt.GATT_SUCCESS) {

    }

    }

    ...

    };

    ...

    }

    发送数据

    首先通过UUID拿到对应的服务,再通过UUID拿到服务的特征,设置特征的属性是BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE。设置成功后可以在该特征值上发送数据到ble设备和接收ble设备的数据。看到这里也许各位不熟ble开发和刚ble开发的看官也许就一脸懵逼,我只是想发送数据到ble设备,怎么一下子搞出个UUID 服务和特征值了,难道就不能和B/S开发一样,连接之后我把数据发送到一个接口,服务器端就返回我需要的数据那么简单。这还得从ble蓝牙的架构说起。

    BLE分为三部分ServiceCharacteristicDescriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Valueservicecharacteristic的集合.一个characteristic包括一个单一变量和0-n个用来描述characteristic变量的descriptor.Descriptor用来描述characteristic变量的属性。例如,一个descriptor可以规定一个可读的描述,或者一个characteristic变量可接受的范围,或者一个characteristic变量特定的测量单位。一般来说,Characteristic是手机与BLE终端交换数据的关键.

    举个栗子:当我们想要用手机与BLE设备进行通信时,实际上也就相当于我们要去找一个学生交流,首先我们需要搭建一个管道,也就是我们需要先获取得到一个BluetoothGatt,其次我们需要知道这个学生在哪一个班级,学号是什么,这也就是我们所说的serviceUUID,和charUUID。这里我们还需要注意一下,找到这个学生后并不是直接和他交流,他就好像一个中介一样,在手机和BLE终端设备之间帮助这两者传递着信息,我们手机所发数据要先经过他,在由他传递到BLE设备上,而BLE设备上的返回信息,也是先传递到他那边,然后手机再从他那边进行读取。

    在发送数据之前需先设置特征的具有notificaion功能

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

    设置完成后回调

    @Override

    public final void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) {

    //设置成功

    if (status == BluetoothGatt.GATT_SUCCESS) {

    }

    }

    设置成功后就开始发送数据了。

    //将指令放置进特征中

    characteristic.setValue(data);

    //设置回复形式characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);

    //开始写数据

    mBluetoothGatt.writeCharacteristic(chharacteristic);

    写入数据成功后回调

    protected void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {

    //发送数据成功啦啦啦

    }

    如何设备回复数据则会回调

    @Override

    public final void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {

    }

    关闭客户端App

    当你的app完成BLE设备的使用后,应该调用close( )),系统可以合理释放占用资源。

    public void close() {

    if (mBluetoothGatt == null) {

    return;

    }

    mBluetoothGatt.close();

    mBluetoothGatt = null;

    }

    最后分享我在BLE 开发中遇到的坑和一些经验

    1 在所有蓝牙的回调中不要操作UI。我是不会告诉你我是怎么发现这个坑的。

    2 在所有的蓝牙回调中不要执行耗时操作。

    3 发送数据要等到上一条数据发送成功后再发下一条数据,毕竟BLE设备运算没有手机快,这里可以推荐一个开源蓝牙连接工具https://github.com/NordicSemiconductor/Android-nRF-Toolbox,里面非常好的对发送的数据做了一个数据队列。

    4 合理的控制扫描过程,一般出现133错误的时候重连就可以先去扫描再去连接。若扫描不到时不要马上又去扫描,不然你把手机放那一夜,把设备远离它,第二天回来看手机时会惊喜的发现手机没电自动关机了

    遇到的坑

    1 断线重连的时候总是报133错误,

    断线后不要马上去连接.先扫描设备,扫描到设备后再去连接。

    2 扫描不到设备

    手动关闭蓝牙再打开蓝牙开关。这个可能是重连里面的扫描引起的,如果设备未在周边,一直去扫描的话,后来设备在身边也可能扫描不到设备。如果未能连接设备,也不能一直去扫描。扫描不到设备时说明设备并不到周边,可以延迟多少时间后再去扫描

    3 连接设备后发送数据,发送数据的回调函数也已经走了。没有接收到数据

    查看设置特征值的描述值

    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)

    mBluetoothGatt.writeDescriptor(descriptor)的回调里面是不是回调成功了

    4反复断开蓝牙后再重连导致连接失败

    断开蓝牙后应该调用close()方法释放资源.连接时应该设置超时,在超时时间内继续去连接,基本低、中、高端机都能重新连接上。

    5 连接上之后自动断开连接,重连上之后又自动断开连接,如此反复。

    我们的BLE设备在某些低端机会遇到这种问题。听固件工程师说是BLE设备蓝牙芯片频率和手机蓝牙频率问题,需调BLE设备频率。遇到这种问题APP就束手无策了。

    6 反复操作断开和连接导致系统蓝牙挂掉(无响应)

    基本也是没有合理释放资源导致

    7 调用扫描操作导致APP无响应

    查看系统蓝牙是否挂掉了。基本和问题6类似

    参考文章:

    http://www.cnblogs.com/cxk1995/p/5693979.html

    https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#roles

     

    展开全文
  • Android蓝牙4.0BLE

    千次阅读 2016-02-16 09:59:25
    原文地址:http://developer.android.com/guide/topics/connectivity/bluetooth-le.html 安卓4.3(API 18)为BLE核心功能提供平台支持和API...这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传
  • Android蓝牙4.0之GATT

    千次阅读 2016-04-29 10:20:04
    蓝牙4.0——Android BLE开发官方文档翻译 ...这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attri
  • Android ble低功耗蓝牙开发

    千次阅读 2015-12-17 11:46:21
    Android4.3(API等级18)平台上开始支持低功耗蓝牙...与传统蓝牙相比,低功耗蓝牙的设计对电量消耗更低,这允许Android应用与其他的低功耗设备通信时对电量的需求更低,如距离传感器、心率监视器和医疗健康设备等等。
  • ym——物联网入口之一Android蓝牙4.0

    万次阅读 2014-10-06 16:39:44
    这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范,用
  • 安卓4.3(原料药18)介绍了内置平台支持蓝牙低能量核心作用,并提供了应用程序可以用来发现设备,查询服务,和读/写特性的接口。与经典的蓝牙蓝牙低功耗(BLE)设计是为了提供显着降低功耗。这使得Android应用...
  • 蓝牙4.0--Android BLE(一)

    千次阅读 2016-06-21 00:16:35
    这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。  关键术语和概念 Attribute Protocol(ATT)—GATT在ATT协议基础上建立,也被称为GATT
  • 这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attribute Profile(GATT) —GATT配置文件是一个通用规范,用
  • 这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。关键术语和概念Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范,用于在BLE链路上发
  • Android BLE编程

    2019-05-08 17:00:52
    这一优点使Android App可以与具有低功耗要求的BLE设备通信,如近距离传感器、心脏速率监视器、健身设备。 闲话不多说,让我总结一下,蓝牙的工作流程和使用。 蓝牙编程中,我们可以将蓝牙分为以下几个步骤: 搜索...
  • Android BLE 开发

    2017-04-14 13:33:25
    这一优点使Android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 BLE权限 为了在app中使用蓝牙功能,必须声明蓝牙权限BLUETOOTH。 利用这个权限去执行蓝牙
  • 蓝牙4.0详解

    2017-08-27 10:44:59
    这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范
  • 这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范
  • 这一优点使Android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。 关键术语和概念 Generic Attribute Profile(GATT)—GATT配置文件是一个通用规范
  • 安卓4.3(API 18)为BLE(Bluetooth Low Energy)核心功能提供平台支持和API,App可以利用它来发现设备、查询...这一优点使android App可以与具有低功耗要求BLE设备通信,如近距离传感器、心脏速率监视器、健身设备等。
  • 新版Android开发教程.rar

    千次下载 热门讨论 2010-12-14 15:49:11
    Android Android Android Android 带来影响 ANDROID 推出后可能影响产业包括移动电信业,软件开发业,手机制造业,在以消费者为核心状 态 。 对消费者影响 � 高档手机选择面增加。 � A ndroid 在设计...

空空如也

空空如也

1 2
收藏数 27
精华内容 10
关键字:

蓝牙的写特性通信android