之前的文章简单实现了使用传统蓝牙进行通讯的DEMO,说是最简单其实只是夸张的写法~毕竟标题党横行,我们也得学学点~至少没有UC震惊部那么夸张。
然后,本来是要写Android开发之BlueTooth--最简单的Andorid低功耗(BLE)蓝牙通讯Demo的,写了一半发现BLE简单不起来,所以分两篇来写BLE相关的应用。因此大家可能发现,你下篇的编写时间别上篇还早?这只是假象~优快云的发布时间是建立草稿的时间,我也是醉了。实际发布时间比上一篇迟将近一周...
上一篇已经简单的写了一下关于GATT服务端的一些知识以及搭建。毕竟这个部分很少要我们做的,所以网络上这方面的资源相对较少。通常外围设备都是有固定产品的,用不着我们开发,例如心率器,血压器等等各种感应器,直接把相关数据格式以及UUID给我们在手机上进行就可以了。但是了解一下也没什么坏处。那么这篇就是简单实现如何用手机连接这些产品获取到对应数据了。
服务端
上一篇文章我们写了一个服务端,这篇就是基于那个服务端程序来建立的连接。所以大家有必要先看一下上一篇,否则这里对应数据的UUID怎么来都不知道。还需要说明的一点是,上一篇我们仅仅成功开启了服务,但是数据更新的逻辑没写。假如他是一个心率传感器,那么我们心率改变时,理应要更新数据,并通知客户端,所以上一篇还缺少了一段代码:
//4.模拟数据更新
private void updateCharacteristic() {
if (mBluetoothGattServer == null) {
return;
}
final Handler updateHandler = new Handler();
updateHandler.postDelayed(new Runnable() {
@Override
public void run() {
for (BluetoothDevice d : mRegisteredDevices) {
BluetoothGattCharacteristic newCharacteristic = mBluetoothGattServer
.getService(TIME_SERVICE)
.getCharacteristic(CURRENT_TIME);
byte[] data = ("数据更新" + System.currentTimeMillis()).getBytes();
newCharacteristic.setValue(data);
mBluetoothGattServer.notifyCharacteristicChanged(d, newCharacteristic, false);
}
updateHandler.postDelayed(this, 5000);
}
}, 5000);//5s更新一次
outputLog("数据模拟更新启动",MSG_TYPE_NORMAL);
}
当广播成功后就启动这个数据更新的函数就行了。接下来开始编写客户端了。编写之前先说明几点:
BLE客户端和传统蓝牙代码上的差异
1.获取适配器
传统蓝牙是这么获取适配器的:
if (mBluetoothAdapter == null) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
BLE蓝牙是这样的:
if (mBluetoothAdapter == null) {
/**这里和传统的蓝牙有什么区别呢?*/
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
到底这算不算区别?反正官方文档这么写,其实这两个互换没感觉到有什么变化,反正都是获取到适配器。具体有没有影响,我还没得测试。有兴趣的试试看,然后告诉我哈~
2.搜索回调
传统蓝牙是需要通过广播来获取搜索结果的:
private void registerRec() {
//3.注册蓝牙广播
mReceiver = new BlueToothStateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);//搜索到蓝牙
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束
registerReceiver(mReceiver, filter);
}
class BlueToothStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(MainActivity.this, "触发广播", Toast.LENGTH_SHORT).show();
String action = intent.getAction();
switch (action) {
case BluetoothDevice.ACTION_FOUND:
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Toast.makeText(MainActivity.this, "找到设备" + device.getName(), Toast.LENGTH_SHORT).show();
if (mRvAdapter != null) {
mRvAdapter.addDevice(device);
}
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
mMessageAdapter.addMessage("搜索结束");
break;
}
}
}
BLE蓝牙是直接以回调方法进行监听的:
private MyLeScanCallback1 mLeScanCallback1 = new MyLeScanCallback1();
private void scanBleDevices1(boolean enable) {
if (enable) {
outputLog("正在搜索设备");
outputLog("当前搜索回调:callback 1");
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback1);
outputLog("停止搜索");
}
}, 10000);//设置10秒超时
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback1);
} else {
outputLog("停止搜索");
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback1);
}
}
class MyLeScanCallback1 implements BluetoothAdapter.LeScanCallback {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
mDeviceAdapter.addDevice(bluetoothDevice);
}
}
3.连接方式
传统蓝牙连接别的设备:
public void run() {
if (mDevice != null) {
try {
//获取套接字
BluetoothSocket temp = mDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));
//mDevice.createRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));//sdk 2.3以下使用
mSocket = temp;
//发起连接请求
if (mSocket != null) {
mSocket.connect();
}
sendHandlerMsg("连接 " + mDevice.getName() + "成功!");
//获取输入输出流
btIs = mSocket.getInputStream();
btOs = mSocket.getOutputStream();
//通讯-接收消息
BufferedReader reader = new BufferedReader(new InputStreamReader(btIs, "UTF-8"));
String content = null;
while (canRecv) {
content = reader.readLine();
sendHandlerMsg("收到消息:" + content);
}
} catch (IOException e) {
e.printStackTrace();
sendHandlerMsg("错误:" + e.getMessage());
} finally {
try {
if (mSocket != null) {
mSocket.close();
}
//btIs.close();//两个输出流都依赖socket,关闭socket即可
//btOs.close();
} catch (IOException e) {
e.printStackTrace();
sendHandlerMsg("错误:" + e.getMessage());
}
}
}
}
BLE连接服务端:
private void connectGatt(BluetoothDevice device) {
outputLog("正在连接到:"+device.getName());
//新建一个链接
mBluetoothGatt = device.connectGatt(BleMainActivity.this, false, mBluetoothGattCallback);
//mBluetoothGatt.connect();//如果是断开重连
//mBluetoothGatt.disconnect();//断开当前连接
}
然后在回调里处理连接成功或者失败的逻辑。
4.通讯方式
传统蓝牙是获取到socket只有以类似于TCP的方式进行通讯。
BLE蓝牙则是通过读写特性来进行通讯。
5.其他
代码上的区别我目前也就总结了这几点,至于其他只能在更详细的开发中慢慢发现了。
搜索回调的方式居然过时了?
相信不少人在按照谷歌文档或者其他翻译文档的博客来写demo得时候发现:
不对啊!我明明按照官方的来,怎么会过时!这官方文档到底自己没有进行更新我就不知道了,反正他在API>=21时,确实过时了。那我们能用什么方法来代