Android 蓝牙4.0 Ble开发(一)
程序员文章站
2022-03-16 17:11:16
...
一,Ble 4.0简介
低功耗蓝牙,低成本、短距离、可互操作的鲁棒性无线技术,从蓝牙4.0开始支持,Android端是从Android4.3开始支持ble,但是是从android5.0开始支持手机作为外设端开发,在此(5.0)之前只能作为*设备开发。
二,API
BluetoothAdapter 蓝牙适配器,通过它来获取蓝牙地址、蓝牙名字、绑定设备、扫描模式、蓝牙状态等参数(后面代码有详细说明)
BluetoothLeScanner 蓝牙扫描类
BluetoothDevice 蓝牙设备类
BluetoothGatt 蓝牙通信类,通过这个类来建立通信通道
BluetoothGattService 蓝牙通信通道服务类
BluetoothGattCallback:*设备回调类。
BluetoothGattServer:外设提供数据类;
BluetoothGattServerCallback:外设回调类
BluetoothGattCharacteracteristic 蓝牙通信通道特征值类
BluetoothGattDescriptor 蓝牙通信通道特征值属性类
一个ble终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个value和多个Descriptor,一个Descriptor包含一个value。其中Characteristic比较重要,用的比较多。Descriptor主要对Characteristic进行范围、单位的描述。
三,ble的分类
*设备(central):进行扫描,启动连接,在单一或多链路层作为主机。
外围设备(periphery):广播发送者,可连接的设备,在单一链路层作为从机。
广播者(Braodcaster):广播发送者,是不可连接的设备。
观察者(Observer):扫描广播,不能够启动连接。
广播者和观察者不能建立连接。应用:温度传感器和温度显示器。
一个*可以同时连接多个周边,但是一个周边只能连接一个*。
四,作为*设备示例
1.初始化Ble
private void initBle() {
//获取蓝牙管理类对象
BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
//获取蓝牙适配器
adapter = manager.getAdapter();
//判断是否支持蓝牙(此处并非是Ble)
if (adapter == null) {
Log.d(tag, "该设备没有蓝牙");
return;
} else {
Log.d(tag, adapter.getAddress() //蓝牙地址
+ "\n" + adapter.getName() //蓝牙名字
+ "\n" + adapter.getBondedDevices()//已匹配的设备
+ + "\n" + adapter.getScanMode() //扫描模式
+ "\n" + adapter.getState());//状态
//判断蓝牙打开状态如果没打开直接打开
if (!adapter.isEnabled()) {
adapter.enable();
}
//当然此处也可采用,通过用户点击来打开蓝牙
// Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); //enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//context.startActivity(enableBtIntent);
}
//判定是否支持Ble
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "该设备上不支持BLE", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "该设备上支持BLE", Toast.LENGTH_SHORT).show();
}
mac.setText("本机的蓝牙mac\n" + adapter.getAddress());
}
2.扫描
// lescan开始扫描ble设备
private void startLeScan(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.e(tag,"start bleScan");
//获取扫描对象 mBluetoothLeScanner=adapter.getBluetoothLeScanner();
//扫描结果的集合
List<ScanFilter>bleScnFilter=new ArrayList<>();
bleScnFilter.add(new ScanFilter.Builder().setDeviceAddress(address).build());
//扫描设置
ScanSettings bleScanSetting= new ScanSettings.Builder().build();
//开始扫描
mBluetoothLeScanner.startScan(null, bleScanSetting, mBleScanCallback);
}else{
Log.e(tag,"build not support LeScan");
}
}
3.扫描回调
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
//扫描结果回调方法
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.e(tag, "bleScan success");
//扫描的设备名字
Log.e(tag, "device name:" + result.getDevice().getName());
//扫描的设备蓝牙地址
Log.e(tag, "device address:" + result.getDevice().getAddress());
//扫描的设备通道的UUID
Log.e(tag, "device Services UUID:" + result.getDevice().getUuids());
//扫描的设备广播标志
Log.e(tag, "record advertise flags:" + Integer.toHexString(result.getScanRecord().getAdvertiseFlags()));
//蓝牙传输功率
Log.e(tag, "record Tx power level:" + result.getScanRecord().getTxPowerLevel());
//设备名称
Log.e(tag, "record device name:" + result.getScanRecord().getDeviceName());
//服务的UUID
Log.e(tag, "record services UUID:" + result.getScanRecord().getServiceUuids());
//广播的数据
Log.e(tag, "record services data:" + result.getScanRecord().getServiceData());
//广播的数据
Log.e(tag, "record services data2:" + result.getScanRecord().getServiceData());
//广播的特征值的UUID
readuuid= result.getDevice().getAddress().toString();
}
//扫描失败回调方法
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.e(tag, "Blescan fail " + errorCode);
}
};
4.停止扫描
private void stopScnning(){
//应该先判断是否实例化扫描对象,否则会出现空指针异常
if (mBluetoothLeScanner!=null){
Log.e(tag,"stop scnning");
mBluetoothLeScanner.stopScan(mBleScanCallback);
}
5.连接
//这里的连接是根据蓝牙地址直接来进行连接的
private void connectBluetooth() {
Log.e(tag,"conectBluetooth");
String contents=content.getText().toString();
devices=adapter.getRemoteDevice(contents);
if (devices==null){
Log.e(tag,"devices==null");
}else{
//得到gatt通信的对象 mBluetoothGatt=devices.connectGatt(this,false,mGattCallback);
//连接
mBluetoothGatt.connect();
}
}
}
6.连接回调
private final BluetoothGattCallback mGattCallback=new BluetoothGattCallback() {
//连接状态改变
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (mBluetoothGatt==null){
Log.e(tag,"mBluetooth is null");
return;
}
if (newState== BluetoothProfile.STATE_CONNECTED){
Log.e(tag,"已连接");
//连接上去执行此方法,获取通信服务
gatt.discoverServices();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss:SSS");
date2 = new Date(System.currentTimeMillis());//获取当前时间
str2 = formatter.format(date2);
long date3=date2.getTime()-date1.getTime();
msg.setText("开始时间:"+str1+"\n"+"连接完成:"+str2+"\n连接时间差:"+date3+"ms");
Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show();
}else if (newState== BluetoothProfile.STATE_CONNECTING){
Log.e(tag,"正在连接");
}else if (newState== BluetoothProfile.STATE_DISCONNECTED){
Log.e(tag,"断开连接"+status+newState);
}else if (newState== BluetoothProfile.STATE_DISCONNECTING){
Log.e(tag,"正在断开连接");
}
}
//当通道写入的时候回调
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.e(tag,"write state"+status);
}
//当D发现可用通道服务的时候回调
@Override//onServicesDiscovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.e(tag,"有可用服务"+gatt.getServices().toString());
if (status==BluetoothGatt.GATT_SUCCESS){
List<BluetoothGattService> service=gatt.getServices();
// getUUID(service);
Log.e(tag,"有可用服务");
Toast.makeText(MainActivity.this,"有可用服务",Toast.LENGTH_SHORT).show();
}else if (status==BluetoothGatt.GATT_FAILURE){
Log.e(tag,"没有发现可用服务");
Toast.makeText(MainActivity.this,"没有发现可用服务",Toast.LENGTH_SHORT).show();
}else{
Log.e(tag,"没有发现可用服务"+status);
Toast.makeText(MainActivity.this,"没有发现可用服务2",Toast.LENGTH_SHORT).show();
}
}
//当通道数据发送改变的时候回调
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.e(tag,characteristic+"");
Toast.makeText(MainActivity.this,"数据发生变化",Toast.LENGTH_LONG).show();
if (characteristic.getValue()!=null){
Log.e(tag,"数据发生变化");
}else{
Log.e(tag,"数据未发生变化");
}
}
//当通道被读的时候回调
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status==BluetoothGatt.GATT_SUCCESS){
Log.e(tag,characteristic.getValue()+"我是分割线"+status);
if (characteristic.getValue().equals(str));
}
}
//当Descriptor写入的时候回调
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
String uuid=descriptor.getValue().toString();
Log.e(tag,uuid+"");
}
};
7.断开连接
private void cutConnectBluetooth(){
if (devices==null){
Log.e(tag," devices or mBluetoothGatt is null");
}else{
if (mBluetoothGatt==null){
Log.e(tag,"mBluetooth is isconnect");
return;
}else{
Log.e(tag,"do disconnect mBluetooth");
mBluetoothGatt.disconnect();
mBluetoothGatt=null;
}
}
}
注意的是必须在调用的页面销毁的时候关闭连接关闭通道,否则会崩溃。
8.最后的最后
权限问题不要忘了!
在你的app manifest文件中声明蓝牙权限。
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
如果想声明你的app只为具有BLE的设备提供,在manifest文件中包括:
<uses-featureandroid:name="android.hardware.bluetooth_le" android:required="true"/>
结语:第一次想把自己爬过的坑,能分享给大家。而且蓝牙这块资料很少,一路过来很多坑,所以在项目截止今天比较有时间的时候,静下心,写了下来,分享给大家,希望能一起进步!Demo在我把外设端写完的时候一起上传!有写的不对的理解不对的地方,万望指正!
上一篇: 详细解读php的异常处理机制
推荐阅读