Android開發之藍芽詳解(一)
一.概述
這篇文章是我學習Android開發官網以及網上一些其他文章總結而來,主要就是為了好好研究一下藍芽開發,看完這篇文章以後,我們就知道了怎樣使用藍芽API完成建立藍芽連線的必要四步:1.開啟藍芽;2.查詢附近已配對或可用的裝置;3.連線裝置;4.裝置間資料交換。由於文章比較長,為了方便大家的學習,所以將文章分為三篇,這是第一篇。
二.基礎
1.API
所有的藍芽API都在android.bluetooth 包下.下面有一些類和介面的摘要,我們需要它們來建立藍芽連線:
BluetoothAdapter
代表本地藍芽介面卡(藍芽無線)。BluetoothAdapter是所有藍芽互動的入口。使用這個類,你能夠發現其他的藍芽裝置,查詢已配對裝置的列表,使用已知的MAC地址來例項化一個BluetoothDevice物件,並且建立一個BluetoothServerSocket物件來監聽與其他裝置的通訊。
BluetoothDevice
代表一個遠端的藍芽裝置。使用這個類通過BluetoothSocket或查詢諸如名稱、地址、類和配對狀態等裝置資訊來請求跟遠端裝置的連線。
BluetoothSocket
代表藍芽socket的介面(類似TCP的Socket)。這是允許一個應用程式跟另一個藍芽裝置通過輸入流和輸出流進行資料交換的連線點。
BluetoothServerSocket
代表一個開啟的監聽傳入請求的服務介面(類似於TCP的ServerSocket)。為了連線兩個Android裝置,一個裝置必須用這個類開啟一個服務介面。當遠端藍芽裝置請求跟本裝置建立連線請求時,BluetoothServerSocket會在連線被接收時返回一個被連線的BluetoothSocket物件。
BluetoothClass
描述了藍芽裝置的一般性特徵和功能。這個類是一個只讀的屬性集,這些屬性定義了裝置的主要和次要裝置類和服務。但是,這個類並不保證描述了裝置所支援的所有的藍芽配置和服務,但是這種對裝置型別的提示是有益的
BluetoothProfile
代表一個藍芽配置的介面。藍芽配置是基於藍芽通訊的裝置間的無線介面規範。一個例子是擴音的配置。更多的配置討論,請看下文的用配置來工作。
BluetoothHeadset
提供對使用藍芽耳機的行動電話的支援。它同時包含了Bluetooth Headset和Hands-Free(v1.5)的配置。
BluetoothA2dp
定義如何把高品質的音訊通過藍芽連線從一個裝置流向另一個裝置。“A2DP”是Advanced Audio Distribution Profile的縮寫。
BluetoothHealth
代表一個健康保健裝置配置的控制藍芽服務的代理。
BluetoothHealthCallback
用於實現BluetoothHealth回撥的抽象類。你必須繼承這個類,並實現它的回撥方法,來接收應用程式的註冊狀態和藍芽通道狀態變化的更新。
BluetoothHealthAppConfiguration
代表藍芽相關的第三方健康保健應用程式所註冊的與遠端藍芽健康保健裝置進行通訊的配置。
BluetoothProfile.ServiceListener
BluetoothProfile IPC客戶端連線或斷開服務的通知介面(它是執行特俗配置的內部服務)。
2.許可權
為了在你的應用程式中使用藍芽功能,至少要宣告兩個藍芽許可權(BLUETOOTH和BLUETOOTH_ADMIN)中的一個。
為了執行任何藍芽通訊(如請求連線、接收連線和傳輸資料),你必須申請BLUETOOTH許可權。
為了啟動裝置發現或維護藍芽設定,你必須申請BLUETOOTH_ADMIN許可權。大多數需要這個許可權的應用程式,僅僅是為能夠發現本地的藍芽裝置。這個許可權所授予的其他能力應該不被使用,除非是電源管理的應用程式,它會在依據使用者的請求來修改藍芽設定。注意:如果你使用了BLUETOOTH_ADMIN許可權,那麼必須要有BLUETOOTH許可權。
在清單檔案中宣告如下許可權:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
3.設定藍芽
在應用程式能夠利用藍芽通道通訊之前,需要確認裝置是否支援藍芽通訊,如果支援,要確保它是可用的。
如果不支援藍芽,那麼你應該有好的禁用所有藍芽功能。如果支援藍芽,但是被禁用的,那麼你要在不離開你的應用程式的情況下,請求使用者啟用藍芽功能,這種設定要使用BluetoothAdapter物件,在以下兩個步驟中完成。
(1)獲得BluetoothAdapter物件
BluetoothAdapter物件是所有藍芽活動都需要的,要獲得這個物件,就要呼叫靜態的getDefaultAdapter()方法。這個方法會返回一個代表裝置自己的藍芽介面卡的BluetoothAdapter物件。整個系統有一個藍芽介面卡,你的應用程式能夠使用這個物件來進行互動。如果getDefaultAdapter()方法返回null,那麼該裝置不支援藍芽,你的處理也要在此結束。例如:
BluetoothAdapter mBluetoothAdapter =BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter ==null){
// 裝置不支援藍芽
}
(2)啟用藍芽功能
接下來,你需要確保藍芽是可用的。呼叫isEnabled()方法來檢查當前藍芽是否可用。如果這個方法返回false,那麼藍芽是被禁用的。要申請啟用藍芽功能,就要呼叫帶有ACTION_REQUEST_ENABLE操作意圖的startActivityForResult()方法。它會給系統設定發一個啟用藍芽功能的請求(不終止你的應用程式)。例如:
if(!mAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(intent, requestCode);
}
這時會顯示一個請求使用者啟用藍芽功能的對話方塊
如果使用者點選允許,那麼系統會開始啟用藍芽功能,完成啟動過程(有可能失敗),焦點會返回給你的應用程式。傳遞給startActivityForResult()方法的requestCode是一個你的應用程式中定義的整數(它必須大於0),系統會把它作為引數返回到你的onActivityResult()回撥實現中。
如果藍芽功能啟用成功,你的Activity會在onActivityResult()回撥中接收到RESULT_OK結果,如果藍芽沒有被啟動(或者使用者響應了拒絕),那麼該結果編碼是RESULT_CANCELED。
可選地,你的應用程式還可以監聽ACTION_STATE_CHANGED廣播Intent,無論藍芽狀態何時改變,系統都會廣播這個Intent。這個廣播包含的附加欄位EXTRA_STATE和EXTRA_PREVIOUS_STATE中分別指明瞭新的和舊的藍芽狀態。這些附加欄位中可能的值是:STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFF和STATE_OFF。監聽這個廣播對於在應用程式執行時檢測藍芽的狀態是有用的。
提示:啟用可發現能力會自動啟動藍芽功能。如果你計劃在執行藍芽活動之前,要始終啟用裝置的可發現機制,就可以跳過上面的步驟,詳細請參考下文“啟用藍芽可發現”。
到此,我們先給出一個例子,讓大家理解一下:
我們設定了四個按鈕,分別用於判斷是否支援藍芽,藍芽是否開啟,開啟藍芽,關閉藍芽,由於使用的是模擬器,所以我們可以看到實驗結果是當前裝置不支援藍芽,並且藍芽未開啟,點選後面兩個按鈕沒反應,如果是在真是裝置上,我們可以進行開啟藍芽和關閉藍芽的操作,大家下來可以試一試,下面給出程式碼:
/**
* Created by lxn on 2016/3/4.
* 藍芽管理類
*/
public class BluetoothController {
private BluetoothAdapter mAdapter;
public BluetoothController(){
mAdapter = BluetoothAdapter.getDefaultAdapter();
}
/**
* 判斷當前裝置是否支援藍芽
* @return
*/
public boolean isSupportBluetooth(){
if(mAdapter!=null){
return true;
}
return false;
}
/**
* 獲取藍芽的狀態
* @return
*/
public boolean getBluetoothStatus(){
if(mAdapter!=null){
return mAdapter.isEnabled();
}
return false;
}
/**
* 開啟藍芽
* @param activity
* @param requestCode
*/
public void turnOnBluetooth(Activity activity,int requestCode){
if(mAdapter!=null&&!mAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(intent, requestCode);
}
}
/**
* 關閉藍芽
*/
public void turnOffBluetooth(){
if(mAdapter!=null&&mAdapter.isEnabled()) {
mAdapter.disable();
}
}
}
public class MainActivity extends AppCompatActivity {
public static final int REQUESTCODE_OPEN = 1;
private BluetoothController mController = new BluetoothController();
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 1);
switch (state) {
case BluetoothAdapter.STATE_OFF:
Toast.makeText(MainActivity.this, "藍芽已關閉", Toast.LENGTH_SHORT).show();
break;
case BluetoothAdapter.STATE_ON:
Toast.makeText(MainActivity.this, "藍芽已開啟", Toast.LENGTH_SHORT).show();
break;
case BluetoothAdapter.STATE_TURNING_ON:
Toast.makeText(MainActivity.this, "正在開啟藍芽", Toast.LENGTH_SHORT).show();
break;
case BluetoothAdapter.STATE_TURNING_OFF:
Toast.makeText(MainActivity.this, "正在關閉藍芽", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(MainActivity.this, "未知狀態", Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(receiver, filter);
}
public void click(View view) {
switch (view.getId()) {
case R.id.btnIsSupport:
boolean flag = mController.isSupportBluetooth();
Toast.makeText(this, "flag = " + flag, Toast.LENGTH_SHORT).show();
break;
case R.id.btnIsTurnOn:
boolean isTurnOn = mController.getBluetoothStatus();
Toast.makeText(this, "isTurnOn" + isTurnOn, Toast.LENGTH_SHORT).show();
break;
case R.id.btnTurnOn:
mController.turnOnBluetooth(this, REQUESTCODE_OPEN);
break;
case R.id.btnTrunOff:
mController.turnOffBluetooth();
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK){
Toast.makeText(this, "終於打開了", Toast.LENGTH_SHORT).show();
}
}
}
4.查詢裝置
使用BluetoothAdapter物件,能夠通過裝置發現或查詢已配對的裝置列表來找到遠端的藍芽裝置。
裝置發現是一個掃描過程,該過程搜尋本地區域內可用的藍芽裝置,然後請求一些彼此相關的一些資訊(這個過程被叫做“發現”、“查詢”或“掃描”)。但是,本地區域內的藍芽裝置只有在它們也啟用了可發現功能時,才會響應發現請求。如果一個裝置是可發現的,那麼它會通過共享某些資訊(如裝置名稱、類別和唯一的MAC地址)來響應發現請求。使用這些資訊,執行發現處理的裝置能夠有選擇的初始化跟被發現裝置的連線。
一旦跟遠端的裝置建立的首次連線,配對請求就會自動的被展現給使用者。當裝置完成配對,相關裝置的基本資訊(如裝置名稱、類別和MAC地址)就會被儲存,並能夠使用藍芽API來讀取。使用已知的遠端裝置的MAC地址,在任何時候都能夠初始化一個連線,而不需要執行發現處理(假設裝置在可連線的範圍內)。
要記住配對和連線之間的差異。配對意味著兩個裝置對彼此存在性的感知,它們之間有一個共享的用於驗證的連線金鑰,用這個金鑰兩個裝置之間建立被加密的連線。連線意味著當前裝置間共享一個RFCOMM通道,並且能夠被用於裝置間的資料傳輸。當前Android藍芽API在RFCOMM連線被建立之前,要求裝置之間配對。(在使用藍芽API初始化加密連線時,配對是自動被執行的。)
以下章節介紹如何發現已配對的裝置,或發現新的使用了可發現功能的裝置。
注意:預設Android裝置是不可發現的。使用者能夠通過系統設定在限定的時間內變成可發現的裝置,或者應用程式能夠請求使用者啟用可發現性,而不離開應用程式。如何啟用可發現性,會在下文來討論。
查詢配對裝置
在執行裝置發現之前,應該先查詢已配對的裝置集合,來看期望的裝置是否是已知的。呼叫getBondedDevices()方法來完成這件工作。這個方法會返回一個代表已配對裝置的BluetoothDevice物件的集合。例如,你能夠查詢所有的配對裝置,然後使用一個ArrayAdapter物件把每個已配對裝置的名稱顯示給使用者。
/**
* 獲取已經配對的裝置
*/
public Set<BluetoothDevice> getConnetedDevices() {
if (mAdapter != null && mAdapter.isEnabled()) {
return mAdapter.getBondedDevices();
}
return null;
}
Set<BluetoothDevice> connetedDevices = mController.getConnetedDevices();
for(BluetoothDevice device:connetedDevices){
adapter.add(device.getName()+"\n"+ device.getAddress());
listView.setAdapter(adapter);
}
從BluetoothDevice物件來初始化一個連線所需要的所有資訊就是MAC地址。在這個例子中,MAC地址被作為ArrayAdapter的一部分來儲存,並顯示給使用者。隨後,該MAC地址能夠被提取用於初始化連線。
發現裝置
簡單的呼叫startDiscovery()方法就可以開始發現裝置。該過程是非同步的,並且該方法會立即返回一個布林值來指明發現處理是否被成功的啟動。通常發現過程會查詢掃描大約12秒,接下來獲取掃描發現的每個裝置的藍芽名稱。
為了接收每個被發現裝置的的資訊,你的應用程式必須註冊一個ACTION_FOUND型別的廣播接收器。對應每個藍芽裝置,系統都會廣播ACTION_FOUND型別的Intent。這個Intent會攜帶EXTRA_DEVICE和EXTRA_CLASS附加欄位,這個兩個欄位分別包含了BluetoothDevice和BluetoothClass物件。例如,下列演示了你如何註冊和處理裝置發現時的廣播:
//第一步:註冊廣播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);//不要忘了在onDestory中unregister
第二部:開始發現
mController.startDiscovery();//開始搜尋可發現的裝置
//第三步:接收廣播
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//發現了裝置
if(BluetoothDevice.ACTION_FOUND.equals(action)){
Toast.makeText(MainActivity.this, "發現裝置", Toast.LENGTH_SHORT).show();
//從Intent中獲取裝置的BluetoothDevice物件
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
adapter.add(device.getName()+"\n"+ device.getAddress());
listView.setAdapter(adapter);
}
}
};
結果如下:
可以看到,我們已經把發現的裝置展示到了ListView中。
警告:執行裝置發現,對於藍芽介面卡來說是一個沉重的過程,它會消耗大量的資源。一旦發現要連線裝置,在嘗試連線之前一定要確認用cancelDiscovery()方法來終止發現操作。另外,如果已經有一個跟裝置的連線,那麼執行發現會明顯的減少連線的可用頻寬,因此在有連線的時候不應該執行發現處理。
好了,第一篇就是這麼多,大家如果理解了可以去看第二篇了。Android開發之藍芽詳解(二)
相關推薦
Android開發之藍芽詳解(一)
一.概述 這篇文章是我學習Android開發官網以及網上一些其他文章總結而來,主要就是為了好好研究一下藍芽開發,看完這篇文章以後,我們就知道了怎樣使用藍芽API完成建立藍芽連線的必要四步:1.開啟藍芽;2.查詢附近已配對或可用的裝置;3.連線裝置;4.裝置間資
Android開發之藍芽(一)——基於SPP協議藍芽模組通訊
使用裝置 基本概念 基本流程 本文意在介紹藍芽開發的主要流程,學習使用藍芽開發一個星期了,寫寫一個星期以來遇到的一些小問題,還有介紹下流程。開發具有基本的通訊功能,本專案主要是用於與藍芽模組的串列埠讀寫功能。 下一篇文章還有Android開
Android開發之位置定位詳解與例項解析(GPS定位、Google網路定位,BaiduLBS(SDK)定位)
/** * 由經緯度獲取所在的城市及區域資訊 * @author caizhiming * */ private class ReadJSONFeedTask extends AsyncTask<String, Void, String> {
Android開發之EditText屬性詳解
1、EditText輸入的文字為密碼形式的設定 (1)通過.xml裡設定: 把該EditText設為:android:password="true" // 以”.”形式顯示文字 (2)在程式碼裡設定: 通過設定EditText的setTransformation
Android開發之藍芽(Bluetooth)操作(二)--修改本機藍芽裝置的可見性,並掃描周圍可用的藍芽裝置
一. 修改本機藍芽裝置的可見性 二. 掃描周圍可用的藍芽裝置 Eg: 一. 清單檔案AdroidManifest.xml: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android=
Android開發之藍芽Socket
藍芽Socket程式設計 實現藍芽Socket伺服器 藍芽Server端就是通過執行緒來註冊一個具有名稱和唯一識別的UUID號的BluetoothServerSocket, 然後就一直監聽Client端(BluetoothSocket)的請求,並對這些請求做出相應的處理。 // 註冊藍芽Server Ble
android開發之Parcelable使用詳解
想要在兩個activity之間傳遞物件,那麼這個物件必須序列化,android中序列化一個物件有兩種方式,一種是實現Serializable介面,這個非常簡單,只需要宣告一下就可以了,不痛不癢。但是android中還有一種特有的序列化方法,那就是實現Parcel
Android開發之自定義控制元件(一)---onMeasure詳解
話說一個有十年的程式設計經驗的老漢,決定改行書法,在一個熱火炎炎的中午,老漢拿著毛筆,在一張白紙上寫了個“Hello World!”,從此開啟了他的書法旅程。那麼問題來了請問自定義一個控制元件需要怎樣的流程?我們經常說自定義控制元件,那麼究竟怎樣去自定義一
Android程式設計之DialogFragment原始碼詳解(一)
DialogFragment是Fragment家族成員之一,如果你把它簡單的理解成Dialog,那就錯了。它的確可以做作dialog顯示,還可以顯示出自己定義的Dialog或者AlertDialog,但它同時也是一個Fragment。 按照官方的話來理解就是,你既可以把它當
Android開發之藍牙連接打印機
cep sdi tco disable ner gis util receiver count 代碼很簡單,直接一個布局文件和一個activity。需要的朋友可以直接將這兩部分粘貼復制到項目中即可。 Activity部分: package com.anhua.bluet
豹哥嵌入式講堂:ARM Cortex-M開發之文件詳解(7)- 反匯編文件(.s/.lst/.dump)
work cfi text1 翻譯 memory 進制數 補充 就是 datatable 大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是嵌入式開發裏的反匯編文件(.s, .lst, .dump)。 豹哥在第四、五、六節課分別介紹了編譯器/鏈接器生成的
豹哥嵌入式講堂:ARM Cortex-M開發之文件詳解(8)- 鏡像文件(.bin/.hex/.s19)
linker 未定義 公司 編輯器 ascii 輔助 oca ddr ext 大家好,我是豹哥,獵豹的豹,犀利哥的哥。今天豹哥給大家講的是嵌入式開發裏的image文件(.bin, .hex, .s19)。 今天這節課是豹哥《ARM Cortex-M開發之文件詳解》
Android開發——事件分發機制詳解---微信魚蝦蟹源碼搭建
lai reset 微信 影響 ren 事件分發機制 lis forum hlist 轉載請註明出處:http://h5.hxforum.com深入學習事件分發機制,是為了解決在Android開發中遇到的滑動沖突問題做準備。事件分發機制描述了用戶的手勢一系列事件是如何被An
電子產品開發之藍芽耳機收納盒控制微控制器晶片
今日分享一款電子產品—藍芽耳機收納盒及藍芽耳機收納盒控制微控制器晶片。使用藍芽耳機的各位肯定都是曉得藍芽耳機收納盒的。大部分藍芽耳機都會隨機配備一款與之匹配的充電盒,充電盒能為其提供電力以及收納存放的功能。 藍芽耳機充電很多事使用Micro USB充電,充電口附近會有充電指示燈。拿出耳機
python之celery使用詳解一
前段時間需要使用rabbitmq做寫快取,一直使用pika+rabbitmq的組合,pika這個模組雖然可以很直觀地操作rabbitmq,但是官方給的例子太簡單,對其底層原理了解又不是很深,遇到很多坑,尤其是需要自己寫連線池管理和channel池管理。雖然也有用過celery,一直也是celery+redis
iOS開發之AddressBookUI框架詳解
iOS開發之AddressBookUI框架詳解 一、關於AddressBookUI框架 AddressbookUI是iOS開發框架中提供的一套通訊錄介面元件。其中封裝好了一套選擇聯絡人,檢視聯絡人的介面,在需要時開發者可以直接呼叫。當然對於聯絡人介面,
iOS開發之AddressBook框架詳解
iOS開發之AddressBook框架詳解 一、寫在前面 首先,AddressBook框架是一個已經過時的框架,iOS9之後官方提供了Contacts框架來進行使用者通訊錄相關操作。儘管如此,AddressBook框架依然是一個非常優雅並且使用方便的通
iOS開發之Accounts框架詳解
iOS開發之Accounts框架詳解 Accounts框架是iOS原生提供的一套賬戶管理框架,其支援Facebook,新浪微博,騰訊微博,Twitter和領英賬戶管理的功能。需要注意,在iOS 11及以上系統中,將此功能已經刪除,因此Accounts.frame
最全!Android 開發狀態列配色詳解
感覺 Android 狀態列一直是一個坑啊!! 並且國內不同 Android 的手機廠商也對狀態列做了不同的適配和修改。在此記錄以下實現不同效果的狀態列的方法 Android 4.4 之前,Andro
Android常用之Butterknife使用詳解
Butterknife簡介 Butterknife中文又名黃油刀,是 JakeWharton大神開源的一款Android檢視的欄位和方法繫結快速註解框架.也是Android開發中比較常用的一款快速註解框架了,可以不用不斷的重複findViewById,在各種場合下快