android 8.1 蓝牙开发 静默开启蓝牙 将蓝牙暴露给其他蓝牙设备 扫描蓝牙设备 静默配对 建联相互通信
阿。 第一次接触蓝牙开发 还是一头雾水的 不过还好经过2天时间 调试好了蓝牙的基本功能 暴露设备 扫描 配对 连接 收发消息等等。。 嗯。。 这几天在网上搜了很多关于蓝牙的帖子 大部分 都是没有将重点问题 暴露出来 解析 和 解决 使我开发及其难受 开发中我就决定 自己解决好问题 要发一篇贴子 没错 再弄蓝牙的你看到这里是值得庆幸的 因为你找到了答案,哈哈(android 8.1 系统 默认14蓝牙版本) 当然在其他版本的问题也是有可能没遇到的,哈哈 不装逼了 开始公布答案
- 我长话短说哈,添加 蓝牙相关的权限,要启用蓝牙 是依赖这个定位权限的 一定要加上
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
这里重点说一下哈, 这个权限
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
是为了做静默配对,需要添加的,注意 这个权限普通第三方程序添加了也没有 必须要有系统权限才行
添加 android:sharedUserId=“android.uid.system” 用系统签名才行 当然如果说你不做静默配对 这个就不需要了
因为我是追求完美的人,所以我是必须要静默的 , O(∩_∩)O哈哈~
获取蓝牙适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
2.开启蓝牙 这里有两种方式 第一种
```java
/**
* 打开设备蓝牙
*
* @return
*/
public BluetoothClient openBluetooth() {
if (!hasBluetooth()) return mBluetoothClient;
if (!mBluetoothAdapter.isEnabled()) {
boolean enable = mBluetoothAdapter.enable();
if(enable)
Toast.makeText(mContext, "蓝牙打开成功", Toast.LENGTH_SHORT).show();
else
Toast.makeText(mContext, "蓝牙打开失败", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(mContext, "蓝牙已打开", Toast.LENGTH_SHORT).show();
}
return mBluetoothClient;
}
第二种方式。。
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,1);
第二种方式是有弹窗的 我是更喜欢第一种
3.蓝牙开启了 接下来就是扫描蓝牙设备了, 我一开始以为蓝牙开启后 就能被蓝牙设备发现, 后来发现这玩意tm 的还得暴露给别人
你穿着衣服别人看不见,你必须得脱掉才能看得见。明白了吗。emmm....
```java
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
startActivityForResult(discoverableIntent,0);
我这里是设置的暴露300秒, 这个数值应该是有个上限好像 我记得是3600,有点记不清了 没有细研究 因为这个问题不大,因为300 秒后我还可以在发起一次。
4扫描
// 开始搜索
mBluetoothAdapter.startDiscovery();
方法执行后扫描到设备将以广播形式,接收所以需要注册广播
/**
* 注册接受搜索到的蓝牙设备广播
*/
public void regiestReceiver() {
mBluetoothReceiver = new BluetoothReceiver();
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mBluetoothReceiver, intentFilter);
}
/**
* 搜索设备和配对状态改变广播
*/
class BluetoothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND == action) { // 找到设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Message message = Message.obtain();
message.what = MSG_WHAT_FOUND_DEVICE;
message.obj = device;
mHandler.sendMessage(message);
Toast.makeText(mContext, "找到设备" + device.getName(), Toast.LENGTH_SHORT).show();
try{
if(device.getName().contains("ZL809") || device.getName().contains("zzy-edu-m1")) // 这里是做了蓝牙名称匹配(静默匹配)
{
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
try {
device.createBond();// 发起匹配(静默匹配)
} catch (Exception e) {
e.printStackTrace();
}
}
}
}catch (Exception e){
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED == action) {
mHandler.sendEmptyMessage(MSG_WHAT_FINISHED_SEARCH);
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED == action) {
int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
switch (state) {
case BluetoothDevice.BOND_NONE:
mHandler.sendEmptyMessage(MSG_WHAT_BOND_NONE);
Logger.d("BOND_NONE 删除配对");
break;
case BluetoothDevice.BOND_BONDING:
mHandler.sendEmptyMessage(MSG_WHAT_BOND_BONDING);
Logger.d("BOND_BONDING 正在配对");
break;
case BluetoothDevice.BOND_BONDED:
mHandler.sendEmptyMessage(MSG_WHAT_BOND_BONDED);
Logger.d("BOND_BONDED 配对成功");
break;
}
}else if(action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)){
try{
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getName().contains("ZL809") || device.getName().contains("zzy-edu-m1"))
{
abortBroadcast();//拦截广播,为了阻止弹窗
int pin = intent.getIntExtra("android.bluetooth.device.extra.PAIRING_KEY", 1234);
device.setPin((""+pin).getBytes());
device.setPairingConfirmation(true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
代码中根据扫描到的设备名称进行匹配自己想要连接的设备,进行静默配对 不做静默的可以去掉 手动确认匹配也是ok的
5 连接通信 完成前面的工作 通信就简单了
两个蓝牙设备通信,即 服务端,客户端 这里注意 一方发起连接请求之前另一方要先开启服务等待连接请求 这里和socket开发很像 几乎就是socket开发了
服务端
mBluetoothServerSocket= mBluetoothAdapter.listenUsingRfcommWithServiceRecord(
Constants.NAME_SECURE, Constants.MY_UUID_SECURE);
bluetoothSocket = mBluetoothServerSocket.accept();
等待客户端接入,当有蓝牙连接后 通过输入输出流 交互数据
@Override
public void onAccept(BluetoothSocket bluetoothSocket) {
try {
InputStream inputStream = bluetoothSocket.getInputStream();
outputStream = bluetoothSocket.getOutputStream();
while (true) {
byte[] bytes = new byte[1024];
inputStream.read(bytes);
String s = new String(bytes, 0, bytes.length);
chatContent.add("B" + s);
handler.sendEmptyMessage(MSG_UPDATE_UI);
}
} catch (IOException e) {
e.printStackTrace();
}
}
客户端
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(Constants.MY_UUID_SECURE);
if (!mBluetoothSocket.isConnected())
mBluetoothSocket.connect();
要注意连接过程要在子线程
/**
* 读取和发送的线程
*/
class ReadWriteThread extends Thread {
OutputStream outputStream;
InputStream inputStream;
public ReadWriteThread(BluetoothSocket bluetoothSocket) {
try {
this.outputStream = bluetoothSocket.getOutputStream();
this.inputStream = bluetoothSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
if (inputStream != null) {
while (true) {
try {
byte[] bytes = new byte[1024];
inputStream.read(bytes);
chatContent.add("B" + new String(bytes, 0, bytes.length));
handler.sendEmptyMessage(MSG_UPDATE_UI);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void sendMessage(String message) {
if (outputStream != null) {
try {
outputStream.write(message.getBytes());
chatContent.add("A" + message);
handler.sendEmptyMessage(MSG_UPDATE_UI);
handler.sendEmptyMessage(MSG_CLEAR_EDITTEXT);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
后续更新个demo 吧 等几天哈
2023-06-30 更新
抱歉让我给忘记了 今天更新一下demo
class BluetoothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND == action) { // 找到设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Message message = Message.obtain();
message.what = MSG_WHAT_FOUND_DEVICE;
message.obj = device;
mHandler.sendMessage(message);
Toast.makeText(mContext, "找到设备" + device.getName(), Toast.LENGTH_SHORT).show();
try{
if(device.getName().contains("ZL809") || device.getName().contains("zzy-edu-m1"))
{
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
try {
device.createBond();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}catch (Exception e){
}
}
需要注意调试时要换成自己的设备名称或者将过滤条件注释掉 (ZL809,zzy-edu-m1)
if(device.getName().contains(“ZL809”) || device.getName().contains(“zzy-edu-m1”))