Android 藍(lán)牙開發(fā)(一)藍(lán)牙通信

原文地址:https://blog.csdn.net/VNanyesheshou/article/details/51554852

1 藍(lán)牙基本操作

隨著可穿戴設(shè)備的流行,研究藍(lán)牙是必不可少的一門技術(shù)了喘漏。

總結(jié)了下藍(lán)牙開發(fā)使用的一些東西分享一下。

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

首先需要AndroidManifest.xml文件中添加操作藍(lán)牙的權(quán)限世分。

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

允許程序連接到已配對(duì)的藍(lán)牙設(shè)備恋沃。

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

允許程序發(fā)現(xiàn)和配對(duì)藍(lán)牙設(shè)備。

BluetoothAdapter

操作藍(lán)牙主要用到的類 BluetoothAdapter類绩脆,使用時(shí)導(dǎo)包

import android.bluetooth.BluetoothAdapter;

源碼具體位置frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

BluetoothAdapter 代表本地設(shè)備的藍(lán)牙適配器边翁。該BluetoothAdapter可以執(zhí)行基本的藍(lán)牙任務(wù)翎承,例如啟

動(dòng)設(shè)備發(fā)現(xiàn),查詢配對(duì)的設(shè)備列表符匾,使用已知的MAC地址實(shí)例化一個(gè)BluetoothDevice類叨咖,并創(chuàng)建一個(gè)

BluetoothServerSocket監(jiān)聽來自其他設(shè)備的連接請(qǐng)求。

獲取藍(lán)牙適配器

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

開啟藍(lán)牙

if(!mBluetoothAdapter.isEnabled()){

//彈出對(duì)話框提示用戶是后打開

Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enabler, REQUEST_ENABLE);

? ? ? //不做提示啊胶,直接打開甸各,不建議用下面的方法,有的手機(jī)會(huì)有問題焰坪。

? ? ? // mBluetoothAdapter.enable();

}

獲取本地藍(lán)牙信息

//獲取本機(jī)藍(lán)牙名稱

String name = mBluetoothAdapter.getName();

//獲取本機(jī)藍(lán)牙地址

String address = mBluetoothAdapter.getAddress();

Log.d(TAG,"bluetooth name ="+name+" address ="+address);

//獲取已配對(duì)藍(lán)牙設(shè)備

Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();

Log.d(TAG, "bonded device size ="+devices.size());

for(BluetoothDevice bonddevice:devices){

Log.d(TAG, "bonded device name ="+bonddevice.getName()+" address"+bonddevice.getAddress());

}

搜索設(shè)備

mBluetoothAdapter.startDiscovery();

停止搜索

mBluetoothAdapter.cancelDiscovery();

搜索藍(lán)牙設(shè)備趣倾,該過程是異步的,通過下面注冊(cè)廣播接受者某饰,可以監(jiān)聽是否搜到設(shè)備儒恋。

IntentFilter filter = new IntentFilter();

//發(fā)現(xiàn)設(shè)備

filter.addAction(BluetoothDevice.ACTION_FOUND);

//設(shè)備連接狀態(tài)改變

filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);

//藍(lán)牙設(shè)備狀態(tài)改變

filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

registerReceiver(mBluetoothReceiver, filter);

監(jiān)聽掃描結(jié)果

通過廣播接收者查看掃描到的藍(lán)牙設(shè)備,每掃描到一個(gè)設(shè)備黔漂,系統(tǒng)都會(huì)發(fā)送此廣播(BluetoothDevice.ACTION_FOUNDE)诫尽。其中參數(shù)intent可以獲取藍(lán)牙設(shè)備BluetoothDevice。

該demo中是連接指定名稱的藍(lán)牙設(shè)備炬守,BLUETOOTH_NAME為"Galaxy Nexus",如果掃描不到牧嫉,記得改這個(gè)藍(lán)牙名稱。

private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver(){

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

Log.d(TAG,"mBluetoothReceiver action ="+action);

if(BluetoothDevice.ACTION_FOUND.equals(action)){//每掃描到一個(gè)設(shè)備减途,系統(tǒng)都會(huì)發(fā)送此廣播酣藻。

//獲取藍(lán)牙設(shè)備

BluetoothDevice scanDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

if(scanDevice == null || scanDevice.getName() == null) return;

Log.d(TAG, "name="+scanDevice.getName()+"address="+scanDevice.getAddress());

//藍(lán)牙設(shè)備名稱

String name = scanDevice.getName();

if(name != null && name.equals(BLUETOOTH_NAME)){

mBluetoothAdapter.cancelDiscovery();

//取消掃描

mProgressDialog.setTitle(getResources().getString(R.string.progress_connecting)); //連接到設(shè)備。

mBlthChatUtil.connect(scanDevice);

}

}else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){

}

}

};

