当前位置: 代码迷 >> Android >> android 蓝牙搜寻、配对连接通信总结
  详细解决方案

android 蓝牙搜寻、配对连接通信总结

热度:92   发布时间:2016-04-28 02:30:15.0
android 蓝牙搜索、配对连接通信总结

 

蓝牙协议可以实现一个蓝牙设备和6到8个蓝牙设备进行通信。

1、蓝牙搜索的实现

利用蓝牙的发现和完成动作动态注册广播接受者获得蓝牙设备。

第一步,获得蓝牙适配器

BluetoothAdapter mBtAdapter= BluetoothAdapter.getDefaultAdapter();
<span style="white-space:pre">	</span>// 判断蓝牙是否打开<span style="white-space:pre">				</span>if (!mAdapter.isEnabled()) {<span style="white-space:pre">					</span>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<? extends BluetoothDevice> 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<? extends BluetoothDevice> 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();					}				}			}		}	}





  相关解决方案