Android藍(lán)牙的開(kāi)啟和搜索設(shè)備功能開(kāi)發(fā)實(shí)例
概覽
Android 平臺(tái)包含藍(lán)牙網(wǎng)絡(luò)堆棧支持,此支持能讓設(shè)備以無(wú)線(xiàn)方式與其他藍(lán)牙設(shè)備交換數(shù)據(jù)。應(yīng)用框架提供通過(guò) Android Bluetooth API 訪(fǎng)問(wèn)藍(lán)牙功能的權(quán)限。這些 API 允許應(yīng)用以無(wú)線(xiàn)方式連接到其他藍(lán)牙設(shè)備,從而實(shí)現(xiàn)點(diǎn)到點(diǎn)和多點(diǎn)無(wú)線(xiàn)功能。
Android 應(yīng)用可通過(guò) Bluetooth API 執(zhí)行以下操作:
- 掃描其他藍(lán)牙設(shè)備
- 查詢(xún)本地藍(lán)牙適配器的配對(duì)藍(lán)牙設(shè)備
- 建立 RFCOMM 通道
- 通過(guò)服務(wù)發(fā)現(xiàn)連接到其他設(shè)備
- 與其他設(shè)備進(jìn)行雙向數(shù)據(jù)傳輸
- 管理多個(gè)連接
本文重點(diǎn)介紹傳統(tǒng)藍(lán)牙。傳統(tǒng)藍(lán)牙適用于較為耗電的操作,其中包括 Android 設(shè)備之間的流式傳輸和通信等。針對(duì)具有低功耗要求的藍(lán)牙設(shè)備,Android 4.3(API 級(jí)別 18)中引入了面向低功耗藍(lán)牙的 API 支持。
為了讓支持藍(lán)牙的設(shè)備能夠在彼此之間傳輸數(shù)據(jù),它們必須先通過(guò)配對(duì)過(guò)程形成通信通道。其中一臺(tái)設(shè)備(可檢測(cè)到的設(shè)備)需將自身設(shè)置為可接收傳入的連接請(qǐng)求。另一臺(tái)設(shè)備會(huì)使用服務(wù)發(fā)現(xiàn)過(guò)程找到此可檢測(cè)到的設(shè)備。在可檢測(cè)到的設(shè)備接受配對(duì)請(qǐng)求后,這兩臺(tái)設(shè)備會(huì)完成綁定過(guò)程,并在此期間交換安全密鑰。二者會(huì)緩存這些密鑰,以供日后使用。完成配對(duì)和綁定過(guò)程后,兩臺(tái)設(shè)備會(huì)交換信息。當(dāng)會(huì)話(huà)完成時(shí),發(fā)起配對(duì)請(qǐng)求的設(shè)備會(huì)發(fā)布已將其鏈接到可檢測(cè)設(shè)備的通道。但是,這兩臺(tái)設(shè)備仍保持綁定狀態(tài),因此在未來(lái)的會(huì)話(huà)期間,只要二者在彼此的范圍內(nèi)且均未移除綁定,便可自動(dòng)重新連接。
設(shè)置藍(lán)牙
藍(lán)牙權(quán)限
如要在應(yīng)用中使用藍(lán)牙功能,必須聲明兩個(gè)權(quán)限。第一個(gè)是 BLUETOOTH
。需要此權(quán)限才能執(zhí)行任何藍(lán)牙通信,例如請(qǐng)求連接、接受連接和傳輸數(shù)據(jù)等。
第二個(gè)必須聲明的權(quán)限是 ACCESS_FINE_LOCATION
。應(yīng)用需要此權(quán)限,因?yàn)樗{(lán)牙掃描可用于收集用戶(hù)的位置信息。此類(lèi)信息可能來(lái)自用戶(hù)自己的設(shè)備,以及在商店和交通設(shè)施等位置使用的藍(lán)牙信標(biāo)。
注意:如果應(yīng)用適配 Android 9(API 級(jí)別 28)或更低版本,則可以聲明 ACCESS_COARSE_LOCATION
權(quán)限而非 ACCESS_FINE_LOCATION
權(quán)限。
如果想讓?xiě)?yīng)用啟動(dòng)設(shè)備發(fā)現(xiàn)或操縱藍(lán)牙設(shè)置,則除了 BLUETOOTH
權(quán)限以外,還必須聲明 BLUETOOTH_ADMIN
權(quán)限。大多數(shù)應(yīng)用只是需利用此權(quán)限發(fā)現(xiàn)本地藍(lán)牙設(shè)備。除非應(yīng)用是根據(jù)用戶(hù)請(qǐng)求修改藍(lán)牙設(shè)置的“超級(jí)管理員”,否則不應(yīng)使用此權(quán)限所授予的其他功能。
在應(yīng)用清單文件中聲明藍(lán)牙權(quán)限。例如:
<manifest ... > <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- If your app targets Android 9 or lower, you can declare ACCESS_COARSE_LOCATION instead. --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... </manifest>
設(shè)置藍(lán)牙
需驗(yàn)證設(shè)備支持藍(lán)牙,確保在此情況下啟用該功能,這樣你的應(yīng)用才能通過(guò)藍(lán)牙進(jìn)行通信。
如果設(shè)備不支持藍(lán)牙,則應(yīng)正常停用任何藍(lán)牙功能。如果設(shè)備支持藍(lán)牙但已停用此功能,則可以請(qǐng)求用戶(hù)在不離開(kāi)應(yīng)用的同時(shí)啟用藍(lán)牙。借助 BluetoothAdapter
,可以分兩步完成此設(shè)置:
獲取 BluetoothAdapter
所有藍(lán)牙 Activity
都需要 BluetoothAdapter
。如要獲取 BluetoothAdapter
,請(qǐng)調(diào)用靜態(tài)的 getDefaultAdapter()
方法。此方法會(huì)返回一個(gè) BluetoothAdapter
對(duì)象,表示設(shè)備自身的藍(lán)牙適配器(藍(lán)牙無(wú)線(xiàn)裝置)。整個(gè)系統(tǒng)只有一個(gè)藍(lán)牙適配器,并且應(yīng)用可使用此對(duì)象與之進(jìn)行交互。如果 getDefaultAdapter()
返回 null
,則表示設(shè)備不支持藍(lán)牙。例如:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { // Device doesn't support Bluetooth }
啟用藍(lán)牙下一步,需要確保已啟用藍(lán)牙。調(diào)用 isEnabled()
,以檢查當(dāng)前是否已啟用藍(lán)牙。如果此方法返回 false
,則表示藍(lán)牙處于停用狀態(tài)。如要請(qǐng)求啟用藍(lán)牙,請(qǐng)調(diào)用 startActivityForResult()
,從而傳入一個(gè) ACTION_REQUEST_ENABLE
Intent 操作。此調(diào)用會(huì)發(fā)出通過(guò)系統(tǒng)設(shè)置啟用藍(lán)牙的請(qǐng)求(無(wú)需停止應(yīng)用)。例如:
private static final int REQUEST_ENABLE_BT = 10; if (!bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_ENABLE_BT && resultCode == RESULT_OK) { Log.e(TAG, "onActivityResult: enable bluetooth!!!!!!"); } }
如圖所示,系統(tǒng)將顯示對(duì)話(huà)框,請(qǐng)求用戶(hù)允許啟用藍(lán)牙。如果用戶(hù)響應(yīng)“Yes”,系統(tǒng)會(huì)開(kāi)始啟用藍(lán)牙,并在該進(jìn)程完成(或失?。┖髮⒔裹c(diǎn)返回應(yīng)用。
傳遞給 startActivityForResult()
的 REQUEST_ENABLE_BT
常量為局部定義的整型數(shù)(必須大于 0)。系統(tǒng)會(huì)以 onActivityResult()
實(shí)現(xiàn)中的 requestCode
參數(shù)形式,傳回該常量。
如果成功啟用藍(lán)牙,Activity
會(huì)在 onActivityResult()
回調(diào)中收到 RESULT_OK
結(jié)果代碼。如果由于某個(gè)錯(cuò)誤(或用戶(hù)響應(yīng)“No”)未成功啟用藍(lán)牙,則結(jié)果代碼為 RESULT_CANCELED
。
你的應(yīng)用還可選擇偵聽(tīng) ACTION_STATE_CHANGED
廣播 Intent,每當(dāng)藍(lán)牙狀態(tài)發(fā)生變化時(shí),系統(tǒng)都會(huì)廣播此 Intent。此廣播包含額外字段 EXTRA_STATE 和 EXTRA_PREVIOUS_STATE
,二者分別包含新的和舊的藍(lán)牙狀態(tài)。這些額外字段可能為以下值:STATE_TURNING_ON
、STATE_ON
、STATE_TURNING_OFF
和 STATE_OFF
。如果你的應(yīng)用需檢測(cè)對(duì)藍(lán)牙狀態(tài)所做的運(yùn)行時(shí)更改,請(qǐng)偵聽(tīng)此廣播。
注意:?jiǎn)⒂每蓹z測(cè)性即可自動(dòng)啟用藍(lán)牙。如果你計(jì)劃在執(zhí)行藍(lán)牙 Activity 之前一直啟用設(shè)備的可檢測(cè)性。
查找設(shè)備
利用 BluetoothAdapter
,你可以通過(guò)設(shè)備發(fā)現(xiàn)或查詢(xún)配對(duì)設(shè)備的列表來(lái)查找遠(yuǎn)程藍(lán)牙設(shè)備。
設(shè)備發(fā)現(xiàn)是一個(gè)掃描過(guò)程,它會(huì)搜索局部區(qū)域內(nèi)已啟用藍(lán)牙功能的設(shè)備,并請(qǐng)求與每臺(tái)設(shè)備相關(guān)的某些信息。此過(guò)程有時(shí)也被稱(chēng)為發(fā)現(xiàn)、查詢(xún)或掃描。但是,只有在當(dāng)下接受信息請(qǐng)求時(shí),附近區(qū)域的藍(lán)牙設(shè)備才會(huì)通過(guò)啟用可檢測(cè)性響應(yīng)發(fā)現(xiàn)請(qǐng)求。如果設(shè)備已啟用可檢測(cè)性,它會(huì)通過(guò)共享一些信息(例如設(shè)備的名稱(chēng)、類(lèi)及其唯一的 MAC 地址)來(lái)響應(yīng)發(fā)現(xiàn)請(qǐng)求。借助此類(lèi)信息,執(zhí)行發(fā)現(xiàn)過(guò)程的設(shè)備可選擇發(fā)起對(duì)已檢測(cè)到設(shè)備的連接。
在首次與遠(yuǎn)程設(shè)備建立連接后,系統(tǒng)會(huì)自動(dòng)向用戶(hù)顯示配對(duì)請(qǐng)求。當(dāng)設(shè)備完成配對(duì)后,系統(tǒng)會(huì)保存關(guān)于該設(shè)備的基本信息(例如設(shè)備的名稱(chēng)、類(lèi)和 MAC 地址),并且可使用 Bluetooth API 讀取這些信息。借助遠(yuǎn)程設(shè)備的已知 MAC 地址,你可以隨時(shí)向其發(fā)起連接,而無(wú)需執(zhí)行發(fā)現(xiàn)操作(假定該設(shè)備仍處于有效范圍內(nèi))。
請(qǐng)注意,被配對(duì)與被連接之間存在區(qū)別:
被配對(duì)是指兩臺(tái)設(shè)備知曉彼此的存在,具有可用于身份驗(yàn)證的共享鏈路密鑰,并且能夠與彼此建立加密連接。被連接是指設(shè)備當(dāng)前共享一個(gè) RFCOMM
通道,并且能夠向彼此傳輸數(shù)據(jù)。當(dāng)前的 Android Bluetooth API 要求規(guī)定,只有先對(duì)設(shè)備進(jìn)行配對(duì),然后才能建立 RFCOMM
連接。在使用 Bluetooth API 發(fā)起加密連接時(shí),系統(tǒng)會(huì)自動(dòng)執(zhí)行配對(duì)。
以下部分介紹如何查找已配對(duì)的設(shè)備,或使用設(shè)備發(fā)現(xiàn)功能來(lái)發(fā)現(xiàn)新設(shè)備。
注意:Android 設(shè)備默認(rèn)處于不可檢測(cè)到狀態(tài)。用戶(hù)可通過(guò)系統(tǒng)設(shè)置將設(shè)備設(shè)為在有限的時(shí)間內(nèi)處于可檢測(cè)到狀態(tài),或者,應(yīng)用可請(qǐng)求用戶(hù)在不離開(kāi)應(yīng)用的同時(shí)啟用可檢測(cè)性。
查詢(xún)已配對(duì)設(shè)備
在執(zhí)行設(shè)備發(fā)現(xiàn)之前,必須查詢(xún)已配對(duì)的設(shè)備集,以了解所需的設(shè)備是否處于已檢測(cè)到狀態(tài)。為此,請(qǐng)調(diào)用 getBondedDevices()
。此方法會(huì)返回一組表示已配對(duì)設(shè)備的 BluetoothDevice 對(duì)象。例如,可以查詢(xún)所有已配對(duì)設(shè)備,并獲取每臺(tái)設(shè)備的名稱(chēng)和 MAC 地址,如以下代碼段所示:
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { // There are paired devices. Get the name and address of each paired device. for (BluetoothDevice device : pairedDevices) { String deviceName = device.getName(); String deviceHardwareAddress = device.getAddress(); // MAC address } }
注意:執(zhí)行設(shè)備發(fā)現(xiàn)將消耗藍(lán)牙適配器的大量資源。在找到要連接的設(shè)備后,請(qǐng)務(wù)必使用 cancelDiscovery()
停止發(fā)現(xiàn),然后再?lài)L試連接。此外,不應(yīng)在連接到設(shè)備的情況下執(zhí)行設(shè)備發(fā)現(xiàn),因?yàn)榘l(fā)現(xiàn)過(guò)程會(huì)大幅減少可供任何現(xiàn)有連接使用的帶寬。
發(fā)現(xiàn)設(shè)備
如要開(kāi)始發(fā)現(xiàn)設(shè)備,只需調(diào)用 startDiscovery()
。該進(jìn)程為異步操作,并且會(huì)返回一個(gè)布爾值,指示發(fā)現(xiàn)進(jìn)程是否已成功啟動(dòng)。發(fā)現(xiàn)進(jìn)程通常包含約 12 秒鐘的查詢(xún)掃描,隨后會(huì)對(duì)發(fā)現(xiàn)的每臺(tái)設(shè)備進(jìn)行頁(yè)面掃描,以檢索其藍(lán)牙名稱(chēng)。
應(yīng)用必須針對(duì) ACTION_FOUND
Intent 注冊(cè)一個(gè) BroadcastReceiver
,以便接收每臺(tái)發(fā)現(xiàn)的設(shè)備的相關(guān)信息。系統(tǒng)會(huì)為每臺(tái)設(shè)備廣播此 Intent。Intent 包含額外字段 EXTRA_DEVICE
和 EXTRA_CLASS
,二者又分別包含 BluetoothDevice
和 BluetoothClass
。以下代碼段展示如何在發(fā)現(xiàn)設(shè)備時(shí)通過(guò)注冊(cè)來(lái)處理廣播:
@Override protected void onCreate(Bundle savedInstanceState) { ... // Register for broadcasts when a device is discovered. IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(receiver, filter); Button btnSearch = findViewById(R.id.btn_search); btnSearch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //開(kāi)始搜索 bluetoothAdapter.startDiscovery(); } }); } // Create a BroadcastReceiver for ACTION_FOUND. private final BroadcastReceiver receiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Discovery has found a device. Get the BluetoothDevice // object and its info from the Intent. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String deviceName = device.getName(); String deviceHardwareAddress = device.getAddress(); // MAC address } } }; @Override protected void onDestroy() { super.onDestroy(); ... // Don't forget to unregister the ACTION_FOUND receiver. unregisterReceiver(receiver); }
啟用可檢測(cè)性
如果希望將本地設(shè)備設(shè)為可被其他設(shè)備檢測(cè)到,請(qǐng)使用 ACTION_REQUEST_DISCOVERABLE
Intent 調(diào)用 startActivityForResult(Intent, int)
。這樣便可發(fā)出啟用系統(tǒng)可檢測(cè)到模式的請(qǐng)求,從而無(wú)需導(dǎo)航至設(shè)置應(yīng)用,避免暫停使用你的應(yīng)用。默認(rèn)情況下,設(shè)備處于可檢測(cè)到模式的時(shí)間為 120 秒(2 分鐘)。通過(guò)添加 EXTRA_DISCOVERABLE_DURATION
Extra
屬性,你可以定義不同的持續(xù)時(shí)間,最高可達(dá) 3600 秒(1 小時(shí))。
以下代碼段將設(shè)備處于可檢測(cè)到模式的時(shí)間設(shè)置為 5 分鐘(300 秒):
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent);
如圖所示,系統(tǒng)將顯示對(duì)話(huà)框,請(qǐng)求用戶(hù)允許將設(shè)備設(shè)為可檢測(cè)到模式。如果用戶(hù)響應(yīng)“Yes”,則設(shè)備會(huì)變?yōu)榭蓹z測(cè)到模式,并在指定時(shí)間內(nèi)保持該模式。然后,你的 Activity 將會(huì)收到對(duì) onActivityResult()
回調(diào)的調(diào)用,其結(jié)果代碼等于設(shè)備可檢測(cè)到的持續(xù)時(shí)間。如果用戶(hù)響應(yīng)“No”或出現(xiàn)錯(cuò)誤,則結(jié)果代碼為 RESULT_CANCELED
。
注意:如果尚未在設(shè)備上啟用藍(lán)牙,則啟用設(shè)備可檢測(cè)性會(huì)自動(dòng)啟用藍(lán)牙。
設(shè)備將在分配的時(shí)間內(nèi)以靜默方式保持可檢測(cè)到模式。如果希望在可檢測(cè)到模式發(fā)生變化時(shí)收到通知,則可以為 ACTION_SCAN_MODE_CHANGED
Intent 注冊(cè) BroadcastReceiver
。此 Intent 將包含額外字段 EXTRA_SCAN_MODE
和 EXTRA_PREVIOUS_SCAN_MODE
,二者分別提供新的和舊的掃描模式。每個(gè) Extra
屬性可能擁有以下值:
SCAN_MODE_CONNECTABLE_DISCOVERABLE
:設(shè)備處于可檢測(cè)到模式。SCAN_MODE_CONNECTABLE
:設(shè)備未處于可檢測(cè)到模式,但仍能收到連接。SCAN_MODE_NONE
:設(shè)備未處于可檢測(cè)到模式,且無(wú)法收到連接。
到此這篇關(guān)于Android藍(lán)牙的開(kāi)啟和搜索設(shè)備功能開(kāi)發(fā)實(shí)例的文章就介紹到這了,更多相關(guān)Android藍(lán)牙的開(kāi)啟和搜索內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳細(xì)介紹Android-Room數(shù)據(jù)庫(kù)的使用
這篇文章主要介紹了詳細(xì)介紹Android-Room數(shù)據(jù)庫(kù)的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03Android基于AdapterViewFlipper實(shí)現(xiàn)的圖片/文字輪播動(dòng)畫(huà)控件
這篇文章主要介紹了Android基于AdapterViewFlipper實(shí)現(xiàn)的圖片/文字輪播動(dòng)畫(huà)控件,幫助大家更好的理解和學(xué)習(xí)使用Android開(kāi)發(fā),感興趣的朋友可以了解下2021-04-04Android實(shí)現(xiàn)下拉刷新的視圖和圖標(biāo)的旋轉(zhuǎn)
本篇文章主要介紹了Android實(shí)現(xiàn)下拉刷新的視圖和圖標(biāo)的旋轉(zhuǎn)的實(shí)例,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03Android實(shí)現(xiàn)粒子中心擴(kuò)散動(dòng)畫(huà)效果
粒子動(dòng)畫(huà)效果相比其他動(dòng)畫(huà)來(lái)說(shuō)是非常復(fù)雜了的,主要涉及三個(gè)方面,粒子初始化、粒子位移、粒子回收等問(wèn)題,本篇將實(shí)現(xiàn)兩種動(dòng)畫(huà)效果,代碼基本相同,只是旋轉(zhuǎn)速度不一樣,需要的朋友可以參考下2024-02-02Android 超詳細(xì)SplashScreen入門(mén)教程
Android 12正式版即將發(fā)布,有一個(gè)非常顯著的視覺(jué)變化就是,Android 12強(qiáng)制給所有的App都增加了SplashScreen的功能。是的,即使你什么都不做,只要你的App安裝到了Android 12手機(jī)上,都會(huì)自動(dòng)擁有這個(gè)新功能2022-03-03OpenGL Shader實(shí)例分析(1)Wave效果
這篇文章主要為大家詳細(xì)介紹了OpenGL Shader實(shí)例分析第一篇,Wave效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02Android Activity啟動(dòng)模式之singleTask實(shí)例詳解
這篇文章主要介紹了Android Activity啟動(dòng)模式之singleTask,結(jié)合實(shí)例形式較為詳細(xì)的分析了singleTask模式的功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-01-01

android 解析json數(shù)據(jù)格式的方法