1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 蓝牙BLE设备连接与通信

蓝牙BLE设备连接与通信

时间:2019-07-02 15:29:28

相关推荐

蓝牙BLE设备连接与通信

1、在建立BLE设备进行通信时注意3点

1.1、蓝牙位置权限必须动态申请(Android 6.0以上),如果没有动态申请会出现下面的问题

Need BLUETOOTH permission: Neither user 10063 nor current process has android.permission.BLUETOOTH.

1.2、尽管设置了BluetoothGatt中的setCharacteristicNotification(),但无法触发BluetoothGattCallback中的onCharacteristicChanged()方法

需要重新写setCharacteristicNotification()方法

1.3、读写和设置通知都是单步操作,必须执行完一个才能执行第二个,否则会操作失败

2、BLE通信基本流程

作者认为BLE连接与通信关键点是两个回调。

2.1、蓝牙扫描回调(BluetoothAdapter.LeScanCallback、ScanCallback(此方法使用不在赘述,参见作者的蓝牙扫描(简单)))

如果蓝牙扫描成功会执行onLeScan方法,可以获得设备的基本信息,例如:设备名字、设备地址

2.2、蓝牙连接回调(BluetoothGattCallback)

这个回调方法比较多需要细看。这个回调中常用的有以下几个方法:

onConnectionStateChange:当回调执行、状态发生变化时执行,在此方法中常用来搜索服务(BluetoothGatt#discoverServices())

onServicesDiscovered:当搜索服务执行时执行,在此方法中可以获得蓝牙设备服务的相关信息和特征的信息,例如:服务的UUID、特征的UUID、特征的属性等。

onCharacteristicWrite:当向蓝牙设备发送写命令(BluetoothGatt#writeCharacteristic())时执行,在此方法中可以获得蓝牙设备发送命令的执行状态。

onCharacteristicChanged:当向蓝牙设备发送写命令成功,并且提醒移动设备接收蓝牙设备返回的数据(BluetoothGatt#setCharacteristicNotification())时执行,此方法用来处理蓝牙返回的数据。

onCharacteristicRead:当向蓝牙设备发送读命令(BluetoothGatt#readCharacteristic())执行。

2.3、建立通信的过程

动态申请蓝牙位置权限;

获得蓝牙适配器、判断蓝牙是否支持、蓝牙是否打开;

扫描蓝牙(调用BluetoothAdapter.LeScanCallback、或者调用ScanCallback),在onLeScan(或者调用onScanResult)中处理蓝牙回调的蓝牙设备信息;

与蓝牙设备建立连接(调用BluetoothGattCallback),首先在onConnectionStateChange()方法中搜索服务,然后在onServicesDiscovered()方法中获得服务的UUID、特征的UUID和目标特征,根据服务的UUID、特征的UUID和目标特征与蓝牙设备建立连接,并向设备发送写命令,同时提醒移动设备接收蓝牙数据;

在onCharacteristicChanged方法中接收蓝牙返回的数据。

2.4、蓝牙通用唯一识别码(UUID,Universally Unique Identifier)的理解

一个设备中有多个服务(多个服务的UUID),一个服务中有多个特征(多个特征的UUID),多个设备的UUID可以都相同。

例如:

设备1:dev-01{server1(ser_UUID-01):{characteristic1_1(char1_UUID-01),characteristic1_2(char1_UUID-02),characteristic1_3(char1_UUID-03)},

server2(ser_UUID-02):{characteristic2_1(char2_UUID-01),characteristic2_2(char2_UUID-02),characteristic2_3,(char2_UUID-03)}}

设备2:dev-02{server1(ser_UUID-01):{characteristic1_1(char1_UUID-01),characteristic1_2(char1_UUID-02),characteristic1_3(char1_UUID-03)},

server2(ser_UUID-02):{characteristic2_1(char2_UUID-01),characteristic2_2(char2_UUID-02),characteristic2_3,(char2_UUID-03)}}

3、权限

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

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

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

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-feature

android:name="android.hardware.bluetooth_le"

android:required="true" />

4、xml代码

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="/apk/res/android"

xmlns:tools="/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

tools:context=".MainActivity">

<Button

android:id="@+id/search"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="搜索"/>

<Button

android:id="@+id/link"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="连接"/>

<Button

android:id="@+id/getData"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="接收数据"/>

<TextView

android:id="@+id/result"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="数据字节长度"/>

<ListView

android:id="@+id/lv"

android:layout_width="match_parent"

android:layout_height="wrap_content">

</ListView>

</LinearLayout>

5、java代码

public class MainActivity extends AppCompatActivity {

private ArrayList<String> data = null;

private ListView listView = null;

private BluetoothAdapter bta = null;

private BluetoothManager btm = null;

private Button button = null;

private Button link = null;

private Button getDataButton = null;

private TextView result = null;

ArrayAdapter<String> adapter = null;

private BluetoothGatt btg = null;

private BluetoothDevice mDevice=null;

private Handler handler = new Handler();

private boolean isScanning = true;

private boolean isLinking = false;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// 获得数据

this.data = new ArrayList<>();

// 初始化控件

this.initView();

this.checkBlePermission();

}

// 初始化控件

private void initView() {

this.result = findViewById(R.id.result);

// 获得button

this.button = findViewById(R.id.search);

this.button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// 扫描蓝牙

scanBle();

}

});

this.link = findViewById(R.id.link);

this.link.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if(!isScanning){

linkBlue();

}else {

Toast.makeText(MainActivity.this, "没有扫描到蓝牙设备",Toast.LENGTH_SHORT).show();

}

}

});

