android 普通蓝牙源码解读
2015-11-23 21:08
573 查看
一:概述
上一篇博客讲了下蓝牙4.0在android中的应用,这里讲讲普通蓝牙之间如何操作。我记得在大二的时候还做了个比较烂的游戏,当时喜欢打dota就做了个蓝牙之间对战坦克的游戏,可以去看看,确实挺烂,到现在我都没想明白两个设备之间如何保持数据实时同步的(蓝牙传输是有延迟的),我去下载了其他的蓝牙对战的游戏,别人做的很好。所以就更加郁闷了。(希望大神不吝赐教 )
蓝牙对战游戏
相对蓝牙4.0,我觉得这个普通蓝牙应该要容易许多,因为没有什么协议的,就只用两个socket中交换数据就行了。
二:源码解读
权限申明:[code]<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.BLUETOOTH"/>
在对蓝牙进行操作之前都需要获取BluetoothAdapter
[code] mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
当然如果获取不到,那么就不跟你玩了。直接finish(),哼。
[code] if (mBluetoothAdapter == null) { finish(); }
获取到了,就在判断蓝牙是否开启。如果没有开启,就请求用户是否开启。
[code]if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); }
然后在onActivityResult()中获取用户的操作(开启还是不想开启蓝牙),当然如果不开启蓝牙,那自然也没什么后话,finish()吧。
[code] 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自然就是服务端。可是在连接前都不知道自己该扮演什么角色。所以这个时候双方都需要开启线程进行监听。
[code] if (mSecureAcceptThread == null) { mSecureAcceptThread = new AcceptThread(true); mSecureAcceptThread.start(); } if (mInsecureAcceptThread == null) { mInsecureAcceptThread = new AcceptThread(false); mInsecureAcceptThread.start(); }
这里的线程是个阻塞线程()。当客户端的socket()主动连接的时候就会返回一个连接好的socket。
[code] socket = mmServerSocket.accept();
但是上面为什么同时开启了两个AcceptThread线程呢?
仔细一看:
[code] if (secure) { tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,MY_UUID_SECURE); } else { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME_INSECURE, MY_UUID_INSECURE); }
好像一个叫安全,一个叫不安全。进去一看,其实调用的同一个方法,只是传入的参数不同而已。
[code]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)); }
[code]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)); }
就是一个进行了加密验证,另一个没有进行加密验证。在使用上我没觉得有什么区别。
好了这些初始话工作做的差不多了。需要找个设备开始连接了。使用过蓝牙的都知道,已经连接过的设备不需要再重新搜索了。没有配对过的就需要重新搜索。
我们先说已经配对过的蓝牙。使用下列代码就可以获得已经配对过的蓝牙。
[code] // Get a set of currently paired devices Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); //使用这个方式就可以遍历出来 for (BluetoothDevice device : pairedDevices) { pairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); }
好了如果其中有你想连接的蓝牙,那么就可以连接了。(连接蓝牙部分)
[code]if (secure) { socket = device.createRfcommSocketToServiceRecord(MY_UUID_SECURE); } else { socket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE); }
使用上面的就可以进行连接了。客户端和服务端的uuid必须时一样的,因为服务端同时有两个阻塞线程在监听,所以使用其中任何一个去连接都没什么问题。
好了,现在来讲下查找设备。查找设备肯定时一方查找,一方被查找。
先让设备设置为可以被查找。其中的300就是设置可以被查找的时间。但是如果其中时间小于0,或者大于3600将自动设置为120秒
[code]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); }
但是我在哪里去获得他找到的设备呢(自问自答好傻=_+),在广播里啊。这个代码应该比较清楚。需要注意的是注册和注销广播哦。
[code] 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连接之后,传数据就比较容易了。创建输入,输出流。
[code] tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream();
使用输入流读取数据。
[code] // Read from the InputStream bytes = mmInStream.read(buffer);
使用输出流写数据就ok了。
[code] mmOutStream.write(buffer);
源码下载(copy谷歌的)
加个好友共同学习(不是公众号):
因为小弟水平有限,如果有写的有问题,希望指出。(欢迎留言)
相关文章推荐
- WebView 中的 JavaScript 调用 Android 的方法
- greenDao---orm框架
- Android自定义控件之仿京东商城下拉刷新
- Android开发:关于在启动页面就会报相机异常等类似问题
- Android之Adapter
- 实现Android中TextView的跑马灯效果
- 【FastDev4Android框架开发】CardView完全解析与RecyclerView结合使用(三十二)
- 2015年最新Android基础入门教程目录(完结版)
- Android简单的View注入
- Android Matrix
- Android Studio中Spinner控件的数据绑定实现
- android做客户端连接web服务器
- Android中Json数据的生成与解析
- Android打开隐藏的应用
- 收藏的Android自定义控件
- Android 学习资源分享:官方示例Support-V7 Demos
- Android初步 简单demo
- Android中的DrawRect()参数解析
- 如何修改mtk android 默认拍照size
- Android——广播