最近工作中用到了蓝牙方面的知识,所以写此博客记录一下。
一、蓝牙开发需要用到的API都在 android.bluetooth包下
表示本地蓝牙适配器(蓝牙无线装置)。 BluetoothAdapter
是所有蓝牙交互的入口点。 利用它可以发现其他蓝牙设备,查询绑定(配对)设备的列表,使用已知的 MAC 地址实例化 BluetoothDevice
,以及创建 BluetoothServerSocket
以侦听来自其他设备的通信。
表示远程蓝牙设备。利用它可以通过 BluetoothSocket
请求与某个远程设备建立连接,或查询有关该设备的信息,例如设备的名称、地址、类和绑定状态等。
表示蓝牙套接字接口(与 TCP Socket
相似)。这是允许应用通过 InputStream 和 OutputStream 与其他蓝牙设备交换数据的连接点。
表示用于侦听传入请求的开放服务器套接字(类似于 TCP ServerSocket
)。 要连接两台 Android 设备,其中一台设备必须使用此类开放一个服务器套接字。 当一台远程蓝牙设备向此设备发出连接请求时,BluetoothServerSocket
将会在接受连接后返回已连接的 BluetoothSocket
。
描述蓝牙设备的一般特征和功能。 这是一组只读属性,用于定义设备的主要和次要设备类及其服务。 不过,它不能可靠地描述设备支持的所有蓝牙配置文件和服务,而是适合作为设备类型提示。
表示蓝牙配置文件的接口。 蓝牙配置文件是适用于设备间蓝牙通信的无线接口规范。
提供蓝牙耳机支持,以便与手机配合使用。
定义高质量音频如何通过蓝牙连接和流式传输,从一台设备传输到另一台设备。“A2DP”代表高级音频分发配置文件。
表示用于控制蓝牙服务的健康设备配置文件代理。
用于实现 BluetoothHealth
回调的抽象类。您必须扩展此类并实现回调方法,以接收关于应用注册状态和蓝牙通道状态变化的更新内容。
BluetoothHealthAppConfiguration
表示第三方蓝牙健康应用注册的应用配置,以便与远程蓝牙健康设备通信。
BluetoothProfile.ServiceListener
在 BluetoothProfile
IPC 客户端连接到服务(即,运行特定配置文件的内部服务)或断开服务连接时向其发送通知的接口
官方文档地址:https://developer.android.com/guide/topics/connectivity/bluetooth,有兴趣可以去看看,上面说的很详细。
二 、要用到的权限
6.0以下
<!-- 使用蓝牙的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 扫描蓝牙设备或者操作蓝牙设置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
6.0以上
<!-- 使用蓝牙的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 扫描蓝牙设备或者操作蓝牙设置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--模糊定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--精准定位权限,仅作用于6.0+-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
三、开发工作
1. 流程:动态权限检查---->获取蓝牙适配器---->启用蓝牙---->查找设备---->配对与连接
流程大概就是这样,权限检查就不说了,应该都会,不会可以自己找找相关博客看下。
2. 首先打开蓝牙,打开蓝牙大概有两种方式
- 2.1 提示用户跳转到设置界面打开
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
- 2.2 不提示静默打开
if (mBluetoothAdapter.isEnabled ()){
mBluetoothAdapter.enable ();
}
- 2.3 查询已配对的蓝牙
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
- 2.4 扫描设备
/**
* 开始蓝牙扫描
*
* @return
*/
public boolean startScan() {
if (!isBlueEnable()) {
Log.e(TAG, "Bluetooth not enable!");
return false;
}
//当前是否在扫描,如果是就取消当前的扫描,重新扫描
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
//此方法是个异步操作,一般搜索12秒
return mBluetoothAdapter.startDiscovery();
}
注册广播,通过广播接收蓝牙信息,我这里是有一个回调接口
/**
* 注册广播
*/
public void registerReceiver() {
IntentFilter filter1=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);
IntentFilter filter2=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
IntentFilter filter3=new IntentFilter (BluetoothDevice.ACTION_FOUND);
registerReceiver (scanBlueReceiver, filter1);
registerReceiver (scanBlueReceiver, filter2);
registerReceiver (scanBlueReceiver, filter3);
}
public class ScanBlueReceiver extends BroadcastReceiver {
private static final String TAG = ScanBlueReceiver.class.getName();
private ScanBlueCallBack callBack;
public ScanBlueReceiver(ScanBlueCallBack callBack) {
this.callBack = callBack;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "action:" + action);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (action) {
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
Log.d(TAG, "开始扫描...");
callBack.onScanStarted();
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
Log.d(TAG, "结束扫描...");
callBack.onScanFinished();
break;
case BluetoothDevice.ACTION_FOUND:
Log.d(TAG, "发现设备...");
callBack.onScanning(device);
break;
}
}
}
2.5 蓝牙配对
首先需要用到 ClsUtils 类,这个网上都有,我就不贴出来了,感谢大神们的奉献。
蓝牙配对需要和目标设备建立连接,这里需要用到上文说的BluetoothSocket了
/**
* 蓝牙连接线程
*/
public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {
private static final String TAG = ConnectBlueTask.class.getName();
private BluetoothDevice bluetoothDevice;
private ConnectBlueCallBack callBack;
public ConnectBlueTask(ConnectBlueCallBack callBack){
this.callBack = callBack;
}
UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
@Override
protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
bluetoothDevice = bluetoothDevices[0];
Log.e (TAG, "doInBackground: "+bluetoothDevice.getAddress ());
BluetoothSocket socket = null;
try{
Log.d(TAG,"开始连接socket,uuid:" );
socket = bluetoothDevice.createRfcommSocketToServiceRecord(SERIAL_UUID);
if (socket != null && !socket.isConnected()){
socket.connect();
}
}catch (IOException e){
Log.e(TAG,"socket连接失败");
try {
socket =(BluetoothSocket) bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(bluetoothDevice,1);
socket.connect();
// socket.close();
} catch (IOException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace ();
} catch (InvocationTargetException e1) {
e1.printStackTrace ();
} catch (NoSuchMethodException e1) {
e1.printStackTrace ();
}
}
return socket;
}
@Override
protected void onPreExecute() {
Log.d(TAG,"开始连接");
if (callBack != null) callBack.onStartConnect();
}
@Override
protected void onPostExecute(BluetoothSocket bluetoothSocket) {
if (bluetoothSocket != null && bluetoothSocket.isConnected()){
Log.d(TAG,"连接成功");
if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
}else {
Log.d(TAG,"连接失败");
if (callBack != null) callBack.onConnectFail(bluetoothDevice, "连接失败");
}
}
}
同样需要注册相应广播,用来获取配对状态
public void pinRegisterReceiver() {
IntentFilter filter4=new IntentFilter (BluetoothDevice.ACTION_PAIRING_REQUEST);
IntentFilter filter5=new IntentFilter (BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver (pinBlueReceiver, filter4);
registerReceiver (pinBlueReceiver, filter5);
}
private String pin="0000"; // 此处为你要连接的蓝牙设备的初始密钥,一般为1234或0000
private static final String TAG=PinBlueReceiver.class.getName ();
private PinBlueCallBack callBack;
public PinBlueReceiver(PinBlueCallBack callBack) {
this.callBack=callBack;
}
@Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction ();
Log.d (TAG, "action:" + action);
BluetoothDevice device=intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals (action)) {
try {
callBack.onBondRequest ();
// 开始配对
boolean ret=ClsUtils.setPin (device.getClass (), device, pin);
abortBroadcast ();// 将广播终止,否则会出现一个一闪而过的配对框。
//Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});
//Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{pin.getBytes()});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace ();
}
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals (action)) {
switch (device.getBondState ()) {
case BluetoothDevice.BOND_NONE:
Log.d (TAG, "取消配对");
callBack.onBondFail (device);
break;
case BluetoothDevice.BOND_BONDING:
Log.d (TAG, "配对中");
callBack.onBonding (device);
break;
case BluetoothDevice.BOND_BONDED:
Log.d (TAG, "配对成功");
callBack.onBondSuccess (device);
break;
}
}
}
大概就是这样。。
参考:https://blog.csdn.net/zqf_888/article/details/81060606 这篇文章写得很好,建议观看。