Android(安卓)BLE蓝牙4.2数据透传操作
16lz
2021-01-26
BLE蓝牙4.2数据透传操作
- 蓝牙模块服务查看
- 测试代码
- 新建工程
- 添加权限
- 初始化几个工具控件
- 代码流程
- Android版本有网友提到需要7.0以上(未求证)
- 本文所测试的蓝牙模块是CC2640,不适用蓝牙2.0版本。
实现大概效果如下(发送数据在点击事件中写的固定的字符串):
蓝牙模块服务查看
这里用到一个软件可以查看使用的蓝牙模块广播的服务,打开手机蓝牙后开启软件即可扫描到附近的蓝牙信号,找到自己的蓝牙模块名字,点击旁边的CONNECT按钮:
连接成功后就可以看到正在广播的服务,找到类似如下的描述:
上面的UUIDf000fff1-0451-4000-b000-000000000000到来进行写操作,描述Client Characteristic Configuration的UUID0x2902补充完整就是00002902-0000-1000-8000-00805f9b34fb是用来监听数据接收。这里有网友提供的UUID的解释,不同厂家的蓝牙模块UUID可能会不一样。这里的两个UUID在后面编写程序的时候会用到。
测试代码
为使工程简洁,就不创建别的类了,所有代码就都在MainActivity里面来写,代码量也不大。
新建工程
新建一个Android空白工程,使用的是Android Studio,具体新建步骤就不描述了:
添加权限
<!-- 蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- 定位权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
初始化几个工具控件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/scan_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="扫描" /> <Button android:id="@+id/send_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="发送" /> </LinearLayout> <TextView android:id="@+id/re_tv" android:layout_width="match_parent" android:layout_height="wrap_content" /> <ListView android:id="@+id/bluetooth_lv" android:layout_width="match_parent" android:layout_height="wrap_content"></ListView></LinearLayout>
代码流程
蓝牙的操作流程网友介绍得比较详细,这里不再做重复介绍,上面的演示效果除了布局,写的代码其余都在这一个MainActivity类里,也就没有做太多优化(抄起来方便),其中比较关键的就是一定要检查那两个UUID:
package com.example.bluetooth4;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.BluetoothProfile;import android.bluetooth.le.BluetoothLeScanner;import android.bluetooth.le.ScanCallback;import android.bluetooth.le.ScanResult;import android.os.Build;import android.os.Handler;import android.os.Message;import android.support.annotation.RequiresApi;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.LinkedList;import java.util.List;import java.util.UUID;public class MainActivity extends AppCompatActivity implements View.OnClickListener { // 布局控件 private Button scanBtn; private Button sendBtn; private TextView reTv; // 蓝牙相关的变量 private BluetoothAdapter mBluetoothAdapter; private BluetoothLeScanner mBluetoothManager; private List<BluetoothDevice> mBluetoothDevice; private BluetoothGatt mBluetoothGatt; private BluetoothGattCharacteristic mWriteCharacteristic; // 用于显示搜索到的蓝牙列表 private ArrayAdapter arrayAdapter; private ListView bluetoothLv; private LinkedList<String> bluetoothList = new LinkedList(); @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化控件 scanBtn = findViewById(R.id.scan_btn); sendBtn = findViewById(R.id.send_btn); bluetoothLv = findViewById(R.id.bluetooth_lv); reTv = findViewById(R.id.re_tv); // 设置监听事件 scanBtn.setOnClickListener(this); sendBtn.setOnClickListener(this); mBluetoothDevice = new ArrayList<>(); arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, bluetoothList); bluetoothLv.setAdapter(arrayAdapter); bluetoothLv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.d("Bluetooth", "选择的蓝牙名称:" +mBluetoothDevice.get(position).getName()); mBluetoothGatt = mBluetoothAdapter.getRemoteDevice(mBluetoothDevice.get(position).getAddress()).connectGatt(getApplicationContext(), true, mGattCallback); Message msg = new Message(); msg.obj = "正在连接..."; mHandlerLog.sendMessage(msg); } }); // 直接获取手机蓝牙是配置,没有再写判断蓝牙的状态(用软件之前那先把蓝牙打开) mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothManager = mBluetoothAdapter.getBluetoothLeScanner(); } // 刷新蓝牙列表 private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); BluetoothDevice device = (BluetoothDevice)msg.obj; Log.d("Bluetooth", "蓝牙名称:" + device.getAddress()+" "+device.getName()); String temp = device.getAddress()+" "+device.getName(); if(bluetoothList.contains(temp)==false) { mBluetoothDevice.add(device); bluetoothList.add(temp); arrayAdapter.notifyDataSetChanged(); } } }; // 提示连接状态 private Handler mHandlerLog = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_SHORT).show(); } }; // 用来刷新接收控件 private Handler mHandlerRes = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); reTv.setText((String)msg.obj); } }; // 扫描蓝牙的回调,把扫描到的用mHandler刷新到界面上 private ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice device = result.getDevice(); Message msg = new Message(); msg.obj = device; mHandler.sendMessage(msg); } }; // 两个按钮的点击事件 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override public void onClick(View v) { if(v.getId()==R.id.scan_btn) { if(scanBtn.getText().toString().equals("扫描")) { mBluetoothDevice.clear(); scanBtn.setText("停止"); mBluetoothManager.startScan(scanCallback); } else { scanBtn.setText("扫描"); mBluetoothManager.stopScan(scanCallback); } } if(v.getId()==R.id.send_btn) { mWriteCharacteristic.setValue("bluetest"); Log.d("Bluetooth", "发送数据"); mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); } } // 蓝牙的服务回调 private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (newState == BluetoothProfile.STATE_CONNECTED) { //连接成功 Log.d("Bluetooth", "连接成功"); Message msg = new Message(); msg.obj = "连接成功"; mHandlerLog.sendMessage(msg); mBluetoothGatt.discoverServices(); //连接成功后就去找出该设备中的服务 private BluetoothGatt mBluetoothGatt; } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { //连接失败 } } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { //找到服务了 List<BluetoothGattService> serviceList= mBluetoothGatt.getServices(); //在这里可以对服务进行解析,寻找到你需要的服务 Log.d("Bluetooth", "找到服务了"+serviceList.size()); for(int i=0;i<serviceList.size();i++) { Log.d("Bluetooth", "服务:"+serviceList.get(i).getUuid().toString()); List<BluetoothGattCharacteristic> gattCharacteristics = serviceList.get(i).getCharacteristics(); for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { // 遍历每条服务里的所有Characteristic Log.d("Bluetooth", "服务Characteristic:"+gattCharacteristic.getUuid().toString()); if (gattCharacteristic.getUuid().toString().equals("f000fff1-0451-4000-b000-000000000000")) { mBluetoothGatt.setCharacteristicNotification(gattCharacteristic,true); //获取一个描述符 BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.readCharacteristic(gattCharacteristic); mBluetoothGatt.writeDescriptor(descriptor); mWriteCharacteristic = gattCharacteristic; } } } } else { Log.d("Bluetooth", "onServicesDiscovered received: " + status); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { Log.d("Bluetooth", "onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + characteristic.getUuid().toString()); }//有数据过来就会回调到这个方法 @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { Log.d("Bluetooth", "接收数据:"+ characteristic.getStringValue(0)); if (characteristic.getValue() != null) { Message msg = new Message(); msg.obj = characteristic.getStringValue(0); mHandlerRes.sendMessage(msg); } } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { Log.d("Bluetooth", "--------onDescriptorWrite-----"); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { Log.d("Bluetooth", "--------onReadRemoteRssi-----"+rssi); } };}
提供demo以作参考
更多相关文章
- Android之手机定位方式(GPS定位,网络定位,基站定位)
- [置顶] android CMWAP, CMNET有何区别
- Android通过OkHttp框架上传照片到服务器
- 搭建XMPP协议,实现自主推送消息到手机
- 写了个Android聊天客户端框架,基本聊天功能、数据库、服务器都有
- Android(安卓)智能机顶盒之蓝牙遥控器开机自动配对
- Android(安卓)API Guides---Building Accessibility Services
- Android下Socket简单通信+Python服务器
- Android(安卓)一文学会无障碍服务(AccessibilityService)