Android實(shí)踐 -- Android藍(lán)牙設(shè)置連接

藍(lán)牙開(kāi)發(fā)相關(guān)

使用Android Bluetooth APIs將設(shè)備通過(guò)藍(lán)牙連接并通信凫岖,設(shè)置藍(lán)牙,查找藍(lán)牙設(shè)備痛单,配對(duì)藍(lán)牙設(shè)備
連接并傳輸數(shù)據(jù)塑顺,以下是Android系統(tǒng)提供的藍(lán)牙相關(guān)的類和接口

  • BluetoothAdapter
  • BluetoothDevice
  • BluetoothSocket
  • BluetoothServerSocket
  • BluetoothClass
  • BluetoothProfile
  • BluetoothHeadset
  • BluetoothA2dp
  • BluetoothHealth
  • BluetoothHealthCallback
  • BluetoothHealthAppConfiguration
  • BluetoothProfile.ServiceListener

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

使用藍(lán)牙功能,需要在AndroidManifest.xml中聲明藍(lán)牙相關(guān)的權(quán)限

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

建立藍(lán)牙

  • 初始化連接

在通過(guò)藍(lán)牙通信之前畅哑,需要先確定設(shè)備是否支持藍(lán)牙功能肴楷,先初始化一個(gè)BluetoothAdapter的實(shí)例,
BluetoothAdapter提供了一個(gè)靜態(tài)方法getDefaultAdapter()來(lái)獲得BluetoothAdapter的實(shí)例

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
    // 設(shè)備不支持藍(lán)牙功能
}
  • 打開(kāi)藍(lán)牙
    下一步就是打開(kāi)藍(lán)牙荠呐,調(diào)用isEnabled()方法檢查藍(lán)牙功能是否已經(jīng)打開(kāi)赛蔫,返回true說(shuō)明藍(lán)牙已開(kāi)啟,
    返回false說(shuō)明藍(lán)牙功能未開(kāi)啟泥张,開(kāi)啟藍(lán)牙可以通過(guò)發(fā)送廣播ACTION_REQUEST_ENABLE,也可以通過(guò)方法
    enable()直接打開(kāi)呵恢,這兩種方法都會(huì)有藍(lán)牙權(quán)限的提示,選擇允許媚创,否則無(wú)法打開(kāi)藍(lán)牙
if (!mBluetoothAdapter.isEnabled()) {
  Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
mBluetoothAdapter.enable();

在應(yīng)用中可以設(shè)置藍(lán)牙的狀態(tài)的監(jiān)聽(tīng)ACTION_STATE_CHANGED廣播渗钉,當(dāng)藍(lán)牙的狀態(tài)的變化時(shí),就會(huì)觸發(fā)這個(gè)
廣播,接收到這個(gè)廣播之后鳄橘,在intent中可以獲得當(dāng)前藍(lán)牙的狀態(tài)和前一次的藍(lán)牙的狀態(tài)

int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);

藍(lán)牙的狀態(tài)值有:

int STATE_OFF = 10;//藍(lán)牙關(guān)閉狀態(tài)
int STATE_TURNING_ON = 11;//藍(lán)牙正在打開(kāi)
int STATE_ON = 12;//藍(lán)牙打開(kāi)狀態(tài)
int STATE_TURNING_OFF = 13;//藍(lán)牙正在關(guān)閉

查找藍(lán)牙設(shè)備

打開(kāi)藍(lán)牙之后声离,下一步就是查找可以使用的藍(lán)牙設(shè)備,藍(lán)牙的api中也提供了相關(guān)的接口,由于藍(lán)牙的掃描
是一個(gè)耗電的操作瘫怜,不用時(shí)計(jì)時(shí)取消掃描藍(lán)牙

mBluetoothAdapter.isDiscovering(); //監(jiān)測(cè)藍(lán)牙是否正在掃描
mBluetoothAdapter.startDiscovery();//開(kāi)始掃描
mBluetoothAdapter.cancelDiscovery();//取消掃描

為了發(fā)現(xiàn)可用的藍(lán)牙的設(shè)備术徊,必須在應(yīng)用中注冊(cè)ACTION_FOUND的廣播,調(diào)用方法startDiscovery()如果查找到可用的
設(shè)備會(huì)觸發(fā)這個(gè)廣播鲸湃,這個(gè)廣播中帶有EXTRA_DEVICE的設(shè)備信息可以通過(guò)下面的方法獲得設(shè)備的信息

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            Log.e("tag","device name: "+device.getName()+" address: "+device.getAddress());
        }
    }
};
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
  • 查詢已經(jīng)配對(duì)的設(shè)備列表
    在進(jìn)行查找之前赠涮,可以先獲得之前已經(jīng)配對(duì)成功的藍(lán)牙設(shè)備的列表,可以調(diào)用方法getBondedDevices()獲得
    已經(jīng)配對(duì)的藍(lán)牙設(shè)備列表
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
  for (BluetoothDevice device : pairedDevices) {
      //可以獲得已經(jīng)配對(duì)的藍(lán)牙的名稱和地址
      Log.e("tag","device name: "+device.getName()+" address: "+device.getAddress());
  }
}
  • 是其他設(shè)備可見(jiàn)
    上面講的都是發(fā)現(xiàn)其他的藍(lán)牙設(shè)備暗挑,也可以設(shè)置設(shè)備本身是否對(duì)其他設(shè)備可見(jiàn)世囊,通過(guò)發(fā)送ACTION_REQUEST_DISCOVERABLE
    的廣播,會(huì)調(diào)用系統(tǒng)的方法窿祥,還可以設(shè)置多長(zhǎng)時(shí)間內(nèi)是可見(jiàn)的,在intent中設(shè)置EXTRA_DISCOVERABLE_DURATION,最大值是
    3600s株憾,超過(guò)3600s會(huì)設(shè)置為120s,點(diǎn)擊允許會(huì)回調(diào)onActivityResult()方法
