1.首先申请相关权限。在manifest.xml
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.bluetooth_le" android:required="true"/>
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application>
.....
</application>
2.声明蓝牙适配器,申请打开蓝牙
private BluetoothAdapter mBluetoothAdapter;
// 判断手机硬件支持蓝牙
if (!getPackageManager().hasSystemFeature( PackageManager.FEATURE_BLUETOOTH_LE))
{
Toast.makeText(this, "手机不支持BLE", Toast.LENGTH_SHORT).show();
finish();//退出
}
// 获取手机本地的蓝牙适配器
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// 打开蓝牙权限
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
{
//弹出对话框,请求打开蓝牙
startActivityForResult(new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE_BT);
}
3.扫描蓝牙设备
mBluetoothAdapter.startLeScan(mLeScanCallback);//开始扫描
mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止扫描
/**
* 蓝牙扫描回调函数 回调蓝牙BluetoothDevice,可以获取name MAC rsss 广播等信息
*
* **/
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback()
{
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord)
{
// TODO
runOnUiThread(new Runnable()
{
@Override
public void run()
{
/* 这里将扫描到设备的信息输出到相应界面显示 */
}
});
}
};
必须注意的是,android5.0以上,使用BluetoothLeScanner进行扫描,以上函数已经不推荐了。
private BluetoothLeScanner bluetoothLeScanner;
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(scanCallback);
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult results) {
super.onScanResult(callbackType, results);
BluetoothDevice device = results.getDevice();
//BluetoothDevice 包含了蓝牙设备的各种信息,比如名字,MAC,等等
//可在此添加扫描的设备到显示界面
}
};
//扫描需要一些时间,想停止可使用一下函数
bluetoothLeScanner.stopScan(scanCallback);
4.连接蓝牙
上面手机扫描到其他蓝牙设备(GAP协议),接下来就要建立连接,通讯(GATT协议)。
//蓝牙service,负责后台的蓝牙服务
private static BluetoothLeService mBluetoothLeService;
//蓝牙特征
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
蓝牙是通过Characteristic进行数据交互的,详细可百度相关知识点。
绑定服务
/* 启动蓝牙service */
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
/* BluetoothLeService绑定的回调函数 */
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName componentName,
IBinder service)
{
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service)
.getService();
if (!mBluetoothLeService.initialize())
{
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
// 根据蓝牙地址,连接设备
mBluetoothLeService.connect(mDeviceAddress);
}
@Override
public void onServiceDisconnected(ComponentName componentName)
{
mBluetoothLeService = null;
}
};
5.处理蓝牙服务
/**
* @Title: displayGattServices
* @Description: 处理蓝牙服务
* @param
* @return void
* @throws
*/
private void displayGattServices(List<BluetoothGattService> gattServices)
{
if (gattServices == null)
return;
String uuid = null;
String unknownServiceString = "unknown_service";
String unknownCharaString = "unknown_characteristic";
// 服务数据,可扩展下拉列表的第一级数据
ArrayList<HashMap<String, String>> gattServiceData =
new ArrayList<HashMap<String, String>>();
// 特征数据(隶属于某一级服务下面的特征值集合)
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData =
new ArrayList<ArrayList<HashMap<String, String>>>();
// 部分层次,所有特征值集合
mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices)
{
// 获取服务列表
HashMap<String, String> currentServiceData = new HashMap<String, String>();
uuid = gattService.getUuid().toString();
// 查表,根据该uuid获取对应的服务名称。SampleGattAttributes这个表需要自定义。
gattServiceData.add(currentServiceData);
System.out.println("Service uuid:" + uuid);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData =
new ArrayList<HashMap<String, String>>();
// 从当前循环所指向的服务中读取特征值列表
List<BluetoothGattCharacteristic> gattCharacteristics = gattService
.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas =
new ArrayList<BluetoothGattCharacteristic>();
// Loops through available Characteristics.
// 对于当前循环所指向的服务中的每一个特征值
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics)
{
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<String, String>();
uuid = gattCharacteristic.getUuid().toString();
if (gattCharacteristic.getUuid().toString()
.equals(HEART_RATE_MEASUREMENT))
{
mhandler.postDelayed(new Runnable()
{
@Override
public void run()
{
// TODO Auto-generated method stub
mBluetoothLeService.readCharacteristic(gattCharacteristic);
}
}, 200);
mBluetoothLeService.setCharacteristicNotification(
gattCharacteristic, true);
target_chara = gattCharacteristic;
}
List<BluetoothGattDescriptor> descriptors = gattCharacteristic
.getDescriptors();
for (BluetoothGattDescriptor descriptor : descriptors)
{
System.out.println("---descriptor UUID:"
+ descriptor.getUuid());
// 获取特征值的描述
mBluetoothLeService.getCharacteristicDescriptor(descriptor);
}
gattCharacteristicGroupData.add(currentCharaData);
}
// 按先后顺序,分层次放入特征值集合中,只有特征值
mGattCharacteristics.add(charas);
// 构件第二级扩展列表(服务下面的特征值)
gattCharacteristicData.add(gattCharacteristicGroupData);
}
}
当需要发送数据时,注意一次发送的数据是有限制的。
private static BluetoothGattCharacteristic cdata= null;
cdata.setValue(str);//str为需要发送的数据
//调用蓝牙服务的写特征值方法实现发送数据
mBluetoothLeService.writeCharacteristic(cdata);
最后定义一个广播接收器专门负责接收处理蓝牙服务。
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
//...
}
}
6.实际测试
使用蓝牙串口模块与电脑连接,打开PC串口助手。测试
电脑端可以正常接收。
这个电脑端的串口软件也是我用C#编写的。
我本来使用XCOM作为串口接收软件,不过XCOM接收是按照GB2312编码接收。