最近在开发蓝牙,由于是使用的模块开发,但是andriod的系统的经典蓝牙也需要熟悉和知道。在这个背景下,参考了网络上的一些资料,完善了demo,方便了后来者能初步运用相关的蓝牙。站在巨人的肩旁上,才能走的更远。
一、整体思路和对应相关方法
1、获得BluetoothAdapter:BluetoothAdapter.getDefaultAdapter();
2、打开蓝牙:询问用户打开(推荐)或直接bluetoothAdapter.enable();
3、查询已绑定设备,发现新设备:bluetoothAdapter.getBondedDevices();bluetoothAdapter.startDiscovery();
4、配对相关的设备,自定配对相关的类,配对设置pin值配对蓝牙设备。 ClsUtils.createBond(btDevice.getClass(), btDevice);
5.1、服务端,一直监听请求,当该端主动发出请求时,关闭该端的监听,角色转为客户端:
bluetoothDevice.createRfcommSocketToServiceRecord(UUID);
45.2、客户端,点击目标设备,配对连接:
bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID);
6、通过BluetoothSocket通信:IO流读写
二、开发详解
1、声明权限,注意可能需要的运行时权限
android 6.0以上设备发现新蓝牙时,需加入运行时权限,否则无法监听ACTION_FOUND广播
if (Build.VERSION.SDK_INT >= 6.0) {
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
Params.MY_PERMISSION_REQUEST_CONSTANT);
}
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults) {
switch (requestCode) {
case Params.MY_PERMISSION_REQUEST_CONSTANT: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 运行时权限已授权
}
return;
}
}
}
2、打开蓝牙,推荐用对话框形式让用户打开
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 蓝牙未打开,询问打开
if (!bluetoothAdapter.isEnabled()) {
Intent turnOnBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOnBtIntent, Params.REQUEST_ENABLE_BT);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Params.REQUEST_ENABLE_BT: {
//用户打开蓝牙
if (resultCode == RESULT_OK) {
//显示已绑定蓝牙设备
showBondDevice();
}
break;
}
case Params.REQUEST_ENABLE_VISIBILITY: {
//设置该蓝牙设备可被其他设备发现,600是设置的设备可发现时间(博客最后有简单说明)
if (resultCode == 600) {
toast("蓝牙已设置可见");
} else if (resultCode == RESULT_CANCELED) {
toast("蓝牙设置可见失败,请重试");
}
break;
}
}
}
3、通过BluetoothAdapter获取已绑定的蓝牙设备
private void showBondDevice() {
deviceList.clear();
// 所有已绑定设备,一个Set集合
Set
for (BluetoothDevice d : tmp) {
deviceList.add(d);
}
//更新列表
listAdapter.notifyDataSetChanged();
}
4、发现蓝牙设备,发现一个设备,会发送一条ACTION_FOUND广播,注册广播接收器,可获得对应蓝牙设备信息。接收者添加PAIRING_REQUEST的广播接收,从而可以处理相关的配对情况。
private class MyBtReceiver extends BroadcastReceiver {
MakePariBlueToothListener mMakePariListener;
public void SetPairlistener(MakePariBlueToothListener makePariBlueToothListener) {
this.mMakePariListener = makePariBlueToothListener;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice btDevice = null; //创建一个蓝牙device对象
// 从Intent中获取设备对象
btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
mtoast.toast("开始搜索 ...");
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
mtoast.toast("搜索结束");
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (isNewDevice(device)) {
deviceList.add(device);
listAdapter.notifyDataSetChanged();
Log.e(TAG, "---------------- " + device.getName());
}
} else if (ACTIONFILTER.equals(action)) {
Log.e("action2=", action);
Log.e("here", "btDevice.getName()");
try {
//1.确认配对
ClsUtils.setPairingConfirmation(btDevice.getClass(), btDevice, true);
//2.终止有序广播
Log.i("order...", "isOrderedBroadcast:" + isOrderedBroadcast() + ",isInitialStickyBroadcast:" + isInitialStickyBroadcast());
abortBroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。
//3.调用setPin方法进行配对...
boolean ret = ClsUtils.setPin(btDevice.getClass(), btDevice, pin);
} catch (Exception e) {
e.printStackTrace();
}
} else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
switch (btDevice.getBondState()) {
case BluetoothDevice.BOND_BONDING:// 正在配对
mMakePariListener.whilePari(btDevice);
break;
case BluetoothDevice.BOND_BONDED:// 配对结束
mMakePariListener.pairingSuccess(btDevice);
break;
case BluetoothDevice.BOND_NONE:// 取消配对/未配对
mMakePariListener.cancelPari(btDevice);
default:
break;
}
}
}
}
5、设备连接,服务器端开启线程一直等待连接,客户端点击某个目标设备,关闭服务器线程监听,并开启线程,发出连接请求。
注意:客户端连接前,一定cancelDiscovery()
// 蓝牙已开启
if (bluetoothAdapter.isEnabled()) {
showBondDevice();
// 默认开启服务线程监听
if (serverThread != null) {
serverThread.cancel();
}
serverThread = new ServerThread(bluetoothAdapter, uiHandler);
new Thread(serverThread).start();
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
// 关闭服务器监听
if (serverThread != null) {
serverThread.cancel();
serverThread=null;
}
BluetoothDevice device = deviceList.get(position);
// 开启客户端线程,连接点击的远程设备
clientThread = new ClientThread(bluetoothAdapter, device, uiHandler);
new Thread(clientThread).start();
// 通知 ui 连接的服务器端设备
Message message = new Message();
message.what = Params.MSG_CONNECT_TO_SERVER;
message.obj = device;
uiHandler.sendMessage(message);
}
});
6、建立BluetoothSocket连接以后,使用IO流数据传输,服务器和客户端读写数据类似,贴一部分代码供参考
public void writeData(String dataSend) {
if (serverThread != null) {
serverThread.write(dataSend);
} else if (clientThread != null) {
clientThread.write(dataSend);
}
}
//写数据
public void write(String data){
try {
out.write(data.getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
new Thread(new Runnable() {
@Override
public void run() {
byte[] buffer = new byte[1024];
int len;
String content;
try {
//读数据
while ((len=in.read(buffer)) != -1) {
content=new String(buffer, 0, len);
Message message = new Message();
message.what = Params.MSG_CLIENT_REV_NEW;
message.obj = content;
//更新 ui
uiHandler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
7、其他说明
(1)新设备绑定,也可以使用bluetoothDevice.createBond()
(2)设置设备可被发现的时间:
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
enableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);
startActivityForResult(enableIntent, Params.REQUEST_ENABLE_VISIBILITY);
(3)服务器获得远端设备,bluetoothSocket.getRemoteDevice()
(4)通过MAC获得蓝牙设备,bluetoothAdapter.getRemoteDevice(String address)
(5)关闭蓝牙,bluetoothAdapter.disable()()
(6)使用相关的连接结果Toast提示。
(7)使用了Rxbinding的防止重复点击。
三、源码示例下载
相关Demo 下载地址:https://github.com/tangrunfa/BluetoothStudy
四、效果图
本文在原文上修改,原文地址:https://blog.csdn.net/qiao_jim/article/details/73008695