简单梳理android蓝牙配对通讯、app层实现蓝牙静默配对、ClsUtils类
2016-08-11 18:36
495 查看
最近做蓝牙通讯,需要app层静默连接通讯,记录近几天的心酸摸索。
蓝牙发现新设备会发出广播:BluetoothDevice.ACTION_FOUND
蓝牙搜索结束会发出广播:BluetoothAdapter.ACTION_DISCOVERY_FINISHED
//自定义蓝牙搜索状态广播接收器,找到设备后更新自己的列表
注意添加权限:尖括号输入不了,囧。
uses-permission android:name=”android.permission.BLUETOOTH”
uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”
如果是android6.0系统需要额外添加权限,否则无法搜索设备:
uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”
uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”
**
公司要求在app层自定义蓝牙配对弹框,自动连接,网上搜了半天,没有很好的代码,今天把自己写的代码分享出来。话不多说,原理很简单,就是那个配对和取消的弹框是通过广播弹出来的,我们需要做的就是,自定义广播将其拦截,做自己的逻辑判断就可以了。下边是自动匹配所有蓝牙请求的代码,记得设置最大优先级哦,将IntentFilter的优先级或者静态注册的话android:priority=”2147483647”。自定义透明activity当做弹出框,点击某一个按钮的时候再device.setPairingConfirmation(true),简单吧。
**
1.搜索蓝牙设备
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) {//不支持蓝牙或者蓝牙不可用 Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show(); } else { if (!bluetoothAdapter.isDiscovering()) bluetoothAdapter.startDiscovery(); }
蓝牙发现新设备会发出广播:BluetoothDevice.ACTION_FOUND
蓝牙搜索结束会发出广播:BluetoothAdapter.ACTION_DISCOVERY_FINISHED
//自定义蓝牙搜索状态广播接收器,找到设备后更新自己的列表
private class BlueDeviceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(BluetoothDevice.ACTION_FOUND)) {//发现新设备 BluetoothDevice btd = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (!deviceList.contains(btd.getName() + "\n" + btd.getAddress())) { deviceList.add(btd.getName() + "\n" + btd.getAddress()); deviceAdapter.notifyDataSetChanged(); } } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { //搜索结束 } } } }
注意添加权限:尖括号输入不了,囧。
uses-permission android:name=”android.permission.BLUETOOTH”
uses-permission android:name=”android.permission.BLUETOOTH_ADMIN”
如果是android6.0系统需要额外添加权限,否则无法搜索设备:
uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”
uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”
2.发起配对请求
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (!bluetoothAdapter.checkBluetoothAddress(deviceAddress)) {//检查是否是有效的蓝牙地址 Toast.makeText(LauncherDemoActivity.this, "蓝牙设备地址无效", Toast.LENGTH_SHORT).show(); return false; } BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress); if (device != null) { Boolean returnValue = null; try { returnValue = ClsUtils.createBond(BluetoothDevice.class, device); } catch (Exception e) { e.printStackTrace(); } if (returnValue) {//发起配对成功,并不代表配对成功,因为可能被拒绝 return true; } }
3.自定义蓝牙配对状态广播接收器,当有自己想要的设备配对时,就可以进行下一步socket通讯了
class MyActionReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) { int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR); if (bondState == BluetoothDevice.BOND_BONDED) {//有新的配对设备 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices(); BluetoothDevice device1 = null; // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { if(device.getAddress().equals("55:44:33:22:11:00")) {//如果连接的设备中有特定的设备则发起socket连接请求 device1 = device; break; } } } if(device1!=null) {//发起socket连接请求 try2ConnectDevice(device1); } } } } private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); BluetoothSocket mmSocket = device.createRfcommSocketToServiceRecord(MY_UUID); this.device = device; try { // This is a blocking call and will only return on a // successful connection or an exception mmSocket.connect(); } catch (IOException e) { connectionFailed(); return; } new CommunicateThread(mmSocket).start(); // 其中CommunicateThread,即和服务器交互线程如下: //客户端交互线程 class CommnicateThread extends Thread { private final BluetoothSocket mmSocket; private InputStream mmInStream; private OutputStream mmOutStream; private DataOutputStream dataOutputStream; private DataInputStream dataInputStream; public CommnicateThread(BluetoothSocket socket) { mmSocket = socket; // Get the BluetoothSocket input and output streams try { mmInStream = mmSocket.getInputStream(); mmOutStream = mmSocket.getOutputStream(); dataOutputStream = new DataOutputStream(mmOutStream); dataInputStream = new DataInputStream(mmInStream); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } } public void run() { // Keep listening to the InputStream while connected while (true) { try { int type = dataInputStream.readByte(); // System.out.println(type); } catch (IOException e) { e.printStackTrace(); cancel(); connectionLost(); break; } } } //发送一个比特数组 public void write(byte[] buffer) { try { dataOutputStream.write(buffer); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } //发送一个int整型数据 public void writeInt(int i) { try { dataOutputStream.writeInt(i); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } //发送一个byte public void writeByte(byte b) { try { dataOutputStream.writeByte(b); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { if (mmSocket != null) mmSocket.close(); if(dataInputStream!=null)dataInputStream.close(); if(dataOutputStream!=null)dataOutputStream.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } }
4.服务器等待socket接入的代码,UUID需要和客户端一直,且是固定的貌似
BluetoothServerSocket bluetoothServerSocket; BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if(bluetoothAdapter==null){ Log.d("BluetoothServerService","设备不支持蓝牙"); return; } try { bluetoothServerSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("ServerListener", MY_UUID); } catch (IOException e) { e.printStackTrace(); } /** * 阻塞式等待接入线程 */ class AcceptThread extends Thread { @Override public void run() { setName("acceptThread"); BluetoothSocket socket = null; if (bluetoothServerSocket == null) return; setState(DISCONNECT); // Listen to the server socket if we're not connected while (mState != CONNECTED) { try { // This is a blocking call and will only return on a // successful connection or an exception socket = bluetoothServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "accept() failed", e); break; } // If a connection was accepted if (socket != null) { setState(CONNECTED); commnicateThread = new CommnicateThread(socket); commnicateThread.start(); } } } public void cancel() { try { if (null != bluetoothServerSocket) { bluetoothServerSocket.close(); } } catch (IOException e) { Log.e(TAG, "close() of server failed", e); } } } //服务器端的交互线程 class CommnicateThread extends Thread { private final BluetoothSocket mmSocket; private InputStream mmInStream; private OutputStream mmOutStream; private DataInputStream dataInputStream; private DataOutputStream dataOutputStream; public CommnicateThread(BluetoothSocket socket) { mmSocket = socket; // Get the BluetoothSocket input and output streams try { mmInStream = mmSocket.getInputStream(); mmOutStream = mmSocket.getOutputStream(); dataInputStream = new DataInputStream(mmInStream); dataOutputStream = new DataOutputStream(mmOutStream); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } } public void run() { // Keep listening to the InputStream while connected while (true) { try { int type = dataInputStream.readByte(); if (type == 1) { short length = dataInputStream.readShort(); int what = dataInputStream.readByte(); System.out.println("1号类型:指令"); sendOrderBroadcast(what); } else if (type == 2) { System.out.println("2号类型:javabean"); byte[] data; int flag; synchronized (this) { flag = dataInputStream.readInt(); int length = dataInputStream.readInt(); data = new byte[length]; dataInputStream.readFully(data); } System.out.println(data.length); InstantNotificationItem i = (InstantNotificationItem) ByteUtil.toObject(data); if (i == null) System.out.println("null"); else { sendNotificationChangeBroadcast(i, flag); } } writeAbyte((byte) 1);//回执给客户端的字符,暂时没有使用 } catch (IOException e) { Log.e(TAG, "连接中断", e); cancel(); connectionLost(); break; } } } /** * @param buffer The bytes to write */ public void write(byte[] buffer) { try { mmOutStream.write(buffer); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void writeAbyte(byte what){ try { dataOutputStream.writeByte(what); } catch (IOException e) { e.printStackTrace(); } } public void cancel() { try { if (mmSocket != null) mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } }
**
附:自定义蓝牙配对弹框、自动连接
**公司要求在app层自定义蓝牙配对弹框,自动连接,网上搜了半天,没有很好的代码,今天把自己写的代码分享出来。话不多说,原理很简单,就是那个配对和取消的弹框是通过广播弹出来的,我们需要做的就是,自定义广播将其拦截,做自己的逻辑判断就可以了。下边是自动匹配所有蓝牙请求的代码,记得设置最大优先级哦,将IntentFilter的优先级或者静态注册的话android:priority=”2147483647”。自定义透明activity当做弹出框,点击某一个按钮的时候再device.setPairingConfirmation(true),简单吧。
public class BluetoothConnectActivityReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); try { // 广播接收者的优先者为最高 收到广播后 停止广播向下传递 // TODO: 16/8/9 判断device是否是自己的设备,是的话拦截,否则不处理。 device.setPairingConfirmation(true); abortBroadcast(); } catch (Exception e) { e.printStackTrace(); } } } }
**
附录2:使用反射调用私有方法的ClsUtils.java文件
**import android.bluetooth.BluetoothDevice; import android.util.Log; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ClsUtils { /** * 与设备配对 参考源码: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); } 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 true; } static public boolean setPassKey(Class btClass, BluetoothDevice btDevice, String str) throws Exception { try { Method removeBondMethod = btClass.getDeclaredMethod("setPasskey", new Class[] { byte[].class }); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[] { str.getBytes() }); Log.e("returnValue", "" + returnValue); } 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 true; } // 取消用户输入 static public boolean cancelPairingUserInput(Class btClass, BluetoothDevice device) throws Exception { Method createBondMethod = btClass.getMethod("cancelPairingUserInput"); // cancelBondProcess() Boolean returnValue = (Boolean) createBondMethod.invoke(device); 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(); } } public static boolean isWantedMac(String macStr) { if (macStr == null || macStr.isEmpty()) return false; if (macStr.equals("55:44:33:22:11:00")) { return true; } else return false; } }
相关文章推荐
- android 蓝牙通讯理解与实现
- android 取消蓝牙配对框 实现自动配对
- Android 蓝牙设备通讯的开发(配对/连接/传输数据)
- android 取消蓝牙配对框 实现自动配对
- Android即时通讯工具的简单实现
- android 实现蓝牙自动配对连接
- 如何实现android蓝牙开发 自动配对连接,并不弹出提示框
- WebSocket实现Android客户端之间的简单通讯
- Android中如何实现蓝牙的配对与连接
- Android简单的蓝牙配对与连接
- Android 取消蓝牙配对框 实现自动配对
- 如何实现android蓝牙开发 自动配对连接,并不弹出提示框
- Android通过JNI实现与C语言的串口通讯操作蓝牙硬件模块
- Android适配安卓6.0蓝牙通讯实现过程
- 如何实现android蓝牙开发 自动配对连接,并不弹出提示框
- Android蓝牙实现自动配对,无需输入密码
- android 取消蓝牙配对框 实现自动配对
- 如何实现android蓝牙开发 自动配对连接,并不弹出提示框
- android 取消蓝牙配对框 实现自动配对
- Android实现的简单蓝牙程序示例