Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 藍牙搜索、配對連接通信總結

android 藍牙搜索、配對連接通信總結

編輯:關於Android編程

 

藍牙協議可以實現一個藍牙設備和6到8個藍牙設備進行通信。

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();
					}
				}
			}

		}
	}





  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved