1. 程式人生 > >Android藍芽自動配對Demo,親測好使!!!

Android藍芽自動配對Demo,親測好使!!!

藍芽自動配對,即搜尋到其它藍芽裝置之後直接進行配對,不需要彈出配對確認框或者金鑰輸入框。

經過最近一段時間得研究,針對網上給出的案例。總結了一個親測好使的Demo。

說明如下:

1、本Demo用來連線藍芽裝置HC-05,如果你要連線其他藍芽裝置,注意修改相關名字以及修改裝置初試pin值。

2、將Demo安裝在Android手機上,點選按鈕,可以實現與目標藍芽裝置的自動配對。

3、若目標藍芽裝置為Android手機的藍芽,則只能保證本裝置不彈出配對框,對方還是會彈出配對框。但是!!不管目標藍芽點選“確認”or“取消”,在本裝置中都顯示已經成功配對。實測表明,確實已經配對了,可以進行資料傳輸。

4、由於使用了廣播機制,所以需要在Androidmanifest.xml進行如下配置。

先配置藍芽使用許可權:

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
 

然後配置action,將需要用到的廣播進行註冊

<receiver android:name="com.ywq.broadcast.BluetoothReceiver" >
    <intent-filter android:priority="1000">
        <action android:name="android.bluetooth.device.action.PAIRING_REQUEST"/>
        <action android:name="android.bluetooth.device.action.FOUND" />
    </intent-filter>
</receiver>

程式執行流程:

1、點選按鈕,判斷藍芽是否開啟,,執行bluetoothAdapter.startDiscovery();由本地藍芽裝置掃描遠端藍芽裝置,startDiscovery()方法是一個非同步方法,呼叫後立即返回。該方法會進行藍芽裝置的搜尋,持續12秒。

2、搜尋時,系統會發送3個廣播,分別為:ACTION_DISCOVERY_START:開始搜尋 、ACTION_DISCOVERY_FINISHED:搜尋結束、 ACTION_FOUND:找到裝置,該Intent中包含兩個extra fields;         

3、在廣播接收類中BluetoothReceiver.java中,當裝置找到之後會執行其onReceive方法。

4、String action = intent.getAction(); //得到action,

第一次action的值為BluetoothDevice.ACTION_FOUND,當找到的裝置是我們目標藍芽裝置時,呼叫createBond方法來進行配對。ClsUtils.createBond(btDevice.getClass(), btDevice);該方法執行後,系統會收到一個請求配對的廣播,即android.bluetooth.device.action.PAIRING_REQUEST。最後進行自動配對操作。

5、配對操作藉助工具類ClsUtils.java得到了Android藍芽API中隱藏的方法,實現自動配對,不彈出配對框的功能。

程式碼如下:

MainActivity.java

package com.example.mybuletooth;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener{
	
	/** Called when the activity is first created. */ 
	private Button autopairbtn=null;
	private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		autopairbtn=(Button) findViewById(R.id.button1);
		autopairbtn.setOnClickListener(this);
		
	}
	
	//設定按鈕的監聽方法
	@Override
	public void onClick(View arg0) {
		
		if (!bluetoothAdapter.isEnabled())
		{
				bluetoothAdapter.enable();//非同步的,不會等待結果,直接返回。
		}else{
				bluetoothAdapter.startDiscovery();
			 }
		
	}
}

BluetoothReceiver.java

package com.ywq.broadcast;

import com.ywq.tools.ClsUtils;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;


public class BluetoothReceiver extends BroadcastReceiver{

	String pin = "1234";  //此處為你要連線的藍芽裝置的初始金鑰,一般為1234或0000
	public BluetoothReceiver() {
		
	}

