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討論哈~