Android手機(jī)藍(lán)牙總結(jié)之傳統(tǒng)藍(lán)牙

最近歼跟,公司有一個(gè)項(xiàng)目時(shí)關(guān)于手機(jī)藍(lán)牙和硬件藍(lán)牙相互通信的需求和媳。基于之前很久沒有學(xué)習(xí)硬件的知識(shí)哈街,這次記錄下來留瞳,以備下次需要時(shí)使用。

首先骚秦,需要搞清楚一些基本的概要她倘,藍(lán)牙3.0以前的是傳統(tǒng)藍(lán)牙璧微,4.0以后的是低功耗藍(lán)牙,Android藍(lán)牙在不同手機(jī)系統(tǒng)版本也有不同的藍(lán)牙硬梁,當(dāng)然也有不一樣的調(diào)用方法前硫。android4.3(API18)版本以下的對(duì)應(yīng)的是傳統(tǒng)藍(lán)牙,在掃描的時(shí)候等待時(shí)間會(huì)比較長(zhǎng)荧止。android4.3以上的是低功耗藍(lán)牙屹电,但是android4.3版本到5.0版本的調(diào)用方法和android5.0以上的調(diào)用方法是不一樣的。android用傳統(tǒng)的藍(lán)牙連接方式是無法和低功耗藍(lán)牙模塊建立通信通道的跃巡,因?yàn)橥ㄐ诺膮f(xié)議是不一樣的危号。低功耗藍(lán)牙是用GATT這種屬性傳輸協(xié)議,而傳統(tǒng)藍(lán)牙則是通過Socket的方式進(jìn)行數(shù)據(jù)的傳輸素邪。

android藍(lán)牙權(quán)限在6.0以上增加了一個(gè)模糊定位的權(quán)限外莲,不開啟部分手機(jī)無法進(jìn)行掃描藍(lán)牙發(fā)出的廣播。

藍(lán)牙權(quán)限:

為了能夠在你開發(fā)的應(yīng)用設(shè)備中使用藍(lán)牙功能兔朦,必須聲明藍(lán)牙的權(quán)限"BLUETOOTH"偷线。在進(jìn)行藍(lán)牙的通信,例如請(qǐng)求連接沽甥,接受連接以及交換數(shù)據(jù)中声邦,需要用到該權(quán)限。

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

如果你的應(yīng)用程序需要實(shí)例化藍(lán)牙設(shè)備的搜索或者對(duì)藍(lán)牙的設(shè)置進(jìn)行操作安接,那么必須聲明BLUETOOTH_ADMIN權(quán)限翔忽。大多數(shù)應(yīng)用需要該權(quán)限對(duì)本地的藍(lán)牙設(shè)備進(jìn)行搜索。該權(quán)限的其他能力并不應(yīng)當(dāng)被使用盏檐,除非你的應(yīng)用是一個(gè)電源管理的應(yīng)用歇式,需要對(duì)藍(lán)牙的設(shè)置進(jìn)行修改

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

android 6.0版本之后增加模糊定位授權(quán),如果不增加這個(gè)權(quán)限部分6.0以上的手機(jī)無法掃描出藍(lán)牙胡野。

<use-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

開啟關(guān)閉藍(lán)牙:

在使用藍(lán)牙通信之前材失,需要先開啟,使用BluetoothAdapter來進(jìn)行完成

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter ==null) {// Device does not support Bluetooth}

如果BluetoothAdapter為null值硫豆,則表示此手機(jī)不支持藍(lán)牙功能龙巨。

if(!mBluetoothAdapter.isEnabled()){ 
   Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
   startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

REQUEST_ENABLE_BT大于0的自己定義的int變量。isEnable()判斷藍(lán)牙是否可用熊响。推薦使用這種方式進(jìn)行開啟藍(lán)牙旨别。

還有另一種方式開啟,但是在部分手機(jī)不會(huì)彈出藍(lán)牙的授權(quán)限頁(yè)汗茄。

mBluetoothAdapter.enable()也能直接開啟藍(lán)牙秸弛。

搜索設(shè)備:

首先找到手機(jī)找出已匹配的藍(lán)牙設(shè)備:

// 將已配對(duì)的設(shè)備添加到列表中
Set pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
    for (BluetoothDevice device : pairedDevices) {
        mDevicesArray.add(device.getName() + "\n" + device.getAddress());
        deviceList.add(device);
    }
}

注冊(cè)廣播接收器并開啟掃描:

IntentFilter filter = new IntentFilter();
 //注冊(cè)設(shè)備被發(fā)現(xiàn)時(shí)的廣播
filter.addAction(BluetoothDevice.ACTION_FOUND);
 //注冊(cè)一個(gè)搜索結(jié)束時(shí)的廣播  
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);

廣播接收器:

public class BluetoothReceiver extends BroadcastReceiver {
    public final String TAG = getClass().getName();
    private BluetoothInterface bluetoothInterface;
    private List<BluetoothDevice> beans = null;

