android 蓝牙搜索、配对连接通信总结
2016-08-12 14:26
501 查看
蓝牙协议可以实现一个蓝牙设备和6到8个蓝牙设备进行通信。
1、蓝牙搜索的实现
利用蓝牙的发现和完成动作动态注册广播接受者获得蓝牙设备。
第一步,获得蓝牙适配器
第二步动态注册蓝牙搜索广播接收者
并且可以利用意图过滤器设置广播的优先级
对应的广播接收者:
或者利用发现和完成动作定义两个广播接受者,在完成的动作中注销广播接收者。
关键代码如下:
这样便完成蓝牙的搜索了。
2、蓝牙配对
蓝牙要想通信目前是必须要先配对才能连接的。
蓝牙配对的api是hide的。但是api19可以直接调用蓝牙设备的配对方法。
所以配对都是利用反射的方法。这里有一个强大的工具类可以直接拿来使用,如下:
蓝牙配对的关键代码:
其中device是蓝牙设备。在配对的时候会有一个配对广播,可以自定义一个广播接受者获取配对广播,然后在这个广播接收者里设置pin值,取消确定对话框,实现自动配对。关键代码如下:
在我的4.2系统上是没有效果的。找了一个上午的资料;网上给出了两种解决方法:(1)修改setting 系统源码,(2)模拟点击事件。
蓝牙配对完成后就可以连接通信了。
3、蓝牙通信
蓝牙同时的本质是蓝牙套接字,一个主动发起连接的的设备做客户端,一个监听连接的设备做服务端,类似sokcet网络编程,利用多线程,读取数据流就可完成蓝牙通信。
如下是蓝牙串口通信的关键代码:
如下蓝牙服务端关键代码:
转自:http://www.2cto.com/kf/201502/374785.html
1、蓝牙搜索的实现
利用蓝牙的发现和完成动作动态注册广播接受者获得蓝牙设备。
第一步,获得蓝牙适配器
BluetoothAdapter mBtAdapter= BluetoothAdapter.getDefaultAdapter(); // 判断蓝牙是否打开 if (!mAdapter.isEnabled()) { mAdapter.enable(); }
第二步动态注册蓝牙搜索广播接收者
// Register for broadcasts when a device is discovered IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(mReceiver, filter); // Register for broadcasts when discovery has finished filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter);
并且可以利用意图过滤器设置广播的优先级
filter.setPriority(Integer.MAX_VALUE);
对应的广播接收者:
// The BroadcastReceiver that listens for discovered devices and // changes the title when discovery is finished 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)) { setProgressBarIndeterminateVisibility(false); setTitle(R.string.select_device); if (mNewDevicesArrayAdapter.getCount() == 0) { String noDevices = getResources().getText(R.string.none_found).toString(); mNewDevicesArrayAdapter.add(noDevices); } } } };
或者利用发现和完成动作定义两个广播接受者,在完成的动作中注销广播接收者。
关键代码如下:
/** * 接收器 当搜索蓝牙设备完成时调用 */ private BroadcastReceiver _foundReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 将结果添加到列表中 _devices.add(device); DeviceInfo info = new DeviceInfo(); info.setmDeviceName(device.getName()); info.setmDeviceMacAddr(device.getAddress()); infos.add(info); info = null; // 显示列表 showDevices(); } }; private BroadcastReceiver _discoveryReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 卸载注册的接收器 unregisterReceiver(_foundReceiver); unregisterReceiver(this); _discoveryFinished = true; } };
这样便完成蓝牙的搜索了。
2、蓝牙配对
蓝牙要想通信目前是必须要先配对才能连接的。
蓝牙配对的api是hide的。但是api19可以直接调用蓝牙设备的配对方法。
所以配对都是利用反射的方法。这里有一个强大的工具类可以直接拿来使用,如下:
public class ClsUtils { public ClsUtils() { // TODO Auto-generated constructor stub } /** * 与设备配对 参考源码:platform/packages/apps/Settings.git * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java */ static public boolean createBond(Class btClass, BluetoothDevice btDevice) throws Exception { Method createBondMethod = btClass.getMethod("createBond"); Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice); return returnValue.booleanValue(); } /** * 与设备解除配对 参考源码:platform/packages/apps/Settings.git * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java */ static public boolean removeBond(Class btClass, BluetoothDevice btDevice) throws Exception { Method removeBondMethod = btClass.getMethod("removeBond"); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice); return returnValue.booleanValue(); } static public boolean setPin(Class btClass, BluetoothDevice btDevice, String str) throws Exception { try { Method removeBondMethod = btClass.getDeclaredMethod("setPin", new Class[] {byte[].class}); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[] {str.getBytes()}); Log.e("returnValue设置密码", "" + returnValue.booleanValue()); return returnValue.booleanValue(); } catch (SecurityException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } // 取消用户输入 static public boolean cancelPairingUserInput(Class btClass, BluetoothDevice device) throws Exception { Method createBondMethod = btClass.getMethod("cancelPairingUserInput"); cancelBondProcess(btClass,device) ; Boolean returnValue = (Boolean) createBondMethod.invoke(device); Log.i("取消对话框","cancelPairingUserInput"+returnValue.booleanValue()); return returnValue.booleanValue(); } // 取消配对 static public boolean cancelBondProcess(Class btClass, BluetoothDevice device) throws Exception { Method createBondMethod = btClass.getMethod("cancelBondProcess"); Boolean returnValue = (Boolean) createBondMethod.invoke(device); return returnValue.booleanValue(); } /** * * @param clsShow */ static public void printAllInform(Class clsShow) { try { // 取得所有方法 Method[] hideMethod = clsShow.getMethods(); int i = 0; for (; i < hideMethod.length; i++) { Log.e("method name", hideMethod[i].getName() + ";and the i is:" + i); } // 取得所有常量 Field[] allFields = clsShow.getFields(); for (i = 0; i < allFields.length; i++) { Log.e("Field name", allFields[i].getName()); } } catch (SecurityException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) { // throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } static public boolean pair(String strAddr, String strPsw) { boolean result = false; BluetoothAdapter bluetoothAdapter = BluetoothAdapter .getDefaultAdapter(); bluetoothAdapter.cancelDiscovery(); if (!bluetoothAdapter.isEnabled()) { bluetoothAdapter.enable(); } BluetoothDevice device = bluetoothAdapter.getRemoteDevice(strAddr); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { try { Log.d("mylog", "NOT BOND_BONDED"); boolean flag1=ClsUtils.setPin(device.getClass(), device, strPsw); // 手机和蓝牙采集器配对 boolean flag2=ClsUtils.createBond(device.getClass(), device); // remoteDevice = device; // 配对完毕就把这个设备对象传给全局的remoteDevice result = true; } catch (Exception e) { // TODO Auto-generated catch block Log.d("mylog", "setPiN failed!"); e.printStackTrace(); } // } else { Log.d("mylog", "HAS BOND_BONDED"); try { ClsUtils.removeBond(device.getClass(), device); //ClsUtils.createBond(device.getClass(), device); boolean flag1= ClsUtils.setPin(device.getClass(), device, strPsw); // 手机和蓝牙采集器配对 boolean flag2=ClsUtils.createBond(device.getClass(), device); // remoteDevice = device; // 如果绑定成功,就直接把这个设备对象传给全局的remoteDevice result = true; } catch (Exception e) { // TODO Auto-generated catch block Log.d("mylog", "setPiN failed!"); e.printStackTrace(); } } return result; } }
蓝牙配对的关键代码:
flag3= ClsUtils.createBond(device.getClass(), device);
其中device是蓝牙设备。在配对的时候会有一个配对广播,可以自定义一个广播接受者获取配对广播,然后在这个广播接收者里设置pin值,取消确定对话框,实现自动配对。关键代码如下:
mReceiver=new ParingReceiver(device); IntentFilter filter=new IntentFilter(); filter.addAction( BluetoothDevice.ACTION_PAIRING_REQUEST); filter.setPriority(Integer.MAX_VALUE); registerReceiver(mReceiver, filter); private class ParingReceived extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { BluetoothDevice btDevice=mAdapter.getRemoteDevice("EC:89:F5:98:46:f9"); try { setPin(btDevice.getClass(),btDevice,"000000"); cancelPairingUserInput(btDevice.getClass(), btDevice); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
在我的4.2系统上是没有效果的。找了一个上午的资料;网上给出了两种解决方法:(1)修改setting 系统源码,(2)模拟点击事件。
蓝牙配对完成后就可以连接通信了。
3、蓝牙通信
蓝牙同时的本质是蓝牙套接字,一个主动发起连接的的设备做客户端,一个监听连接的设备做服务端,类似sokcet网络编程,利用多线程,读取数据流就可完成蓝牙通信。
如下是蓝牙串口通信的关键代码:
/** * 建立连接并通信 * * @param btDev * @return */ private boolean connect(BluetoothDevice btDev) { boolean flag = false; try { /*if(btDev.fetchUuidsWithSdp()){ btDev.getUuids(); }*/ //建立连接 mSocket = btDev.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); mSocket.connect(); mOutputStream = mSocket.getOutputStream(); mInputStream = mSocket.getInputStream(); mOutputStream.write("StartOnNet\n".getBytes()); mOutputStream.flush(); flag = true; } catch (Exception e) { }
如下蓝牙服务端关键代码:
private class ServerThread implements Runnable { private InputStream mInputStream; private OutputStream mOutputStream; public ServerThread() { } @Override public void run() { try { while (true) { mBluetoothServerSocket = mAdapter .listenUsingRfcommWithServiceRecord( "btspp", UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); Log.i("服务端线程运行", "蓝牙服务端线程开始"); Log.i("服务端线程运行", "蓝牙服务端线程阻塞中"); mBluetoothSocket = mBluetoothServerSocket.accept(); if (mBluetoothSocket != null) { break; } } Log.i("服务端线程运行", "蓝牙服务端线程<<<<<<<<<<<<<"); mInputStream = mBluetoothSocket.getInputStream(); mOutputStream = mBluetoothSocket.getOutputStream(); byte[] data = getSocketResult(mInputStream); String tempString = new String(data); Log.i("蓝牙服务端监听str", tempString); // 向客户端发送数据 if (tempString.equals("StartOnNet\n")) { mOutputStream.write("haha".getBytes()); mOutputStream.flush(); if(!isServiceRunning("com.yqq.endClient3.service.GpsInfoCollectionService",BluethoothServer.this)){ // 开启GPS收集服务 gpsService= new Intent(BluethoothServer.this, GpsInfoCollectionService.class); Log.i("蓝牙服务端监听<<<<<<<<<<<<<<<<<<<<<<", "<<<<<<<<<<<<<<<<<"); startService(gpsService); } } } catch (Exception e) { // TODO: handle exception } finally { if (mInputStream != null) { try { mInputStream.close(); mInputStream = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (mInputStream != null) { try { mOutputStream.close(); mOutputStream = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (mBluetoothSocket != null) { try { mBluetoothSocket.close(); mBluetoothSocket = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (mBluetoothServerSocket != null) { try { mBluetoothServerSocket.close(); mBluetoothServerSocket = null; Looper.prepare(); Message message = Message.obtain(); message.what = 0x123456; mHandler.sendMessage(message); Looper.loop(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
转自:http://www.2cto.com/kf/201502/374785.html
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories