最近项目中有用到和硬件手环交互的功能。手环是一个BLE手环,需要用到蓝牙技术。
1.在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2.动态权限获取:(这个必须加,不然会导致搜索设备的回调不被调用)
//清单文件里面也需要配置
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.CAMERA,}, 0);
}
//系统方法,从requestPermissions()方法回调结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//确保是我们的请求
if (requestCode == REQUEST_COARSE_LOCATION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限被授予", Toast.LENGTH_SHORT).show();
} else if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
3.获取BluetoothManager管理者:
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
4.获取BluetoothAdapter对象:
mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBluetooth = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, 1);
}
5.开始搜索设备设置回调,当有设备被搜索到时 就会回调此方法:
mBluetoothAdapter.startLeScan(mLeScanCallback);
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
try {
int startByte = 2;
boolean patternFound = false;
while (startByte <= 5) {
if (((int) scanRecord[startByte + 2] & 0xff) == 0x02 && // Identifies
((int) scanRecord[startByte + 3] & 0xff) == 0x15) { // Identifies
patternFound = true;
break;
}
startByte++;
}
// 如果找到了的话
if (patternFound) {
// 转换为16进制
byte[] uuidBytes = new byte[16];
System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16);
String hexString = bytesToHex(uuidBytes);
// ibeacon的UUID值
String uuid = hexString.substring(0, 8) + "-"
+ hexString.substring(8, 12) + "-"
+ hexString.substring(12, 16) + "-"
+ hexString.substring(16, 20) + "-"
+ hexString.substring(20, 32);
// ibeacon的Major值
int major = (scanRecord[startByte + 20] & 0xff) * 0x100
+ (scanRecord[startByte + 21] & 0xff);
// ibeacon的Minor值
int minor = (scanRecord[startByte + 22] & 0xff) * 0x100
+ (scanRecord[startByte + 23] & 0xff);
String ibeaconName = device.getName();
String mac = device.getAddress();
int txPower = (scanRecord[startByte + 24]);
Log.i("lee", " Name:" + ibeaconName + " Mac:" + mac + " UUID:" + uuid + " Major:" + major + " Minor:" + minor + " TxPower:" + txPower + " rssi:" + rssi);
}
} catch (Exception e) {
}
}
};
当有设备被搜索到时就会回调这个方法,第一个参数是设备,第二个参数是rssi,代表信号强度,第三个参数scanRecord是广播包数据。此处写了一个过滤,当是ibeacon设备时就会进入if语句中打印出该ibeacon设备的信息。
全部代码:
package com.demo.ibeacondemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private static final int REQUEST_COARSE_LOCATION = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
isLocationOpen();
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBluetooth = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, 1);
}
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
static final char[] hexArray = "0123456789ABCDEF".toCharArray();
private void isLocationOpen() {
//清单文件里面也需要配置
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.CAMERA,}, 0);
}
}
//系统方法,从requestPermissions()方法回调结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//确保是我们的请求
if (requestCode == REQUEST_COARSE_LOCATION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限被授予", Toast.LENGTH_SHORT).show();
} else if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限被拒绝", Toast.LENGTH_SHORT).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
try {
int startByte = 2;
boolean patternFound = false;
while (startByte <= 5) {
if (((int) scanRecord[startByte + 2] & 0xff) == 0x02 && // Identifies
((int) scanRecord[startByte + 3] & 0xff) == 0x15) { // Identifies
patternFound = true;
break;
}
startByte++;
}
// 如果找到了的话
if (patternFound) {
// 转换为16进制
byte[] uuidBytes = new byte[16];
System.arraycopy(scanRecord, startByte + 4, uuidBytes, 0, 16);
String hexString = bytesToHex(uuidBytes);
// ibeacon的UUID值
String uuid = hexString.substring(0, 8) + "-"
+ hexString.substring(8, 12) + "-"
+ hexString.substring(12, 16) + "-"
+ hexString.substring(16, 20) + "-"
+ hexString.substring(20, 32);
// ibeacon的Major值
int major = (scanRecord[startByte + 20] & 0xff) * 0x100
+ (scanRecord[startByte + 21] & 0xff);
// ibeacon的Minor值
int minor = (scanRecord[startByte + 22] & 0xff) * 0x100
+ (scanRecord[startByte + 23] & 0xff);
String ibeaconName = device.getName();
String mac = device.getAddress();
int txPower = (scanRecord[startByte + 24]);
Log.i("lee", " Name:" + ibeaconName + " Mac:" + mac + " UUID:" + uuid + " Major:" + major + " Minor:" + minor + " TxPower:" + txPower + " rssi:" + rssi);
}
} catch (Exception e) {
}
}
};
}
以上就能完成搜索设备的功能。