設(shè)置藍(lán)牙可見性

有時(shí)候掃描不到某設(shè)備鳍置,這是因?yàn)樵撛O(shè)備對(duì)外不可見或者距離遠(yuǎn)辽剧,需要設(shè)備該藍(lán)牙可見,這樣該才能被搜索到税产。

可見時(shí)間默認(rèn)值為120s怕轿,最多可設(shè)置300坊夫。

if (mBluetoothAdapter.isEnabled()) {

if (mBluetoothAdapter.getScanMode() !=

BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {

Intent discoverableIntent = new Intent(

BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

discoverableIntent.putExtra(

BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);

startActivity(discoverableIntent);

}

}

2 服務(wù)端

android 藍(lán)牙之間可以通過SDP協(xié)議建立連接進(jìn)行通信,通信方式類似于平常使用socket撤卢。

首先創(chuàng)建BluetoothServerSocket ,BluetoothAdapter中提供了兩種創(chuàng)建BluetoothServerSocket 方式梧兼,如下圖所示為創(chuàng)建安全的RFCOMM Bluetooth socket放吩,該連接是安全的需要進(jìn)行配對(duì)。而通過listenUsingInsecureRfcommWithServiceRecord創(chuàng)建的RFCOMM Bluetooth socket是不安全的羽杰,連接時(shí)不需要進(jìn)行配對(duì)渡紫。

其中的uuid需要服務(wù)器端和客戶端進(jìn)行統(tǒng)一。

private class AcceptThread extends Thread {

? ? ? ? // 本地服務(wù)器套接字

? ? ? ? private final BluetoothServerSocket mServerSocket;

? ? ? ? public AcceptThread() {? ? ?

? ? ? ? ? ? BluetoothServerSocket tmp = null;

? ? ? ? ? ? // 創(chuàng)建一個(gè)新的偵聽服務(wù)器套接字

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? tmp = mAdapter.listenUsingRfcommWithServiceRecord(

? ? ? ? ? ? ? ? SERVICE_NAME, SERVICE_UUID);

? ? ? ? ? ? //tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(SERVICE_NAME, SERVICE_UUID);

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? Log.e(TAG, "listen() failed", e);

? ? ? ? ? ? }

? ? ? ? ? ? mServerSocket = tmp;

? ? ? ? }

? ? ? ? public void run() {

? ? ? ? ? ? BluetoothSocket socket = null;

? ? ? ? ? ? // 循環(huán)考赛,直到連接成功

? ? ? ? ? ? while (mState != STATE_CONNECTED) {

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? // 這是一個(gè)阻塞調(diào)用 返回成功的連接

? ? ? ? ? ? ? ? ? ? // mServerSocket.close()在另一個(gè)線程中調(diào)用惕澎,可以中止該阻塞

? ? ? ? ? ? ? ? ? ? socket = mServerSocket.accept();

? ? ? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? ? ? Log.e(TAG, "accept() failed", e);

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? // 如果連接被接受

? ? ? ? ? ? ? ? if (socket != null) {

? ? ? ? ? ? ? ? ? ? synchronized (BluetoothChatUtil.this) {

? ? ? ? ? ? ? ? ? ? ? ? switch (mState) {

? ? ? ? ? ? ? ? ? ? ? ? case STATE_LISTEN:

? ? ? ? ? ? ? ? ? ? ? ? case STATE_CONNECTING:

? ? ? ? ? ? ? ? ? ? ? ? ? ? // 正常情況。啟動(dòng)ConnectedThread颜骤。

? ? ? ? ? ? ? ? ? ? ? ? ? ? connected(socket, socket.getRemoteDevice());

? ? ? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? ? ? case STATE_NONE:

? ? ? ? ? ? ? ? ? ? ? ? case STATE_CONNECTED:

? ? ? ? ? ? ? ? ? ? ? ? ? ? // 沒有準(zhǔn)備或已連接唧喉。新連接終止。

? ? ? ? ? ? ? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? socket.close();

? ? ? ? ? ? ? ? ? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Log.e(TAG, "Could not close unwanted socket", e);

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? if (D) Log.i(TAG, "END mAcceptThread");

? ? ? ? }

? ? ? ? public void cancel() {

? ? ? ? ? ? if (D) Log.d(TAG, "cancel " + this);

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? mServerSocket.close();

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? Log.e(TAG, "close() of server failed", e);

? ? ? ? ? ? }

? ? ? ? }

? ? }

mServerSocket通過accept()等待客戶端的連接(阻塞)忍抽,直到連接成功或失敗八孝。

3 客戶端

客戶端主要用來創(chuàng)建RFCOMM socket,并連接服務(wù)端鸠项。

先掃描周圍的藍(lán)牙設(shè)備干跛,如果掃描到指定設(shè)備則進(jìn)行連接。mBlthChatUtil.connect(scanDevice)連接到設(shè)備祟绊,

連接過程主要在ConnectThread線程中進(jìn)行楼入,先創(chuàng)建socket,方式有兩種牧抽,

如下代碼中是安全的(createRfcommSocketToServiceRecord)嘉熊。另一種不安全連接對(duì)應(yīng)的函數(shù)是createInsecureRfcommSocketToServiceRecord。

private class ConnectThread extends Thread {

? ? ? ? private BluetoothSocket mmSocket;

? ? ? ? private final BluetoothDevice mmDevice;

? ? ? ? public ConnectThread(BluetoothDevice device) {

? ? ? ? ? ? mmDevice = device;

? ? ? ? ? ? BluetoothSocket tmp = null;

? ? ? ? ? ? // 得到一個(gè)bluetoothsocket

? ? ? ? ? ? try {

? ? ? ? ? ? mmSocket = device.createRfcommSocketToServiceRecord

? ? ? ? ? ? (SERVICE_UUID);

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? Log.e(TAG, "create() failed", e);

? ? ? ? ? ? ? ? mmSocket = null;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? public void run() {

? ? ? ? ? ? Log.i(TAG, "BEGIN mConnectThread");

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? // socket 連接,該調(diào)用會(huì)阻塞阎姥,直到連接成功或失敗

? ? ? ? ? ? ? ? mmSocket.connect();

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? connectionFailed();

? ? ? ? ? ? ? ? try {//關(guān)閉這個(gè)socket

? ? ? ? ? ? ? ? ? ? mmSocket.close();

? ? ? ? ? ? ? ? } catch (IOException e2) {

? ? ? ? ? ? ? ? ? ? e2.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return;

? ? ? ? ? ? }

? ? ? ? ? ? // 啟動(dòng)連接線程

? ? ? ? ? ? connected(mmSocket, mmDevice);

? ? ? ? }

? ? ? ? public void cancel() {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? mmSocket.close();

? ? ? ? ? ? } catch (IOException e) {

? ? ? ? ? ? ? ? Log.e(TAG, "close() of connect socket failed", e);

? ? ? ? ? ? }

? ? ? ? }

? ? }

接著客戶端socket主動(dòng)連接服務(wù)端记舆。連接過程中會(huì)自動(dòng)進(jìn)行配對(duì),需要雙方同意才可以連接成功呼巴。

4 數(shù)據(jù)傳輸

客戶端與服務(wù)端連接成功后都會(huì)調(diào)用connected(mmSocket, mmDevice)泽腮,創(chuàng)建一個(gè)ConnectedThread線程()。

該線程主要用來接收和發(fā)送數(shù)據(jù)衣赶≌锷蓿客戶端和服務(wù)端處理方式一樣。該線程通過socket獲得輸入輸出流府瞄。

private ?InputStream mmInStream = socket.getInputStream();

private ?OutputStream mmOutStream =socket.getOutputStream();

發(fā)送數(shù)據(jù)

public void write(byte[] buffer) {

? ? try {

? ? ? ? mmOutStream.write(buffer);

? ? ? ? // 分享發(fā)送的信息到Activity

? ? ? ? mHandler.obtainMessage(MESSAGE_WRITE, -1, -1, buffer)

? ? ? ? ? ? ? ? .sendToTarget();

? ? } catch (IOException e) {

? ? ? ? Log.e(TAG, "Exception during write", e);

? ? }

}

接收數(shù)據(jù)

線程循環(huán)進(jìn)行接收數(shù)據(jù)碧磅。

public void run() {

? ? // 監(jiān)聽輸入流

? ? while (true) {

? ? ? ? try {

? ? ? ? ? ? byte[] buffer = new byte[1024];

? ? ? ? ? ? // 讀取輸入流

? ? ? ? ? ? int bytes = mmInStream.read(buffer);

? ? ? ? ? ? // 發(fā)送獲得的字節(jié)的ui activity

? ? ? ? ? ? Message msg = mHandler.obtainMessage(MESSAGE_READ);

? ? ? ? ? ? Bundle bundle = new Bundle();

? ? ? ? ? ? bundle.putByteArray(READ_MSG, buffer);

? ? ? ? ? ? msg.setData(bundle);

? ? ? ? ? ? mHandler.sendMessage(msg);? ? ? ? ?

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? Log.e(TAG, "disconnected", e);

? ? ? ? ? ? ? ? connectionLost();

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }

? ? ? ? }

? }

---------------------

作者:zpengyong

來源:CSDN

原文:https://blog.csdn.net/VNanyesheshou/article/details/51554852

版權(quán)聲明:本文為博主原創(chuàng)文章碘箍,轉(zhuǎn)載請(qǐng)附上博文鏈接!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鲸郊,一起剝皮案震驚了整個(gè)濱河市丰榴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秆撮,老刑警劉巖四濒,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異职辨,居然都是意外死亡盗蟆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門舒裤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喳资,“玉大人,你說我怎么就攤上這事腾供∑偷耍” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵伴鳖,是天一觀的道長宏赘。 經(jīng)常有香客問我,道長黎侈,這世上最難降的妖魔是什么察署? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮峻汉,結(jié)果婚禮上贴汪,老公的妹妹穿的比我還像新娘。我一直安慰自己休吠,他們只是感情好扳埂,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘤礁,像睡著了一般阳懂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柜思,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天岩调,我揣著相機(jī)與錄音,去河邊找鬼赡盘。 笑死号枕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的陨享。 我是一名探鬼主播葱淳,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼钝腺,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了赞厕?” 一聲冷哼從身側(cè)響起艳狐,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎皿桑,沒想到半個(gè)月后僵驰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唁毒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了星爪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浆西。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顽腾,靈堂內(nèi)的尸體忽然破棺而出近零,到底是詐尸還是另有隱情,我是刑警寧澤抄肖,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布久信,位于F島的核電站,受9級(jí)特大地震影響漓摩,放射性物質(zhì)發(fā)生泄漏裙士。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一管毙、第九天 我趴在偏房一處隱蔽的房頂上張望腿椎。 院中可真熱鬧,春花似錦夭咬、人聲如沸啃炸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽南用。三九已至,卻和暖如春掏湾,著一層夾襖步出監(jiān)牢的瞬間裹虫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國打工融击, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恒界,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓砚嘴,卻偏偏與公主長得像十酣,于是被迫代替她去往敵國和親涩拙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

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

  • 最近項(xiàng)目使用藍(lán)牙耸采,之前并沒有接觸兴泥,還是發(fā)現(xiàn)了很多坑,查閱了很多資料虾宇,說的迷迷糊糊搓彻,今天特查看官方文檔。 說下遇到的...
    King9527閱讀 1,797評(píng)論 0 1
  • 話不多說我們直接步入正題嘱朽,下面是一個(gè)思維導(dǎo)圖: 首先我們先與另外兩種通信方案進(jìn)行一下對(duì)比: 配對(duì)流程: 1. ...
    自己_d7eb閱讀 7,931評(píng)論 0 1
  • Android平臺(tái)支持藍(lán)牙網(wǎng)絡(luò)協(xié)議棧旭贬,實(shí)現(xiàn)藍(lán)牙設(shè)備之間數(shù)據(jù)的無線傳輸。本文檔描述了怎樣利用android平臺(tái)提供的...
    Camming閱讀 3,324評(píng)論 0 3
  • 一. 藍(lán)牙權(quán)限 二.配對(duì) 代碼走起~~ 會(huì)順帶加些常用的知識(shí)點(diǎn)搪泳。簡書這個(gè)貼代碼稀轨,格式都沒了,將就的看吧岸军,需...
    未丑閱讀 4,808評(píng)論 0 1
  • 目標(biāo):要在4月和先生好好的相處奋刽,發(fā)掘自己溫柔的一面;培養(yǎng)一位財(cái)務(wù)人員達(dá)到會(huì)計(jì)的水平艰赞;幫助兒子更加的自信佣谐,養(yǎng)成好的學(xué)...
    錦上添花_1155閱讀 94評(píng)論 0 0