//設(shè)置設(shè)備在300s內(nèi)是可見(jiàn)的
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);

如果沒(méi)有打開(kāi)藍(lán)牙晒衩,執(zhí)行上面的操作會(huì)自動(dòng)打開(kāi)藍(lán)牙

可以通過(guò)監(jiān)聽(tīng)ACTION_SCAN_MODE_CHANGED廣播嗤瞎,可以在intent中根據(jù)EXTRA_SCAN_MODE的參數(shù)獲得當(dāng)前設(shè)備的SCAN MODE
有一些幾種模式

int SCAN_MODE_NONE = 20;//這個(gè)模式不能被發(fā)現(xiàn)也不能連接
int SCAN_MODE_CONNECTABLE = 21;//這個(gè)模式不能被掃描到,但是可以連接
int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;//這個(gè)模式可以被發(fā)現(xiàn)听系,也能被連接

藍(lán)牙的連接

  • Server 端
    通過(guò)BluetoothAdapterlistenUsingRfcommWithServiceRecord(String, UUID)方法獲得BluetoothServerSocket對(duì)象
    的實(shí)例贝奇,然后socket就會(huì)通過(guò)accept()監(jiān)聽(tīng)客戶端的連接的狀態(tài)
private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;
    public AcceptThread() {
        BluetoothServerSocket tmp = null;
        try {
            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) { }
        mmServerSocket = tmp;
    }

    public void run() {
        BluetoothSocket socket = null;
        // 在后臺(tái)一直監(jiān)聽(tīng)客戶端的請(qǐng)求
        while (true) {
            try {
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                break;
            }
            if (socket != null) {
                mmServerSocket.close();
                break;
            }
        }
    }
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) { }
    }
}
  • Client 端
    使用BluetoothDevicecreateRfcommSocketToServiceRecord(UUID)方法獲得BluetoothSocket對(duì)象的實(shí)例
    然后調(diào)用connect()方法,這時(shí)server端會(huì)監(jiān)聽(tīng)到這個(gè)請(qǐng)求靠胜,之后就建立連接掉瞳,然后就可以進(jìn)行通信了
private class ConnectThread extends Thread {
  private final BluetoothSocket mmSocket;
  private final BluetoothDevice mmDevice;
  public ConnectThread(BluetoothDevice device) {
      BluetoothSocket tmp = null;
      mmDevice = device;
      try {
          tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
      } catch (IOException e) { }
      mmSocket = tmp;
  }

  public void run() {
      mBluetoothAdapter.cancelDiscovery();

      try {
          mmSocket.connect();
      } catch (IOException connectException) {
          try {
              mmSocket.close();
          } catch (IOException closeException) { }
          return;
      }
  }
  public void cancel() {
      try {
          mmSocket.close();
      } catch (IOException e) { }
  }
}

連接的監(jiān)聽(tīng)

可以通過(guò)注冊(cè)廣播監(jiān)聽(tīng)藍(lán)牙設(shè)備連接的狀態(tài)變化,廣播BluetoothDevice.ACTION_BOND_STATE_CHANGED,監(jiān)聽(tīng)到這個(gè)廣播之后浪漠,可以
在intent中獲得連接的狀態(tài)

int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);

設(shè)備連接的狀態(tài)值

int BOND_NONE = 10;//沒(méi)有連接  
int BOND_BONDING = 11;//正在連接  
int BOND_BONDED = 12;//已經(jīng)建立連接  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陕习,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子址愿,更是在濱河造成了極大的恐慌该镣,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件响谓,死亡現(xiàn)場(chǎng)離奇詭異损合,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)娘纷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)嫁审,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赖晶,你說(shuō)我怎么就攤上這事律适。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵擦耀,是天一觀的道長(zhǎng)棉圈。 經(jīng)常有香客問(wèn)我涩堤,道長(zhǎng)眷蜓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任胎围,我火速辦了婚禮吁系,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘白魂。我一直安慰自己汽纤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布福荸。 她就那樣靜靜地躺著蕴坪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敬锐。 梳的紋絲不亂的頭發(fā)上背传,一...
    開(kāi)封第一講書(shū)人閱讀 52,785評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音台夺,去河邊找鬼径玖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛颤介,可吹牛的內(nèi)容都是我干的梳星。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼滚朵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼冤灾!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起辕近,我...
    開(kāi)封第一講書(shū)人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瞳购,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后亏推,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體学赛,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年吞杭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盏浇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芽狗,死狀恐怖绢掰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤滴劲,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布攻晒,位于F島的核電站,受9級(jí)特大地震影響班挖,放射性物質(zhì)發(fā)生泄漏鲁捏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一萧芙、第九天 我趴在偏房一處隱蔽的房頂上張望给梅。 院中可真熱鬧,春花似錦双揪、人聲如沸动羽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)运吓。三九已至,卻和暖如春疯趟,著一層夾襖步出監(jiān)牢的瞬間拘哨,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工迅办, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宅静,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓站欺,卻偏偏與公主長(zhǎng)得像姨夹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矾策,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

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