最近工作中用到了藍牙方面的知識,所以寫此博客記錄一下。
一、藍牙開發需要用到的API都在 android.bluetooth包下
表示本地藍牙適配器(藍牙無線裝置)。 BluetoothAdapter
是所有藍牙交互的入口點。 利用它可以發現其他藍牙設備,查詢綁定(配對)設備的列表,使用已知的 MAC 地址實例化 BluetoothDevice
,以及創建 BluetoothServerSocket
以偵聽來自其他設備的通信。
表示遠程藍牙設備。利用它可以通過 BluetoothSocket
請求與某個遠程設備建立連接,或查詢有關該設備的信息,例如設備的名稱、地址、類和綁定狀態等。
表示藍牙套接字接口(與 TCP Socket
相似)。這是允許應用通過 InputStream 和 OutputStream 與其他藍牙設備交換數據的連接點。
表示用於偵聽傳入請求的開放服務器套接字(類似於 TCP ServerSocket
)。 要連接兩臺 Android 設備,其中一臺設備必須使用此類開放一個服務器套接字。 當一臺遠程藍牙設備向此設備發出連接請求時,BluetoothServerSocket
將會在接受連接後返回已連接的 BluetoothSocket
。
描述藍牙設備的一般特徵和功能。 這是一組只讀屬性,用於定義設備的主要和次要設備類及其服務。 不過,它不能可靠地描述設備支持的所有藍牙配置文件和服務,而是適合作爲設備類型提示。
表示藍牙配置文件的接口。 藍牙配置文件是適用於設備間藍牙通信的無線接口規範。
提供藍牙耳機支持,以便與手機配合使用。
定義高質量音頻如何通過藍牙連接和流式傳輸,從一臺設備傳輸到另一臺設備。“A2DP”代表高級音頻分發配置文件。
表示用於控制藍牙服務的健康設備配置文件代理。
用於實現 BluetoothHealth
回調的抽象類。您必須擴展此類並實現回調方法,以接收關於應用註冊狀態和藍牙通道狀態變化的更新內容。
BluetoothHealthAppConfiguration
表示第三方藍牙健康應用註冊的應用配置,以便與遠程藍牙健康設備通信。
BluetoothProfile.ServiceListener
在 BluetoothProfile
IPC 客戶端連接到服務(即,運行特定配置文件的內部服務)或斷開服務連接時向其發送通知的接口
官方文檔地址:https://developer.android.com/guide/topics/connectivity/bluetooth,有興趣可以去看看,上面說的很詳細。
二 、要用到的權限
6.0以下
<!-- 使用藍牙的權限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 掃描藍牙設備或者操作藍牙設置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
6.0以上
<!-- 使用藍牙的權限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 掃描藍牙設備或者操作藍牙設置 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--模糊定位權限,僅作用於6.0+-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--精準定位權限,僅作用於6.0+-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
三、開發工作
1. 流程:動態權限檢查---->獲取藍牙適配器---->啓用藍牙---->查找設備---->配對與連接
流程大概就是這樣,權限檢查就不說了,應該都會,不會可以自己找找相關博客看下。
2. 首先打開藍牙,打開藍牙大概有兩種方式
- 2.1 提示用戶跳轉到設置界面打開
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
- 2.2 不提示靜默打開
if (mBluetoothAdapter.isEnabled ()){
mBluetoothAdapter.enable ();
}
- 2.3 查詢已配對的藍牙
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
- 2.4 掃描設備
/**
* 開始藍牙掃描
*
* @return
*/
public boolean startScan() {
if (!isBlueEnable()) {
Log.e(TAG, "Bluetooth not enable!");
return false;
}
//當前是否在掃描,如果是就取消當前的掃描,重新掃描
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
//此方法是個異步操作,一般搜索12秒
return mBluetoothAdapter.startDiscovery();
}
註冊廣播,通過廣播接收藍牙信息,我這裏是有一個回調接口
/**
* 註冊廣播
*/
public void registerReceiver() {
IntentFilter filter1=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_STARTED);
IntentFilter filter2=new IntentFilter (android.bluetooth.BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
IntentFilter filter3=new IntentFilter (BluetoothDevice.ACTION_FOUND);
registerReceiver (scanBlueReceiver, filter1);
registerReceiver (scanBlueReceiver, filter2);
registerReceiver (scanBlueReceiver, filter3);
}
public class ScanBlueReceiver extends BroadcastReceiver {
private static final String TAG = ScanBlueReceiver.class.getName();
private ScanBlueCallBack callBack;
public ScanBlueReceiver(ScanBlueCallBack callBack) {
this.callBack = callBack;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "action:" + action);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (action) {
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
Log.d(TAG, "開始掃描...");
callBack.onScanStarted();
break;
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
Log.d(TAG, "結束掃描...");
callBack.onScanFinished();
break;
case BluetoothDevice.ACTION_FOUND:
Log.d(TAG, "發現設備...");
callBack.onScanning(device);
break;
}
}
}
2.5 藍牙配對
首先需要用到 ClsUtils 類,這個網上都有,我就不貼出來了,感謝大神們的奉獻。
藍牙配對需要和目標設備建立連接,這裏需要用到上文說的BluetoothSocket了
/**
* 藍牙連接線程
*/
public class ConnectBlueTask extends AsyncTask<BluetoothDevice, Integer, BluetoothSocket> {
private static final String TAG = ConnectBlueTask.class.getName();
private BluetoothDevice bluetoothDevice;
private ConnectBlueCallBack callBack;
public ConnectBlueTask(ConnectBlueCallBack callBack){
this.callBack = callBack;
}
UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
@Override
protected BluetoothSocket doInBackground(BluetoothDevice... bluetoothDevices) {
bluetoothDevice = bluetoothDevices[0];
Log.e (TAG, "doInBackground: "+bluetoothDevice.getAddress ());
BluetoothSocket socket = null;
try{
Log.d(TAG,"開始連接socket,uuid:" );
socket = bluetoothDevice.createRfcommSocketToServiceRecord(SERIAL_UUID);
if (socket != null && !socket.isConnected()){
socket.connect();
}
}catch (IOException e){
Log.e(TAG,"socket連接失敗");
try {
socket =(BluetoothSocket) bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(bluetoothDevice,1);
socket.connect();
// socket.close();
} catch (IOException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace ();
} catch (InvocationTargetException e1) {
e1.printStackTrace ();
} catch (NoSuchMethodException e1) {
e1.printStackTrace ();
}
}
return socket;
}
@Override
protected void onPreExecute() {
Log.d(TAG,"開始連接");
if (callBack != null) callBack.onStartConnect();
}
@Override
protected void onPostExecute(BluetoothSocket bluetoothSocket) {
if (bluetoothSocket != null && bluetoothSocket.isConnected()){
Log.d(TAG,"連接成功");
if (callBack != null) callBack.onConnectSuccess(bluetoothDevice, bluetoothSocket);
}else {
Log.d(TAG,"連接失敗");
if (callBack != null) callBack.onConnectFail(bluetoothDevice, "連接失敗");
}
}
}
同樣需要註冊相應廣播,用來獲取配對狀態
public void pinRegisterReceiver() {
IntentFilter filter4=new IntentFilter (BluetoothDevice.ACTION_PAIRING_REQUEST);
IntentFilter filter5=new IntentFilter (BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver (pinBlueReceiver, filter4);
registerReceiver (pinBlueReceiver, filter5);
}
private String pin="0000"; // 此處爲你要連接的藍牙設備的初始密鑰,一般爲1234或0000
private static final String TAG=PinBlueReceiver.class.getName ();
private PinBlueCallBack callBack;
public PinBlueReceiver(PinBlueCallBack callBack) {
this.callBack=callBack;
}
@Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction ();
Log.d (TAG, "action:" + action);
BluetoothDevice device=intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals (action)) {
try {
callBack.onBondRequest ();
// 開始配對
boolean ret=ClsUtils.setPin (device.getClass (), device, pin);
abortBroadcast ();// 將廣播終止,否則會出現一個一閃而過的配對框。
//Method removeBondMethod = device.getClass().getDeclaredMethod("setPin", new Class[]{byte[].class});
//Boolean returnValue = (Boolean) removeBondMethod.invoke(device, new Object[]{pin.getBytes()});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace ();
}
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals (action)) {
switch (device.getBondState ()) {
case BluetoothDevice.BOND_NONE:
Log.d (TAG, "取消配對");
callBack.onBondFail (device);
break;
case BluetoothDevice.BOND_BONDING:
Log.d (TAG, "配對中");
callBack.onBonding (device);
break;
case BluetoothDevice.BOND_BONDED:
Log.d (TAG, "配對成功");
callBack.onBondSuccess (device);
break;
}
}
}
大概就是這樣。。
參考:https://blog.csdn.net/zqf_888/article/details/81060606 這篇文章寫得很好,建議觀看。