Android BLE 蓝牙编程(三)
上节我们已经可以连接上蓝牙设备了。
本节我们就要获取手环的电池电量和计步啦。
在介绍这个之前我们需要先了解下什么是 服务 什么是 UUID
我们记得上节中我们item监听事件的回调的返回值是BluetoothGatt 类型的,还记得么?嘿嘿。
返回的bluetoothgatt中包含一个或多个BluetoothGattService(服务)
每个service包含一个或多个characteristic(特征值)
每个特征值包含一个value 和多个 descriptor(注意看啊!是一个value)
这些对于本项目来说某个特征值的value中就包含了记录的步数。(很遗憾我折腾了很久也没找到电池电量,不得不舍弃展示电池电量的想法)
先熟悉下下面的图片吧~~
(百度脑图)
在了解下UUID 上图中每个蓝牙设备都有自己的MAC 地址有了这个地址 我们就可以连接这个设备。
连接上设备后会的到设备的服务就是上图中的Gattservice 这每个service都有个固定的UUID以标识区分
每个service又包含多个的characteristic 这些特征值也有唯一的UUID 这些UUID就是我们编程需要的,
获取到characteristic对应的UUID就意味着获取到该characteristic提供的功能或者数据。
特征值对应的UUID所实现的功能是由硬件工程师决定的。
因为小米手环的硬件工程师我们没有联系方式,况且人家也肯定不会告诉我所有功能对应的UUID
因此我们只好自己对应数值来找了。
简单说 上图的每个characteristic 都对应一个UUID 这些UUID对应了设备的不同功能
手环为例:
控制手环震动的 UUID :00002a06-0000-1000-8000-00805f9b34fb 手机向该 UUID 写入 0x01 或者 0x02 时手环都会震动,01强度弱于 02
计步的 UUID :0000ff06-0000-1000-8000-00805f9b34fb 读取该UUID下的value数组 第0 个数据就是 步数
首先我们来获取下计步数吧
经过一番折腾我终于找到了小米手环对应步数的 UUID :0000ff06-0000-1000-8000-00805f9b34fb
gattcallback 回调方法中找到 onServicesDiscovered
添加如下代码:
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
//寻找到服务时
if (status == bluetoothGatt.GATT_SUCCESS) {
final List<BluetoothGattService> services = bluetoothGatt.getServices();
runOnUiThread(new Runnable() {
@Override
public void run() {
//List<String> serlist = new ArrayList<>();
for (final BluetoothGattService bluetoothGattService : services) {
bluetoothGattServices = bluetoothGattService; Log.i(TAG, "onServicesDiscovered: " + bluetoothGattService.getUuid()); List<BluetoothGattCharacteristic> charc = bluetoothGattService.getCharacteristics(); for (BluetoothGattCharacteristic charac : charc) {
Log.i(TAG, "run: " + charac.getUuid());
//找到透传特征值
// 00002a06-0000-1000-8000-00805f9b34fb 小米手环震动特征值 0x01震动 0x02强震
if (charac.getUuid().toString().equals("00002a06-0000-1000-8000-00805f9b34fb")) {
//设备 震动特征值
characteristic_zd = charac; } else if (charac.getUuid().toString().equals("0000ff06-0000-1000-8000-00805f9b34fb")) {
//设备 步数
characteristic_jb = charac;
bluetoothGatt.readCharacteristic(characteristic_jb); Log.i(TAG, "run: 正在尝试读取步数");
} else if (charac.getUuid().toString().equals("")) {
//设备 电量特征值
}
} serviceslist.add(bluetoothGattService.getUuid().toString()); }
}
});
} }
注释写的很清楚
我用 characteristic_zd 记住震动的特征值
用 characteristic_jb 记住计步的
记住计步特征值后使用 bluetoothGatt 提供的read方法并传人相应特征值。该方法为异步方法他的返回内容会由
回调中的 onCharacteristicRead 方法接收到
找到该方法添加如下代码:
if (status == bluetoothGatt.GATT_SUCCESS) {
final int sum = characteristic.getValue()[0]; runOnUiThread(new Runnable() {
@Override
public void run() {
jibu.setText("走了" + sum + "步");
}
}); Log.e(TAG, "onCharacteristicRead: " + characteristic.getValue()[0]); }
方法的参数中status表示状态,为 bluetoothGatt.GATT_SUCCESS 时表示成功获取返回
因为在异步方法中,想要操作UI线程,于是就用了 runOnUiThread 方法。显示出来步数即可。
好了下面贴出完整主Activity代码:
MainActivity.java:
package com.wbnq.shouhuan; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast; import java.util.ArrayList;
import java.util.List;
import java.util.UUID; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button saomiao, duanzhen, changzhen, buting, tingxia;
private TextView jibu, dianliang, lianjiezhuangtai;
private ListView list; public static String TAG = "shouhuan-MainActivity"; BluetoothAdapter bluetoothAdapter;
BluetoothGatt bluetoothGatt;
List<BluetoothDevice> deviceList = new ArrayList<>();
List<String> serviceslist = new ArrayList<String>();
BluetoothDevice bluetoothDevice;
BluetoothGattService bluetoothGattServices;
BluetoothGattCharacteristic characteristic_zd, characteristic_jb; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initView(); //蓝牙管理,这是系统服务可以通过getSystemService(BLUETOOTH_SERVICE)的方法获取实例
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
//通过蓝牙管理实例获取适配器,然后通过扫描方法(scan)获取设备(device)
bluetoothAdapter = bluetoothManager.getAdapter(); } private void initView() {
saomiao = (Button) findViewById(R.id.saomiao);
duanzhen = (Button) findViewById(R.id.zhendong);
changzhen = (Button) findViewById(R.id.changzhen);
buting = (Button) findViewById(R.id.buting);
tingxia = (Button) findViewById(R.id.tingxia);
list = (ListView) findViewById(R.id.list); jibu = (TextView) findViewById(R.id.jibu);
dianliang = (TextView) findViewById(R.id.dianliang);
lianjiezhuangtai = (TextView) findViewById(R.id.lianjiezhuangtai); saomiao.setOnClickListener(this);
duanzhen.setOnClickListener(this);
changzhen.setOnClickListener(this);
buting.setOnClickListener(this);
tingxia.setOnClickListener(this); //item 监听事件
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
bluetoothDevice = deviceList.get(i);
//连接设备的方法,返回值为bluetoothgatt类型
bluetoothGatt = bluetoothDevice.connectGatt(MainActivity.this, false, gattcallback);
lianjiezhuangtai.setText("连接" + bluetoothDevice.getName() + "中...");
}
}); } @Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.saomiao:
//开始扫描前开启蓝牙
Intent turn_on = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turn_on, 0);
Toast.makeText(MainActivity.this, "蓝牙已经开启", Toast.LENGTH_SHORT).show(); Thread scanThread = new Thread(new Runnable() {
@Override
public void run() {
Log.i("TAG", "run: saomiao ...");
saomiao();
}
});
scanThread.start();
lianjiezhuangtai.setText("正在扫描"); break;
case R.id.zhendong: break;
case R.id.changzhen: break;
case R.id.buting: break;
case R.id.tingxia: break;
case R.id.list: break; }
} public void saomiao() {
deviceList.clear();
bluetoothAdapter.startLeScan(callback);
} //扫描回调
public BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
Log.i("TAG", "onLeScan: " + bluetoothDevice.getName() + "/t" + bluetoothDevice.getAddress() + "/t" + bluetoothDevice.getBondState()); //重复过滤方法,列表中包含不该设备才加入列表中,并刷新列表
if (!deviceList.contains(bluetoothDevice)) {
//将设备加入列表数据中
deviceList.add(bluetoothDevice); list.setAdapter(new MyAdapter(MainActivity.this, deviceList));
} }
}; private BluetoothGattCallback gattcallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, final int newState) {
super.onConnectionStateChange(gatt, status, newState); runOnUiThread(new Runnable() {
@Override
public void run() {
String status;
switch (newState) {
//已经连接
case BluetoothGatt.STATE_CONNECTED:
lianjiezhuangtai.setText("已连接");
bluetoothAdapter.stopLeScan(callback);
//该方法用于获取设备的服务,寻找服务
bluetoothGatt.discoverServices();
break;
//正在连接
case BluetoothGatt.STATE_CONNECTING:
lianjiezhuangtai.setText("正在连接");
break;
//连接断开
case BluetoothGatt.STATE_DISCONNECTED:
lianjiezhuangtai.setText("已断开");
break;
//正在断开
case BluetoothGatt.STATE_DISCONNECTING:
lianjiezhuangtai.setText("断开中");
break;
}
//pd.dismiss();
}
});
} @Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
//寻找到服务时
if (status == bluetoothGatt.GATT_SUCCESS) {
final List<BluetoothGattService> services = bluetoothGatt.getServices();
runOnUiThread(new Runnable() {
@Override
public void run() {
//List<String> serlist = new ArrayList<>();
for (final BluetoothGattService bluetoothGattService : services) {
bluetoothGattServices = bluetoothGattService; Log.i(TAG, "onServicesDiscovered: " + bluetoothGattService.getUuid()); List<BluetoothGattCharacteristic> charc = bluetoothGattService.getCharacteristics(); for (BluetoothGattCharacteristic charac : charc) {
Log.i(TAG, "run: " + charac.getUuid());
//找到透传特征值
// 00002a06-0000-1000-8000-00805f9b34fb 小米手环震动特征值 0x01震动 0x02强震
if (charac.getUuid().toString().equals("00002a06-0000-1000-8000-00805f9b34fb")) {
//设备 震动特征值
characteristic_zd = charac; } else if (charac.getUuid().toString().equals("0000ff06-0000-1000-8000-00805f9b34fb")) {
//设备 步数
characteristic_jb = charac;
bluetoothGatt.readCharacteristic(characteristic_jb); Log.i(TAG, "run: 正在尝试读取步数");
} else if (charac.getUuid().toString().equals("")) {
//设备 电量特征值
}
} serviceslist.add(bluetoothGattService.getUuid().toString()); }
// ArrayAdapter<String> adapter = new ArrayAdapter<String>(
// MainActivity.this, android.R.layout.simple_expandable_list_item_1, serviceslist);
//list.setAdapter(adapter);
}
});
} } @Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status); if (status == bluetoothGatt.GATT_SUCCESS) {
final int sum = characteristic.getValue()[0]; runOnUiThread(new Runnable() {
@Override
public void run() {
jibu.setText("走了" + sum + "步");
}
}); Log.e(TAG, "onCharacteristicRead: " + characteristic.getValue()[0]); } } @Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
} //获取返回 数据
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic); Log.i(TAG, "onCharacteristicChanged: 获取回调方法"); Log.e("", "命令:" + HexUtil.encodeHexStr(characteristic.getValue())); final byte[] values = characteristic.getValue(); runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, HexUtil.encodeHexStr(values), Toast.LENGTH_SHORT).show();
}
}); } }; private boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) {
if (bluetoothGatt == null || characteristic == null)
return false;
if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable))
return false;
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (clientConfig == null)
return false; if (enable) {
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
return bluetoothGatt.writeDescriptor(clientConfig);
}
}
今天就写这些,下次要实现震动方法咯!是不是很激动呢~~
嘿嘿嘿~
大家加油啦~~
Android BLE 蓝牙编程(三)的更多相关文章
- Android BLE 蓝牙编程(一)
最近在研究这个,等我有时间来写吧! 终于在端午节给自己放个假,现在就来说说关于android蓝牙ble的 最近的学习成果吧!! 需要材料(写个简单教程吧--关于小米手环的哦!嘿嘿) Android 手 ...
- Android BLE 蓝牙编程(二)
大家中秋快乐啊--哈哈,今天继续工程项目吧! 上篇我们已经实现了蓝牙设备的扫描,本篇我们来通过list展示扫描到的设备并 实现点击连接. 先贴出上篇的完整的MainActivity的方法: packa ...
- Android BLE 蓝牙编程(四)
接上篇,我们已经实现了短震,长震的功能了- 现在我们需要实现点击后一直震动的功能 开始我的想法是再循环中不断执行write方法,然而这个办法行不通. 系统会报错. 那要如何实现这个想法呢?其实很简单, ...
- Android ble 蓝牙4.0 总结
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- Android ble 蓝牙4.0 总结一
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- Android BLE蓝牙详细解读
代码地址如下:http://www.demodashi.com/demo/15062.html 随着物联网时代的到来,越来越多的智能硬件设备开始流行起来,比如智能手环.心率检测仪.以及各式各样的智能家 ...
- 蓝牙防丢器原理、实现与Android BLE接口编程
本文是对已实现的蓝牙防丢器项目的总结,阐述蓝牙防丢器的原理.实现与android客户端的蓝牙BLE接口编程.在这里重点关注如何利用BLE接口来进行工程实现,对于BLE的协议.涉及到JNI的BLE接口内 ...
- [yueqian_scut]蓝牙防丢器原理、实现与Android BLE接口编程
本文是对已实现的蓝牙防丢器项目的总结,阐述蓝牙防丢器的原理.实现与Android客户端的蓝牙BLE接口编程.在这里重点关注如何利用BLE接口来进行工程实现,对于BLE的协议.涉及到JNI的BLE接口内 ...
- android ble蓝牙开发略解
Android 蓝牙4.0开发 1. 权限和相关属性 “android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行,这个4.3之前 ...
随机推荐
- list集合的排序Comparator和Collections.sort
一个例子 package sortt; import java.util.ArrayList; import java.util.Collections; import java.util.Compa ...
- 机顶盒上gridview+ScrollView的使用。
最近在机顶盒上做一个gridview, 其焦点需要在item的子控件上,但gridview的焦点默认在item上,通过 android:descendantFocusability="aft ...
- Linux0.11内核--进程调度分析之1.初始化
[版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5596746.html ] 首先看main.c里的初始化函数main函数里面有个函数是对进程调度 ...
- iOS-钥匙串中证书全部失效(证书的签发者无效)的解决办法
今天用Xcode打包IPA文件给同事,结果提示import时,提示证书missing,找了半天没发现问题,后来打开钥匙串,发现证书全失效了!!!根证书失效了!吓死宝宝了 解决方法 首选此方法: 1.打 ...
- iOS 疑难杂症 — — Swift debugger 无法在控制台 po 变量值的问题
前言 这个问题出现有好几个月了,一直没弄,以为是 Xcode 的问题后面版本升级应该就能好所以就不管了,今天心情好顺便查了一下. 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://w ...
- Thinking in Java 笔记
大二就买了这本书,如今再看这本书,看到了一些以前没看的细节,也有了不同的体会.本文使用第4版,整理每章的笔记心得.老外的书有个特点,他会花费大量的文字去阐述一个概念,这比堆代码强多了. 第 1 章 对 ...
- Vmware扩展磁盘如何不需重启系统
在虚拟机Vmware中我们有时候需要添加新的虚拟磁盘或给已有虚拟磁盘扩容(expand),在新增磁盘或磁盘扩容后,Linux系统并不能马上识别到.也就是说你看不到磁盘空间变化(使用fdisk -l查看 ...
- SQL SERVER 中如何用脚本管理作业
在SQL SERVER中用脚本管理作业,在绝大部分场景下,脚本都比UI界面管理作业要高效.简洁.打个简单的比方,如果你要查看作业的运行时长,如果用UI界面查看,100个作业,你就得在历史记录里面至少查 ...
- 使用multi-paxos实现日志同步应用
paxos 说multi-paxos之前先简要说一下paxos paxos是在多个成员之间对某个值(提议)达成一致的一致性协议.这个值可以是任何东西.比如多个成员之间进行选主,那么这个值就是主的身份. ...
- python安装numpy和pandas
最近要对一系列数据做同比比较,需要用到numpy和pandas来计算,不过使用python安装numpy和pandas因为linux环境没有外网遇到了很多问题就记下来了.首要条件,python版本必须 ...