this.getDataButton = findViewById(R.id.getData);

this.getDataButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if(isLinking){

getData();

}else {

Toast.makeText(MainActivity.this, "蓝牙设备没建立连接",Toast.LENGTH_SHORT).show();

}

}

});

// 初始化ListView

this.adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, this.data);

this.listView = findViewById(R.id.lv);

this.listView.setAdapter(adapter);

}

/*----- 搜索蓝牙设备 -----*/

// 扫描蓝牙

private void scanBle() {

btm = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

// 初始化蓝牙适配器

if(btm == null){

return;

}

bta = btm.getAdapter();

if(bta == null){

this.result.setText("The bluetooth not support");

this.result.setVisibility(View.VISIBLE);

return;

}

// 打开蓝牙

if (!bta.isEnabled()) {

Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enable, 1);

} else {

bta.startLeScan(oldBtsc);

// 设置扫描时间

handler.postDelayed(new Runnable() {

@Override

public void run() {

bta.stopLeScan(oldBtsc);

Log.d("------------","停止扫描");

}

}, 8000);

}

}

private BluetoothAdapter.LeScanCallback oldBtsc = new BluetoothAdapter.LeScanCallback() {

@Override

public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {

if(device.getName().equals("ECG-XA01")){

mDevice=device;

data.add(device.getAddress() + ""+ device.getName());

Log.d("------------", device.getAddress());

adapter.notifyDataSetChanged();

bta.stopLeScan(oldBtsc);

isScanning = false;

}

}

};

/*----- 搜索蓝牙服务和特征 -----*/

// 连接蓝牙

private void linkBlue(){

btg = mDevice.connectGatt(MainActivity.this, true, btgcb);

}

// 获得数据

private void getData(){

BluetoothGattService service = btg.getService(UUID.fromString("0000180F-0000-1000-8000-00805F9B34FB"));

BluetoothGattCharacteristic characteristic1= service.getCharacteristic(UUID.fromString("11111102-5544-7766-9988-AABBCCDDEEFF"));

setCharacteristicNotification(characteristic1, true);

if(btg.writeCharacteristic(characteristic1)){

Log.d("------------","writeCharacteristic");

}

}

private BluetoothGattCallback btgcb = new BluetoothGattCallback() {

@Override

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

super.onConnectionStateChange(gatt, status, newState);

if(newState == BluetoothGatt.STATE_CONNECTED){

Log.d("------------","ConnectionStateChange");

// 搜索服务

btg.discoverServices();

}

}

@Override

public void onServicesDiscovered(BluetoothGatt gatt, int status) {

super.onServicesDiscovered(gatt, status);

Log.d("------------","ServicesDiscovered");

if (status == BluetoothGatt.GATT_SUCCESS) {

List<BluetoothGattService> supportedGattServices = btg.getServices();

for(int i=0;i<supportedGattServices.size();i++){

Log.d("------------","1:BluetoothGattService UUID=:"+supportedGattServices.get(i).getUuid());

List<BluetoothGattCharacteristic> listGattCharacteristic=supportedGattServices.get(i).getCharacteristics();

for(int j=0;j<listGattCharacteristic.size();j++){

Log.d("------------","2:BluetoothGattCharacteristic UUID=:"+listGattCharacteristic.get(j).getUuid());

}

}

BluetoothGattService service1 = btg.getService(UUID.fromString("0000300F-0000-1000-8000-00805F9B34FB"));

final BluetoothGattCharacteristic characteristic1= service1.getCharacteristic(UUID.fromString("11111101-5544-7766-9988-AABBCCDDEEFF"));

characteristic1.setValue(new byte[]{0x01, 0x01});

btg.writeCharacteristic(characteristic1);

btg.setCharacteristicNotification(characteristic1, true);

Log.d("------------","write success ");

} else {

Log.d("------------", "onservicesdiscovered收到: " + status);

}

}

@Override

public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

super.onCharacteristicRead(gatt, characteristic, status);

}

@Override

public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

super.onCharacteristicWrite(gatt, characteristic, status);

Log.d("------------", "CharacteristicWrite" + status);

if(status == BluetoothGatt.GATT_SUCCESS){

// 连接成功

isLinking = true;

}

}

@Override

public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {

super.onCharacteristicChanged(gatt, characteristic);

Log.d("------------", "CharacteristicChanged");

// 查看字节长度

Log.d("------------", characteristic.getValue().length+" ");

result.setText("获得字节长度:"+characteristic.getValue().length);

}

};

// 如果setCharacteristicNotification()不能触发onCharacteristicChanged()方法时,调用此方法

public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {

if (bta == null || btg == null) {

Log.w("------------", "BluetoothAdapter not initialized");

return;

}

btg.setCharacteristicNotification(characteristic, enabled);

List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();

for (BluetoothGattDescriptor dp : descriptors) {

dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

btg.writeDescriptor(dp);

}

}

// 位置权限动态申请(ACCESS_COARSE_LOCATION)

public void checkBlePermission() {

if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)

!= PackageManager.PERMISSION_GRANTED) {

// 调用系统的方法

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);

} else {

Log.i("tag", "已申请位置权限");

}

}

// 位置权限动态申请(ACCESS_COARSE_LOCATION)

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

switch (requestCode) {

// 此处的1与上文的checkBlePermission()方法中ActivityCompat.requestPermissions的1(requestCode)对应

case 1: {

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

Log.i("tag", "同意位置申请");

} else {

Log.i("tag", "拒绝位置申请");

}

return;

}

}

}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。