一:概述
上一篇博客讲了下蓝牙4.0在android中的应用,这里讲讲普通蓝牙之间如何操作。
我记得在大二的时候还做了个比较烂的游戏,当时喜欢打dota就做了个蓝牙之间对战坦克的游戏,可以去看看,确实挺烂,到现在我都没想明白两个设备之间如何保持数据实时同步的(蓝牙传输是有延迟的),我去下载了其他的蓝牙对战的游戏,别人做的很好。所以就更加郁闷了。(希望大神不吝赐教 )
相对蓝牙4.0,我觉得这个普通蓝牙应该要容易许多,因为没有什么协议的,就只用两个socket中交换数据就行了。
二:源码解读
权限申明:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
在对蓝牙进行操作之前都需要获取BluetoothAdapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
当然如果获取不到,那么就不跟你玩了。直接finish(),哼。
if (mBluetoothAdapter == null) {
finish();
}
获取到了,就在判断蓝牙是否开启。如果没有开启,就请求用户是否开启。
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
然后在onActivityResult()中获取用户的操作(开启还是不想开启蓝牙),当然如果不开启蓝牙,那自然也没什么后话,finish()吧。
if (resultCode == Activity.RESULT_OK) {
//开启了蓝牙
setupChat();
} else {
Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving,Toast.LENGTH_SHORT).show();
getActivity().finish();
}
如果开启了蓝牙,后续就开始一些初始化工作。
这里初始化需要说点东西:
因为蓝牙需要两台设备其中一台做为服务端(server)另一台做为客户端(client),我们比如两台设备分别时A 和 B ,A如果主动去连接B ,那么A就时客户端,B自然就是服务端。可是在连接前都不知道自己该扮演什么角色。所以这个时候双方都需要开启线程进行监听。
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(true);
mSecureAcceptThread.start();
}
if (mInsecureAcceptThread == null) {
mInsecureAcceptThread = new AcceptThread(false);
mInsecureAcceptThread.start();
}
这里的线程是个阻塞线程()。当客户端的socket()主动连接的时候就会返回一个连接好的socket。
socket = mmServerSocket.accept();
但是上面为什么同时开启了两个AcceptThread线程呢?
仔细一看:
if (secure) {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE);
} else {
tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, MY_UUID_INSECURE);
}
好像一个叫安全,一个叫不安全。进去一看,其实调用的同一个方法,只是传入的参数不同而已。
public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
if (isBluetoothEnabled() == false) {
throw new IOException();
}
return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
new ParcelUuid(uuid));
}
public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
if (isBluetoothEnabled() == false) {
throw new IOException();
}
return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
new ParcelUuid(uuid));
}
就是一个进行了加密验证,另一个没有进行加密验证。在使用上我没觉得有什么区别。
好了这些初始话工作做的差不多了。需要找个设备开始连接了。使用过蓝牙的都知道,已经连接过的设备不需要再重新搜索了。没有配对过的就需要重新搜索。
我们先说已经配对过的蓝牙。使用下列代码就可以获得已经配对过的蓝牙。
// Get a set of currently paired devices
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
//使用这个方式就可以遍历出来
for (BluetoothDevice device : pairedDevices) {
pairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
好了如果其中有你想连接的蓝牙,那么就可以连接了。(连接蓝牙部分)
if (secure) {
socket = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
} else {
socket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE);
}
使用上面的就可以进行连接了。客户端和服务端的uuid必须时一样的,因为服务端同时有两个阻塞线程在监听,所以使用其中任何一个去连接都没什么问题。
好了,现在来讲下查找设备。查找设备肯定时一方查找,一方被查找。
先让设备设置为可以被查找。其中的300就是设置可以被查找的时间。但是如果其中时间小于0,或者大于3600将自动设置为120秒
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
但是我在哪里去获得他找到的设备呢(自问自答好傻=_+),在广播里啊。这个代码应该比较清楚。需要注意的是注册和注销广播哦。
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// When discovery is finished, change the Activity title
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
找到后就开始连接吧。连接方法同上(就是用device.create…..那里)。
蓝牙连接好了,那么就要开始传数据啦。有连个socket连接之后,传数据就比较容易了。创建输入,输出流。
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
使用输入流读取数据。
// Read from the InputStream
bytes = mmInStream.read(buffer);
使用输出流写数据就ok了。
mmOutStream.write(buffer);
加个好友共同学习(不是公众号):
因为小弟水平有限,如果有写的有问题,希望指出。(欢迎留言)