前:本文为QiaoJim原创,转载请附原文链接,谢谢合作!
http://blog.csdn.net/qiao_jim/article/details/73008695
----------------------------------------------------------------------------------
最近学习了android传统蓝牙,自己整理了一下思路,然后写了一个BluetoothStudy小测试程序,来运用所理解的android传统蓝牙开发技术,写下
一些心得和思路,供其他android热爱者参考,也方便日后回顾。
博客如有错误之处,欢迎留言之处,十分感谢。博客最后会附上源码,可下载借鉴。
一、整体思路和对应相关方法
1、获得BluetoothAdapter:BluetoothAdapter.getDefaultAdapter();
2、打开蓝牙:询问用户打开(推荐)或直接bluetoothAdapter.enable();
3、查询已绑定设备,发现新设备:bluetoothAdapter.getBondedDevices();bluetoothAdapter.startDiscovery();
4.1、服务端,一直监听请求,当该端主动发出请求时,关闭该端的监听,角色转为客户端:
bluetoothDevice.createRfcommSocketToServiceRecord(UUID);
4.2、客户端,点击目标设备,配对连接:
bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID);
5、通过BluetoothSocket通信:IO流读写
二、开发详解
1、声明权限,注意可能需要的运行时权限
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
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;
}
}
}
private void showBondDevice() {
deviceList.clear();
// 所有已绑定设备,一个Set集合
Set<BluetoothDevice> tmp = bluetoothAdapter.getBondedDevices();
for (BluetoothDevice d : tmp) {
deviceList.add(d);
}
//更新列表
listAdapter.notifyDataSetChanged();
}
4、发现蓝牙设备,发现一个设备,会发送一条ACTION_FOUND广播,注册广播接收器,可获得对应蓝牙设备信息
bluetoothAdapter.startDiscovery();
intentFilter = new IntentFilter();
btReceiver = new MyBtReceiver();
//监听 搜索开始,搜索结束,发现新设备 3条广播
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
getActivity().registerReceiver(btReceiver, intentFilter);
//广播接收器
private class MyBtReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
toast("开始搜索 ...");
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
toast("搜索结束");
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//获得发现的设备
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
deviceList.add(device);
listAdapter.notifyDataSetChanged();
}
}
}
}
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();
(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()
三、源码示例下载
附上源码github地址,有帮助的话别忘了加 ★ 噢。
https://github.com/QiaoJim/BluetoothStudy
感谢阅读,如有错误,请留言。如果觉得博文不错,请点赞支持。
四、效果图