android 藍芽程式設計
前言
最近有一些藍芽的通訊需要做,就研究了一下藍芽連線相關
- 連線藍芽電子秤
- 連線pos機列印
其中連線藍芽電子秤是接收資料
pos機列印是傳送資料/接收資料
流程圖
流程圖畫的相當不專業,請自行腦補
核心類
因為這次的電子秤不是4.0的裝置,所以沒有使用BLE的開發,而是經典藍芽(SPP)的連線方式
BluetoothAdapter
全域性變數
protected BluetoothAdapter mAdapter;
獲取的方法,在API18下的時候使用的方式和以上的不一樣,其實差別不大
if (SDK_INT < 18) {
adapter = BluetoothAdapter.getDefaultAdapter();
} else {
BluetoothManager bm = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
adapter = bm.getAdapter();
}
藍芽使用的是註冊廣播的方式來獲取系統給我們的通知
核心有以下的幾種,註冊廣播的方法自己去搜下吧
BluetoothDevice.ACTION_FOUND//找到裝置
BluetoothDevice.ACTION_NAME_CHANGED//裝置的名字
BluetoothAdapter.ACTION_DISCOVERY_FINISHED//掃描結束
BluetoothDevice.ACTION_PAIRING_REQUEST//配對請求的放棄
BluetoothAdapter.STATE_OFF//藍芽關閉
BluetoothAdapter.STATE_ON//藍芽開啟
連線
一般這種連線應該是全域性單例,考慮寫在了service中
首先需要掃描所有的藍芽連線,但是這裡有個坑,就是如果你將廣播註冊在onCreate中和onDestroy,你每次都需要接收系統的廣播,如果出現同名或者別的原因,這裡就會一直接收廣播
所以這裡需要動態的將廣播註冊與反註冊
我這裡使用的方案請參照流程圖
說明
這裡是經典藍芽(SPP)的連線程式碼,BLE的連線相關目前還沒有做,後續如果有實現的時候也會再寫blog
關於UUID
藍芽連線的UUID是有一套自己的定義規範的,但是目前的廠商不知道為什麼大部分習慣都使用同一個UUID,我這裡藍芽稱,藍芽印表機都用的這個
public static final UUID _UUID = java.util.UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
掃描
mAdapter.startDiscovery()
關於找到裝置的坑
這裡有一些關於裝置的坑,有的裝置你使用BluetoothDevice.ACTION_FOUND
廣播中獲取藍芽裝置的名字會發現是空的,這個時候就很尷尬了,使用系統自帶的藍芽掃描也會發現,掃描到的是先MAC地址,然後過幾秒更改為名字,這裡有另一個廣播BluetoothDevice.ACTION_NAME_CHANGED
可以獲取到名字更新時的光爆
當然藍芽裝置如果提前知道藍芽的mac地址,最好還是使用mac地址連線匹配為最佳,畢竟mac地址輕易不會重複
配對
try {
// 連線建立之前的先配對
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
Method creMethod = BluetoothDevice.class.getMethod("createBond");
creMethod.invoke(device);
} else {//已配對,連線socket
connDevice(device);
}
} catch (Exception e) {
// TODO: handle exception
//DisplayMessage("無法配對!");
e.printStackTrace();
}
這裡如果已經配對,則直接連線,如果沒有配對需要先配對,這裡只是建立配對請求
ACTION_PAIRING_REQUEST
這個廣播用於接收配對請求的發起,然後使用
LogUtils.d(TAG, "manualConn:" + manualConn);
if (manualConn) {
return;
}
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device == null) {
return;
}
LogUtils.d(TAG, device.getName());
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
try {
// ClsUtils.setPin(device.getClass(), device, pwd); // 手機和藍芽採集器配對
LogUtils.d(TAG, "設定pin碼" + pwd);
ToastUtils.toast(device.getName() + "配對中");
boolean pinResult = device.setPin(pwd.getBytes());
// handler.postDelayed(new Runnable() {
// @Override
// public void run() {
// try {
// ClsUtils.cancelPairingUserInput(device.getClass(), device);
// } catch (Exception e) {
// }
// }
// }, 1000);
// 一般呼叫不成功,前言裡面講解過了
LogUtils.d(TAG, "pinResult:" + pinResult);
if (pinResult) {
connDevice(device);
} else {
ToastUtils.toast("pin碼不正確,請手動配對電子秤後點擊連線");
manualConn = true;
}
} catch (Exception e) {
ToastUtils.toast("請求連線錯誤...");
}
}
這裡是直接貼出來了程式中的片段,也會有一些報錯,替換為自己的Log/Toast的util就可以了,也可以考慮刪除掉,這裡註釋掉的部分原本是打算關閉配對的連線框的,但是這裡有一些其他的問題,不同的rom處理方式不同,有些處理時會將pin碼清空導致連線失敗,所以這裡將這部分程式碼清空,不關閉了
連線
核心連線程式碼
socket = device.createInsecureRfcommSocketToServiceRecord(_UUID); //不安全的
// socket = device.createRfcommSocketToServiceRecord(_UUID); //安全
socket.connect()
關於連線方式,這裡有兩種.一種是使用不安全的連線方式,一種是使用安全的連線方式,這裡需要根據你的藍芽裝置作為區分,
都是建立一個BluetoothSocket
一般來說,如果對方是android裝置,應該是安全的,如果是外接裝置(藍芽電子秤) 一般使用不安全的方案.
這兩個連線方法要求API>10
題外話
我其實現在的minSDK已經是19了,目前google自己都放棄維護低版本了,google chrome都不支援他們了,咱們也沒必要繼續支援低版本了
連線成功後,可以獲取到一個socket連線,可以用這個socket連接獲取到相關資訊,不管是接收還是發出,通過這個連線就可以具體的獲取相關資訊
這裡只是拋磚引玉
具體的實現後續有時間抽取出來形成一個開源專案再貼吧,專案畢竟是公司的,我這裡不方便直接將整個程式碼貼出來,這個連線的相關程式碼非常亂
後記
這個藍芽專案讓我感受到了google深深的惡意,整個專案的坑數不勝數,這裡先這樣吧