    public BluetoothReceiver(BluetoothInterface bluetoothInterface) {
        this.bluetoothInterface = bluetoothInterface;
        beans = new ArrayList<>();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        //發(fā)現(xiàn)藍(lán)牙廣播
        if (action.equals(BluetoothDevice.ACTION_FOUND)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            beans.add(device);
            //顯示已配對(duì)設(shè)備
            if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
                Log.e(TAG, "\n" + device.getName() + "==>" + device.getAddress() + "\n");
            } else if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                Log.e(TAG, "\n" + device.getName() + "==>" + device.getAddress() + "\n");
            }
        //搜索完成回調(diào)
        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
            bluetoothInterface.discoveryCompleted(beans);
        }
    }
}

只要搜索沒有完成,會(huì)一直接收外部藍(lán)牙設(shè)備發(fā)送的廣播。如果找到了對(duì)應(yīng)的藍(lán)牙設(shè)備递览,可以取消搜索叼屠。

mBluetoothAdapter.cancelDiscovery();

匹配和連接藍(lán)牙

匹配藍(lán)牙

//MY_UUID是藍(lán)牙串口服務(wù)對(duì)應(yīng)的應(yīng)用UUID,網(wǎng)上有說不能寫在UI線程绞铃,但我寫在UI線程也沒問題
BluetoothSocket socket =device.createRfcommSocketToServiceRecord(MY_UUID);

連接藍(lán)牙

public class ConnectedThread extends Thread {
    private final BluetoothSocket mSocket;
    private final InputStream mInStream;
    private final OutputStream mOutStream;
    private Handler mHandler;
    public final static int MESSAGE_READ = 1;
    public final static int MESSAGE_EXCEPTIONS = 2;
    public final static int MESSAGE_SUCCESS = 3;

    public ConnectedThread(BluetoothSocket socket, Handler handler) {
        mSocket = socket;
        mHandler = handler;
        InputStream temIn = null;
        OutputStream temOut = null;
        try {
            temIn = socket.getInputStream();
            temOut = socket.getOutputStream();
        } catch (IOException e) {

        }
        mInStream = temIn;
        mOutStream = temOut;
    }

    @Override
    public void run() {
        try {
            mSocket.connect();
            mHandler.sendEmptyMessage(MESSAGE_SUCCESS);
        } catch (IOException e) {
            e.printStackTrace();
            mHandler.sendEmptyMessage(MESSAGE_EXCEPTIONS);
            try {
                mSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        int bytes;
        //對(duì)輸入流保持監(jiān)聽直至一個(gè)異常發(fā)生
        while (true) {
            byte[] buffer = new byte[20];
            try {
                bytes = mInStream.read(buffer);
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }

    /**
     * 向藍(lán)牙模塊發(fā)射數(shù)據(jù)
     *
     * @param bytes
     */
    public void write(byte[] bytes) {
        try {
            mOutStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 關(guān)閉Socket的連接
     */
    public void cancel() {
        try {
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

藍(lán)牙在發(fā)送數(shù)據(jù)時(shí)有大小限制镜雨,一般為20字節(jié),在6.0之后的版本可以進(jìn)行設(shè)置大小儿捧。
如果有不正確的地方荚坞,可以在下面評(píng)論一起學(xué)習(xí)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纯命,一起剝皮案震驚了整個(gè)濱河市西剥,隨后出現(xiàn)的幾起案子痹栖,更是在濱河造成了極大的恐慌亿汞,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揪阿,死亡現(xiàn)場(chǎng)離奇詭異疗我,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)南捂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門吴裤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溺健,你說我怎么就攤上這事麦牺。” “怎么了鞭缭?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵剖膳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我岭辣,道長(zhǎng)吱晒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任沦童,我火速辦了婚禮仑濒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘偷遗。我一直安慰自己墩瞳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布氏豌。 她就那樣靜靜地躺著喉酌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瞭吃,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天碌嘀,我揣著相機(jī)與錄音,去河邊找鬼歪架。 笑死股冗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的和蚪。 我是一名探鬼主播止状,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼攒霹!你這毒婦竟也來了怯疤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤催束,失蹤者是張志新(化名)和其女友劉穎集峦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抠刺,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡塔淤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了速妖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片高蜂。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖罕容,靈堂內(nèi)的尸體忽然破棺而出备恤,到底是詐尸還是另有隱情,我是刑警寧澤锦秒,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布露泊,位于F島的核電站,受9級(jí)特大地震影響脂崔,放射性物質(zhì)發(fā)生泄漏滤淳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一砌左、第九天 我趴在偏房一處隱蔽的房頂上張望脖咐。 院中可真熱鬧,春花似錦汇歹、人聲如沸屁擅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)派歌。三九已至弯囊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間胶果,已是汗流浹背匾嘱。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留早抠,地道東北人霎烙。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蕊连,于是被迫代替她去往敵國(guó)和親悬垃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容