	//廣播接收器,當遠端藍芽裝置被發現時,回撥函式onReceiver()會被執行 
	@Override
	public void onReceive(Context context, Intent intent) {
		
		String action = intent.getAction(); //得到action
		Log.e("action1=", action);
		BluetoothDevice btDevice=null;  //建立一個藍芽device物件
		 // 從Intent中獲取裝置物件
		btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 
		
		if(BluetoothDevice.ACTION_FOUND.equals(action)){  //發現裝置
			Log.e("發現裝置:", "["+btDevice.getName()+"]"+":"+btDevice.getAddress());
			
			if(btDevice.getName().contains("HC-05"))//HC-05裝置如果有多個,第一個搜到的那個會被嘗試。
			{
				if (btDevice.getBondState() == BluetoothDevice.BOND_NONE) {  
					
					Log.e("ywq", "attemp to bond:"+"["+btDevice.getName()+"]");
					try {
						//通過工具類ClsUtils,呼叫createBond方法
						ClsUtils.createBond(btDevice.getClass(), btDevice);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
                }
			}else
				Log.e("error", "Is faild");
		}else if(action.equals("android.bluetooth.device.action.PAIRING_REQUEST")) //再次得到的action,會等於PAIRING_REQUEST
		{
			Log.e("action2=", action);
			if(btDevice.getName().contains("HC-05"))
			{
				Log.e("here", "OKOKOK");
				
				try {
					
					//1.確認配對
					ClsUtils.setPairingConfirmation(btDevice.getClass(), btDevice, true);
					//2.終止有序廣播
					Log.i("order...", "isOrderedBroadcast:"+isOrderedBroadcast()+",isInitialStickyBroadcast:"+isInitialStickyBroadcast());
					abortBroadcast();//如果沒有將廣播終止,則會出現一個一閃而過的配對框。
					//3.呼叫setPin方法進行配對...
					boolean ret = ClsUtils.setPin(btDevice.getClass(), btDevice, pin);
					
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else
				Log.e("提示資訊", "這個裝置不是目標藍芽裝置");
			
		}
	}
}

工具類ClsUtils.java
package com.ywq.tools;

/************************************ 藍芽配對函式 * **************/

import java.lang.reflect.Method;  
import java.lang.reflect.Field;  
import android.bluetooth.BluetoothDevice;  
import android.util.Log;  
  
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<? extends BluetoothDevice> 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 cancelPairingUserInput(Class<?> btClass,  
            BluetoothDevice device)  throws Exception  
    {  
        Method createBondMethod = btClass.getMethod("cancelPairingUserInput");  
//        cancelBondProcess(btClass, device);
        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();  
    } 
    
    //確認配對
    
    static public void setPairingConfirmation(Class<?> btClass,BluetoothDevice device,boolean isConfirm)throws Exception 
    {
    	Method setPairingConfirmation = btClass.getDeclaredMethod("setPairingConfirmation",boolean.class); 
    	setPairingConfirmation.invoke(device,isConfirm);
    }
    
   
    /** 
     * 
     * @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();  
        }  
    }  
}  

Androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mybuletooth"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
    
    <uses-permission android:name="android.permission.BLUETOOTH"/>
	<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <receiver android:name="com.ywq.broadcast.BluetoothReceiver" >
    		<intent-filter android:priority="1000">
        		<action android:name="android.bluetooth.device.action.PAIRING_REQUEST"/>
        		<action android:name="android.bluetooth.device.action.FOUND" />
    		</intent-filter>
		</receiver>
    </application>

</manifest>


佈局配置檔案activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.mybuletooth.MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="54dp"
        android:layout_marginTop="56dp"
        android:text="自動配對" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:text="點選按鈕,自動搜尋藍芽裝置,並且進行配對" />

</RelativeLayout>


針對網上其它帖子中的demo不好使的原因,在此給出一些我的看法,是不是這樣不敢保證,至少部分是這些原因吧。。。

1、出現一個一閃而過的配對框怎麼辦?

答:那是因為廣播沒有停止,須得呼叫abortBroadcast();將廣播停止。

2、自動配對框還是會彈出來怎麼辦?

答:網上好多帖子程式碼有誤,或者沒有說清楚。請注意相關配置和工具類中函式的使用。

這是本人親測好使的自動配對Demo,僅供參考,希望對大家有所幫助。有問題可以聯絡我。

重要更新:********************************************************************************


2016-10-20 ,今天和一個諮詢我的小夥伴詳細的聊了會兒天。他的問題是,下圖所示的if語句塊進不去。

它的btDevice.getBondState( )=12,但是BluetoothDevice.BOND_NONE=10,這不是肯定進不去麼。哭

其中,查閱SDK,可以看到BluetoothDevice的這幾個函式和數字的含義是什麼。

如下所示:

我一看,天吶,很明顯的低階錯誤。我讓他開啟設定看看,是否顯示已經配對。結果自然是已經配對了。

產生原因:這個demo在跑之前,他已經在手機-設定-藍芽中手動把目標藍芽配對了。那還玩個毛呀大哭

當手動取消配對後,程式執行正常,log列印和預期一樣,自動配對實現。

提示:

通過這個小失誤,可以看出,評論裡好多說這也不行,那也不行的。既然好多人都說好使,那你為什麼就不行呢?還是多從自身找問題吧,心思縝密點,避免這種低階失誤。大哥,你是程式猿好不好。

                                         


如果對你有幫助,記得點贊哦~歡迎大家關注我的部落格,有問題可以進群366533258討論哈~