1. 程式人生 > >android 藍芽程式設計

android 藍芽程式設計

前言

最近有一些藍芽的通訊需要做,就研究了一下藍芽連線相關

  1. 連線藍芽電子秤
  2. 連線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深深的惡意,整個專案的坑數不勝數,這裡先這樣吧