Android平台BLE低功耗蓝牙开发

[复制链接]

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

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

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

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

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

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

// 使用此检查确定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,如果支持,确认已经启用。注意如果设置为false,这个检查才是必需的。

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

获取 BluetoothAdapter

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

// 初始化蓝牙适配器

final BluetoothManager bluetoothManager =

(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);

mBluetoothAdapter = bluetoothManager.getAdapter();开启蓝牙

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

// 确保蓝牙在手机上可以开启

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

Intent enableBtIntent = newIntent (BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

}发现BLE设备

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

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

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

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

/**

* 扫描和显示可以提供的蓝牙设备.

*/

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的实现。

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

}

});

}

};连接到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客户端操作。

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

//通过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。注意在该部分中的数据解析按照蓝牙心率测量配置文件规格进行。

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来处理:

// 通过服务控制不同的事件

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

}

}

};关闭客户端App

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

public void close() {

if (mBluetoothGatt == null) {

return;

}

mBluetoothGatt.close();

mBluetoothGatt = null;

}

android 车载安富蓝牙电话开发,Android平台BLE低功耗蓝牙开发相关推荐

  1. android 车载安富蓝牙电话开发,为了进一步助力物联网产品的开发,安富利研发安卓 9.0 操作系统...

    球领先的技术解决方案提供商安富利推出了全新的 MaaXBoard Mini 单板计算机,进一步扩大其硬件产品阵容.此举旨在帮助物联网开发者快速将新产品推向市场,并降低开发成本.MaaXBoard Mi ...

  2. Android BLE低功耗蓝牙开发

    啦啦啦在上一个项目中有用到BLE低功耗蓝牙开发,当时baidu google了很多资料,但大多数都是千篇一律,英文文档我这种渣渣又看不懂...总之刚开始查的很痛苦.所以要把自己的踩坑之路写下来记录下, ...

  3. Android 8.0 BLE 低功耗蓝牙开发记录

    Android 8.0 BLE 低功耗蓝牙开发记录(1-3)--------------(权限申请篇未完待续) 目的:开源博客,希望大家一起修改博客错误地方,共同完善并会鸣谢提供意见的朋友.为大家提供 ...

  4. ble 低功耗蓝牙开发学习 嵌入式交流学习

    ble 低功耗蓝牙开发学习 嵌入式交流学习 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 这篇文章教你学会低功耗蓝牙开发,从0到深入,适合自学的学生.初级工程师 前言 随着疫情爆发 ...

  5. c# 低功耗蓝牙_Android ble低功耗蓝牙开发-客户端

    什么是BLE(低功耗蓝牙) BLE(Bluetooth Low Energy,低功耗蓝牙)是对传统蓝牙BR/EDR技术的补充. 尽管BLE和传统蓝牙都称之为蓝牙标准,且共享射频,但是,BLE是一个完全 ...

  6. Android ble covana,Android BLE低功耗蓝牙开发

    最近做了一个智能硬件开发(针灸仪)的项目,有一部分涉及到低功耗蓝牙的开发,就是通过蓝牙和设备进行数据的交互,比如控制改设备的LED的开关,设备的开关机,设置设备的时间和温度等,下面就项目中遇到的坑一一 ...

  7. android低耗能蓝牙开发,Android BLE低功耗蓝牙开发

    最近做了一个智能硬件开发(针灸仪)的项目,有一部分涉及到低功耗蓝牙的开发,就是通过蓝牙和设备进行数据的交互,比如控制改设备的LED的开关,设备的开关机,设置设备的时间和温度等,下面就项目中遇到的坑一一 ...

  8. Android BLE低功耗蓝牙开发(下) BLE客户端(中央设备)与GATT服务的通讯

    之前的文章简单实现了使用传统蓝牙进行通讯的DEMO,说是最简单其实只是夸张的写法~毕竟标题党横行,我们也得学学点~至少没有UC震惊部那么夸张. 然后,本来是要写Android开发之BlueTooth- ...

  9. BLE低功耗蓝牙开发学习,从零到深教程文档总结(持续更新2022/6/14更新)

    写在前面: 写教程原因: 说说自己写这次的ble教程的由来吧.以往公司总有很多是做单片机的或者应届生毕业,他们对ble不是很连接,公司一般都会安排别人来做一点培训啊,或者老员工带.巧了,之前帮别的培训 ...

  10. 20_微信小程序-BLE低功耗蓝牙开发-发布小程序

    所有功能测试OK了,就剩下最后一步了,那就是把开发好的微信小程序发布出去. 1. 填写小程序信息,登录小程序管理平台,在设置->填写信息,里面填写小程序相关信息(后面我直接把小程序名称改为&qu ...

最新文章

  1. 通过性能计数器确定.net应用程序是否存在内存溢出
  2. iphone电池怎么保养_苹果iPhone手机怎么开启【优化电池充电】
  3. 测试管理 | 4种优先级排序方法一定要掌握
  4. mkdir: 无法创建目录“/home/lj/.tldr“: 文件已存在
  5. linux ping策略打开_Linux Iptables允许或阻止ICMP ping请求
  6. CC1101魔幻的收发切换机制
  7. 深掘工业互联网大数据五大维度
  8. Python学习教程:教你用Python通过微信来控制电脑摄像头
  9. ssh 远程连接、上传下载命令
  10. erdas几何校正_ERDAS遥感图像的几何校正.docx
  11. zmq xsub/xpub 实现消息订阅(一)
  12. gopher对mysql的利用_[题目]记一次利用gopher的内网mysql盲注
  13. 锐捷交换机忘记密码解决方案:恢复出厂设置、重置配置文件
  14. 8-详解前缀树贪心算法N皇后问题
  15. rm: cannot remove `/usr/local/tmp/‘: Directory not empty
  16. Android ADB USB 驱动 万能配置方式
  17. 累计投放贷款1000亿,马云是如何做银行的?
  18. 2020中国彩礼地图:哪里娶媳妇最贵?
  19. 浅谈三次数学危机——费马大定理
  20. docker迁移遇到torch不能使用

热门文章

  1. 鼠标移动文字上显示图片
  2. C语言库函数:memcmp/strcmp和strncmp的区别
  3. 使用halcon实现3维点云物体与模型的匹配并显示差异
  4. Riverbed SteelHead 9.5.0
  5. 电脑系统更新完后,计算机管理服务中找不到mysql的服务
  6. 网络编程中常用的fd是什么
  7. OSChina 周五乱弹 —— 为什么程序媛那么少?
  8. OpenAI 最强对话模型 ChatGPT 注册使用笔记
  9. 问题 B: 神棍的纯真愿望
  10. 【转】iPhone通讯录AddressBook.framework和AddressBookUI.framework的应用