前言
这两天在开发一个android版的手机蓝牙通信的的APP,对android的蓝牙机进行了一个简单的研究
android上的蓝牙分为两种经典蓝牙(BR/EDR)和低功耗蓝牙(BLE)
因为我开发的是经典蓝牙开发的这里就简单讲下如何开发
开发前建议大家先去看下谷歌官方的蓝牙说明
https://developer.android.google.cn/guide/topics/connectivity/bluetooth
经典蓝牙
第一步 申请权限
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- 仅在支持BLE(即蓝牙4.0)的设备上运行 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 如果Android 6.0蓝牙搜索不到设备,需要补充下面两个权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <!-- 网络权限 -->
大概要申请这么多权限
这里发起前要注意下,android 9以后,关键性权限需要用户第二次确认才能调用,所以这个发起收拾肯定是写在权限回调里面的
//申请用户权限
ActivityCompat.requestPermissions(MainActivity.this, mPermissionListnew, mOpenCode);
第二歩 发起搜索
获取当前蓝牙管理器
mBluetooth = BluetoothAdapter.getDefaultAdapter();
判断当前蓝牙是否启动
//蓝牙服务未启动
if (!mBluetooth.isEnabled()) {
boolean enable = mBluetooth.enable();
if (!enable) {
SystemExit(getString(R.string.initBluetooth));
return;
}
}
下面是完整代码
// 权限回调
@Override
@SuppressLint("MissingPermission")
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//判断权限是否同意 这里要注意下,每个安卓版本的权限是不一样的
for (Integer permission : grantResults) {
if (permission != 0) {
SystemExit(getString(R.string.run));
return;
}
}
//从系统服务中获取蓝牙管理器
//这里虽然写了很多,但是BluetoothAdapter.getDefaultAdapter() 这个就可以的
if (mBluetooth == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//从系统服务中获取蓝牙管理器
BluetoothManager bm = getSystemService(BluetoothManager.class);
mBluetooth = bm.getAdapter();
} else {
//获取系统默认的蓝牙适配器
mBluetooth = BluetoothAdapter.getDefaultAdapter();
}
if (mBluetooth == null) {
SystemExit("没有蓝牙功能");
return;
}
}
//蓝牙服务未启动
if (!mBluetooth.isEnabled()) {
boolean enable = mBluetooth.enable();
if (!enable) {
SystemExit(getString(R.string.initBluetooth));
return;
}
}
if (requestCode == mOpenCode) {
//初始化蓝牙
initBluetooth();
}
}
上面写了那么多其实本质上还是在申请权限那一批里面
下面开始进行蓝牙扫描
也就是上面initBluetooth()方法
开启蓝牙扫描
开启蓝牙扫很简单调用下startDiscovery()方法就行
@SuppressLint("MissingPermission")
private void beginDiscovery() {
if (mBluetooth != null && !mBluetooth.isDiscovering()) {
mBluetooth.startDiscovery();//开始扫描周围的蓝牙设备
}
}
获取蓝牙扫描的返回数据
获取蓝牙扫描数据,就要先注册广播,通过广播回调进行获取数据
//需要过滤多个动作,则调用IntentFilter对象的addAction添加新动作
IntentFilter discoveryFilter = new IntentFilter();
//获取新的数据
discoveryFilter.addAction(BluetoothDevice.ACTION_FOUND);
//连接上了
discoveryFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
//状态改变
discoveryFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//蓝牙连接状态更改
discoveryFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
//蓝牙即将断开
discoveryFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
//注册蓝牙设备搜索的广播接收器 discoveryReceiver()这个是回调函数
registerReceiver(discoveryReceiver, discoveryFilter);
回调方法
@SuppressLint("MissingPermission")
public final BroadcastReceiver discoveryReceiver = new BroadcastReceiver() {
@RequiresApi(api = Build.VERSION_CODES.R)
@SuppressLint("NotifyDataSetChanged")
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int bondState = device.getBondState();
Fruit fruit = new Fruit();
fruit.setAddress(device.getAddress());
//发现新的蓝牙设备
fruit.setName(device.getName());
if (fruit.getName() == null || fruit.getName().length() == 0) {
fruit.setName("N/A");
}
fruit.setState(bondState);
fruit.setBluetoothType(device.getType());
short rssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);
fruit.setRssi(rssi + "");
fruit.setBluetoothDevice(device);
onActivityDataChangedListener.addFruitData(fruit);
switch (action) {
case BluetoothDevice.ACTION_FOUND:
break;
//蓝牙状态修改
//断开蓝牙连接
case BluetoothDevice.ACTION_ACL_DISCONNECTED:
case BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED:
BluetoothServiceConnect remove = StaticObject.bluetoothSocketMap.remove(device.getAddress());
if (remove != null) {
ToastUtil.toastWord(MainActivity.this, MainActivity.this.getString(ConnectTheInterrupt));
remove.close();
Msg m = new Msg(device.getAddress());
m.setStateType(1);
try {
StaticObject.mTaskQueue.put(m);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//蓝牙状态修改
case BluetoothDevice.ACTION_ACL_CONNECTED:
case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
/* fruit.setState(bondState);
short rssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);
fruit.setRssi(rssi + "");
onActivityDataChangedListener.addFruitData(fruit);*/
//adapter.notifyDataSetChanged();
break;
}
}
};
另外说下 通过**getBondedDevices()**这个方法可以获取已经配对了蓝牙信息
Set<BluetoothDevice> bondedDevices = mBluetooth.getBondedDevices();
if (bondedDevices != null && bondedDevices.size() != 0) {
for (BluetoothDevice device : bondedDevices) {
Fruit fruit = new Fruit();
fruit.setAddress(device.getAddress());
fruit.setName(device.getName());
fruit.setState(device.getBondState());
fruit.setBluetoothType(device.getType());
fruit.setBluetoothDevice(device);
onActivityDataChangedListener.addFruitData(fruit);
}
}
连接蓝牙
上面已经获取了蓝牙驱动,接下来就是连接蓝牙了,这一步比较简单
通过方法回调获取BluetoothDevice 对象,调用createInsecureRfcommSocketToServiceRecord()这个方法,传入uuid来获取socker连接
uuid说明https://zhangzhenfei.cn/archives/guan-yu-andrion-an-zhuo--lan-ya-lian-jie
static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
BluetoothSocket insecureRfcommSocketToServiceRecord= bluetoothDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID));
insecureRfcommSocketToServiceRecord.connect();
//然后这里就获取到输入流和输出流,接下来就可以进行交互了
insecureRfcommSocketToServiceRecord.getOutputStream()
insecureRfcommSocketToServiceRecord.getInputStream()
评论区