⑴ android藍牙BLE(三) —— 廣播
在藍牙開發中,有些情況是不需要連接的,只要外設廣播自己的數據即可,例如蘋果的 ibeacon 。自 Android 5.0 更新藍牙API後,手機可以作為外設廣播數據。
廣播包有兩種:
其中 廣播包是每個外設都必須廣播的,而響應包是可選的 。每個廣播包的長度必須是 31個位元組 ,如果不到 31個位元組 ,則剩下的全用 0 填充 補全,這部分的數據是無效的
廣播包中包含若干個廣播數據單元,廣播數據單元也稱為 AD Structure 。
廣播數據單元 = 長度值Length + AD type + AD Data。
長度值 Length 只佔 一個位元組 ,並且位於廣播數據單元的 第一個位元組 。
概念的東西有些抽象,先看看下面的廣播報文:
0x代表這串字元串是十六進制的字元串。 兩位十六進制數代表一個位元組 。因為兩個字元組成的十六進制字元串最大為 FF ,即255,而java中byte類型的取值范圍是-128到127,剛好可以表示一個255的大小。所以兩個十六進制的字元串表示一個位元組。
繼續查看報文內容,開始讀取第一個廣播數據單元。讀取 第一個 位元組: 0x07 ,轉換為十進制就是7,即表示後面的7個位元組是這個廣播數據單元的數據內容。超過這7個位元組的數據內容後,表示是一個新的廣播數據單元。
而第二個廣播數據單元,第一個位元組的值是 0x16 ,轉換為十進制就是22,表示後面22個位元組為第二個廣播數據單元。
在廣播數據單元的 數據部分 中, 第一個位元組 代表 數據類型 (AD type),決定數據部分表示的是什麼數據。(即廣播數據單元第二個位元組為AD type)
AD Type 的類型如下:
這bit 1~7分別代表著發送該廣播的藍牙晶元的物理連接狀態。當bit的值為1時,表示支持該功能。
例:
藍牙廣播的數據格式大致講了一下,有助於下面的廣播操作的理解。
先看看廣播設置( AdvertiseSettings )如何定義:
(1)、通過 AdvertiseSettings.Builder#setAdvertiseMode() 設置廣播模式。其中有3種模式:
(2)、通過 AdvertiseSettings.Builder#setAdvertiseMode() 設置廣播發射功率。共有4種功率模式:
(3)、通過 AdvertiseSettings.Builder#setTimeout() 設置持續廣播的時間,單位為毫秒。最多180000毫秒。當值為0則無時間限制,持續廣播,除非調用 BluetoothLeAdvertiser#stopAdvertising() 停止廣播。
(4)、通過 AdvertiseSettings.Builder#setConnectable() 設置該廣播是否可以連接的。
之前說過,外設必須廣播廣播包,掃描包是可選。但添加掃描包也意味著廣播更多得數據,即可廣播62個位元組。
可見無論是廣播包還是掃描包,其廣播的內容都是用 AdvertiseData 類封裝的。
(1)、 AdvertiseData.Builder#setIncludeDeviceName() 方法,可以設置廣播包中是否包含藍牙的名稱。
(2)、 AdvertiseData.Builder#setIncludeTxPowerLevel() 方法,可以設置廣播包中是否包含藍牙的發射功率。
(3)、 AdvertiseData.Builder#addService UUID (Parcel UUID ) 方法,可以設置特定的 UUID 在廣播包中。
(4)、 AdvertiseData.Builder#addServiceData(Parcel UUID ,byte[]) 方法,可以設置特定的 UUID 和其數據在廣播包中。
(5)、 AdvertiseData.Builder#addManufacturerData(int,byte[]) 方法,可以設置特定廠商Id和其數據在廣播包中。
從 AdvertiseData.Builder 的設置中可以看出,如果一個外設需要在不連接的情況下對外廣播數據,其數據可以存儲在 UUID 對應的數據中,也可以存儲在廠商數據中。但由於廠商ID是需要由Bluetooth SIG進行分配的,廠商間一般都將數據設置在廠商數據。
另外可以通過 BluetoothAdapter#setName() 設置廣播的名稱
先看一個例子,我們分別在 廣播包 和 掃描包 中設置 AdvertiseData.Builder 的 每一種廣播報文參數 ,得到一下報文內容:
(1)、Type = 0x01 表示設備LE物理連接。
(2)、Type = 0x09 表示設備的全名
(3)、Type = 0x03 表示完整的16bit UUID 。其值為0xFFF7。
(4)、Type = 0xFF 表示廠商數據。前兩個位元組表示廠商ID,即廠商ID為0x11。後面的為廠商數據,具體由用戶自行定義。
(5)、Type = 0x16 表示16 bit UUID 的數據,所以前兩個位元組為 UUID ,即 UUID 為0xF117,後續為 UUID 對應的數據,具體由用戶自行定義。
最後繼承 AdvertiseCallback 自定義廣播回調。
初始化完畢上面的對象後,就可以進行廣播:
廣播主要是通過 BluetoothLeAdvertiser#startAdvertising() 方法實現,但在之前需要先獲取 BluetoothLeAdvertiser 對象。
BluetoothLeAdvertiser 對象存在兩個情況獲取為Null:
所以在調用 BluetoothAdapter#getBluetoothLeAdvertiser() 前,需要先調用判斷藍牙已開啟,並判斷在 BluetoothAdapter 中獲取的 BluetoothLeAdvertiser 是否為空(測試過某些華為手機 mBluetoothAdapter.() 為 false , 但是能發送ble廣播)。
與廣播成對出現就是 BluetoothLeAdvertiser.stopAdvertising() 停止廣播了,傳入開啟廣播時傳遞的廣播回調對象,即可關閉廣播:
雖然通過廣播告知外邊自身擁有這些Service,但手機自身並沒有初始化Gattd的Service。導致外部的中心設備連接手機後,並不能找到對應的 GATT Service 和 獲取對應的數據。
Service類型有兩個級別:
創建 BluetoothGattService 時,傳入兩個參數: UUID 和Service類型:
我們都知道Gatt中, Service 的下一級是 Characteristic , Characteristic 是最小的通信單元,通過對 Characteristic 進行讀寫操作來進行通信。
特徵屬性表示該 BluetoothGattCharacteristic 擁有什麼功能,即能對 BluetoothGattCharacteristic 進行什麼操作。其中主要有3種:
許可權屬性用於配置該特徵值所具有的功能。主要兩種:
Characteristic 下還有 Descriptor ,初始化 BluetoothGattDescriptor 時傳入: Descriptor UUID 和 許可權屬性
為 Service 添加 Characteristic ,為 Characteristic 添加 Descriptor :
通過藍牙管理器 mBluetoothManager 獲取 Gatt Server ,用來添加 Gatt Service 。添加完 Gatt Service 後,外部中心設備連接手機時,將能獲取到對應的 GATT Service 和 獲取對應的數據
定義 Gatt Server 回調。當中心設備連接該手機外設、修改特徵值、讀取特徵值等情況時,會得到相應情況的回調。
最後開啟廣播後,用nRF連接後看到的特徵值信息如下圖所示:(加多了一個只能都的特徵值)
android藍牙BLE(一) —— 掃描
android藍牙BLE(二) —— 通信
android藍牙BLE(三) —— 廣播
android藍牙BLE(四) —— 實戰
⑵ 怎麼用android獲取bluetooth的信號強度
android獲取藍牙bluetooth的信號強度步驟如下:
在oncreate方法裡面增加 注冊掃描廣播
public void onCreate(Bundle savedInstanceState) {
純顫 // 注冊開始發現廣播。
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
this.registerReceiver(mReceiver, filter);
}
2.新建BroadcastReceiver廣播對象,並實現裡面的onreceive方法,在onreceive得到rssi(信號強度)。
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//當設備開始掃描時。
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
芹鋒 //從Intent得到blueDevice對象
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
//信號強度。
short rssi = intent.getExtras().getShort(
BluetoothDevice.EXTRA_RSSI);
}
嫌褲晌 }
}
};
⑶ Android-Ble藍牙開發Demo示例–掃描,連接,發送和接收數據,分包解包(附源碼)
萬物互聯的物聯網時代的已經來臨,ble藍牙開發在其中扮演著舉重若輕的角色。最近剛好閑一點,抽時間梳理下這塊的知識點。
涉及ble藍牙通訊的客戶端(開啟、掃描、連接、發送和接收數據、分包解包)和服務端(初始化廣播數據、開始廣播、配置Services、Server回調操作)整個環節以及一些常見的問題即踩過的一些坑。
比如
1、在Android不同版本或不同手機的適配問題,掃描不到藍牙設備
2、如何避免ble藍牙連接出現133錯誤?
3、單次寫的數據大小有20位元組限制,如何發送長數據
藍牙有傳統(經典)藍牙和低功耗藍牙BLE(Bluetooth Low Energy)之分,兩者的開發的API不一樣,本文主講Ble藍牙開發,傳統藍牙不展開,有需要的可以自行了解。
相對傳統藍牙,BLE低功耗藍牙,主要特點是快速搜索,快速連接,超低功耗保持連接和數據傳輸。
客戶端
服務端
Android4.3(API Level 18)開始引入BLE的核心功能並提供了相應的 API。應用程序通過這些 API 掃描藍牙設備、查詢 services、讀寫設備的 characteristics(屬性特徵)等操作。
BLE藍牙協議是GATT協議, BLE相關類不多, 全都位於android.bluetooth包和android.bluetooth.le包的幾個類:
android.bluetooth.
.BluetoothGattService 包含多個Characteristic(屬性特徵值), 含有唯一的UUID作為標識
.BluetoothGattCharacteristic 包含單個值和多個Descriptor, 含有唯一的UUID作為標識
.BluetoothGattDescriptor 對Characteristic進行描述, 含有唯一的UUID作為標識
.BluetoothGatt 客戶端相關
.BluetoothGattCallback 客戶端連接回調
.BluetoothGattServer 服務端相關
.BluetoothGattServerCallback 服務端連接回調
android.bluetooth.le.
.AdvertiseCallback 服務端的廣播回調
.AdvertiseData 服務端的廣播數據
.AdvertiseSettings 服務端的廣播設置
.BluetoothLeAdvertiser 服務端的廣播
.BluetoothLeScanner 客戶端掃描相關(Android5.0新增)
.ScanCallback 客戶端掃描回調
.ScanFilter 客戶端掃描過濾
.ScanRecord 客戶端掃描結果的廣播數據
.ScanResult 客戶端掃描結果
.ScanSettings 客戶端掃描設置
BLE設備分為兩種設備: 客戶端(也叫主機/中心設備/Central), 服務端(也叫從機/外圍設備/peripheral)
客戶端的核心類是 BluetoothGatt
服務端的核心類是 BluetoothGattServer 和 BluetoothLeAdvertiser
BLE數據的核心類是 BluetoothGattCharacteristic 和 BluetoothGattDescriptor
下面詳細講解下客戶端和服務端的開發步驟流程
安卓手機涉及藍牙許可權問題,藍牙開發需要在AndroidManifest.xml文件中添加許可權聲明:
在搜索設備之前需要詢問打開手機藍牙:
注意: BLE設備地址是動態變化(每隔一段時間都會變化),而經典藍牙設備是出廠就固定不變了!
通過掃描BLE設備,根據設備名稱區分出目標設備targetDevice,下一步實現與目標設備的連接,在連接設備之前要停止搜索藍牙;停止搜索一般需要一定的時間來完成,最好調用停止搜索函數之後加以100ms的延時,保證系統能夠完全停止搜索藍牙設備。停止搜索之後啟動連接過程;
BLE藍牙的連接方法相對簡單只需調用connectGatt方法;
參數說明
與設備建立連接之後與設備通信,整個通信過程都是在BluetoothGattCallback的非同步回調函數中完成;
BluetoothGattCallback中主要回調函數如下:
上述幾個回調函數是BLE開發中不可缺少的;
當調用targetdDevice.connectGatt(context, false, gattCallback)後系統會主動發起與BLE藍牙設備的連接,若成功連接到設備將回調onConnectionStateChange方法,其處理過程如下:
判斷newState == BluetoothGatt.STATE_CONNECTED表明此時已經成功連接到設備;
mBluetoothGatt.discoverServices();
掃描BLE設備服務是安卓系統中關於BLE藍牙開發的重要一步,一般在設備連接成功後調用,掃描到設備服務後回調onServicesDiscovered()函數,函數原型如下:
BLE藍牙開發主要有負責通信的BluetoothGattService完成的。當且稱為通信服務。通信服務通過硬體工程師提供的UUID獲取。獲取方式如下:
具體操作方式如下:
開啟監聽,即建立與設備的通信的首發數據通道,BLE開發中只有當客戶端成功開啟監聽後才能與服務端收發數據。開啟監聽的方式如下:
BLE單次寫的數據量大小是有限制的, 通常是20位元組 ,可以嘗試通過requestMTU增大,但不保證能成功。分包寫是一種解決方案,需要定義分包協議,假設每個包大小20位元組,分兩種包,數據包和非數據包。對於數據包,頭兩個位元組表示包的序號,剩下的都填充數據。對於非數據包,主要是發送一些控制信息。
監聽成功後通過向 writeCharacteristic寫入數據實現與服務端的通信。寫入方式如下:
其中:value一般為Hex格式指令,其內容由設備通信的藍牙通信協議規定;
若寫入指令成功則回調BluetoothGattCallback中的onCharacteristicWrite()方法,說明將數據已經發送給下位機;
若發送的數據符合通信協議,則服務端會向客戶端回復相應的數據。發送的數據通過回調onCharacteristicChanged()方法獲取,其處理方式如下:
通過向服務端發送指令獲取服務端的回復數據,即可完成與設備的通信過程;
當與設備完成通信之後之後一定要斷開與設備的連接。調用以下方法斷開與設備的連接:
源碼上傳在CSDN上了,有需要的可以借鑒。
=====> Android藍牙Ble通訊Demo示例源碼–掃描,連接,發送和接收數據,分包解包
BLE單次寫的數據量大小是有限制的,通常是20位元組,可以嘗試通過requestMTU增大,但不保證能成功。分包寫是一種解決方案,需要定義分包協議,假設每個包大小20位元組,分兩種包,數據包和非數據包。對於數據包,頭兩個位元組表示包的序號,剩下的都填充數據。對於非數據包,主要是發送一些控制信息。
總體流程如下:
1、定義通訊協議,如下(這里只是個舉例,可以根據項目需求擴展)
2、封裝通用發送數據介面(拆包)
該介面根據會發送數據內容按最大位元組數拆分(一般20位元組)放入隊列,拆分完後,依次從隊列里取出發送
3、封裝通用接收數據介面(組包)
該介面根據從接收的數據按協議里的定義解析數據長度判讀是否完整包,不是的話把每條消息累加起來
4、解析完整的數據包,進行業務邏輯處理
5、協議還可以引入加密解密,需要注意的選演算法參數的時候,加密後的長度最好跟原數據長度一致,這樣不會影響拆包組包
一般都是Android版本適配以及不同ROM機型(小米/紅米、華為/榮耀等)(EMUI、MIUI、ColorOS等)的許可權問題
藍牙開發中有很多問題,要靜下心分析問題,肯定可以解決的,一起加油;
⑷ Android 藍牙測距離,兩部藍牙手機距離
/**
*功能:根據rssi計算距離
*Createdbyliuhuichaoon2017/1/17.
*/
publicclassRssiUtil{
//A和n的值,需要根據實際環境進行檢測得出
privatestaticfinaldoubleA_Value=50;/**A-發射端和接收端相隔1米時的信號強度*/
privatestaticfinaldoublen_Value=2.5;/**n-環境衰減因子*/
/**
*根據Rssi獲得返回的距離,返回數據單位為m
*@paramrssi
*@return
*/
publicstaticdoublegetDistance(intrssi){
intiRssi=Math.abs(rssi);
doublepower=(iRssi-A_Value)/(10*n_Value);
returnMath.pow(10,power);
}
}
掃描藍牙過程中獲得信號強度:
[java]view plain
/*監聽掃描過程中的變化*/
=newBroadcastReceiver(){
@Override
publicvoidonReceive(Contextcontext,Intentintent){
Stringaction=intent.getAction();
//Whendiscoveryfindsadevice
if(BluetoothDevice.ACTION_FOUND.equals(action))
{
//
//通過EXTRA_DEVICE附加域來得到一個BluetoothDevice設備
BluetoothDevicedevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//Ifit'salreadypaired,skipit,becauseit'sbeenlistedalready
//如果這個設備是不曾配對過的,添加到list列表
/*if(device.getBondState()!=BluetoothDevice.BOND_BONDED)
{*/
//信號強度
intrssi=intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
⑸ Android BLE藍牙踩坑總結
自從 Android-BLE 庫開源了一段時間以來,越來越多的小夥伴問到了各種各樣的關於BLE的奇怪問題,在這里我想跟大家分享一下本人對於Android BLE藍牙的一些看法和解決方式,避免剛接觸的小夥伴再次踩坑。
很多人曾問過我這個問題,為什麼其他手機都沒什麼問題,就華為的一些手機老是連接不穩定,經常連接的很慢,而且連接上還經常斷開。的確,在這里強調一下華為的一部分手機確實很容易出現這種問題,有時候軟體、硬體都搞不定,而且經常性收到客戶投訴關於華為手機連接穩定性問題,這個的確沒有完全解決的辦法,只能靠App和硬體的優化,並不是想甩鍋給華為,咱也不敢問到底是什麼原因,而且我們公司專門針對各個Android版本的手機做過測試,包括藍牙傳輸速率的測試,最後發現華為P20的速度竟然跟小米8的速度差了好幾倍,按理說P20手機也不便宜啊,為什麼手機搜物藍牙晶元不能做的再好一點呢?
BLE掃描濫用預防
AOSP-BLE掃描世歲液濫用說明
息屏狀態下,藍雀斗牙掃描日誌,因為掃描周期是12s,所以列印的時間戳間隔是12s,這里的日誌為系統日誌。
https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/include/bt_target.h#1428
stackoverflow問答社區
⑹ android中怎樣判斷藍牙是否連接
一般頂部都有圖標的,另外可以到設置通信裡面查找
⑺ android usb藍牙 怎麼調試
Android可以使用藍牙連接adb調試App
1. 將電腦藍牙與手機進行配對(控制面板—>設備和列印機->添加設備)
2. 在手機上設置(設置à 更多無線連接à網路共享à藍牙共享網路)
3. PC端,設備和列印機—》選擇配對好的手機—》右鍵—》連接時使用—》訪問點
4. 連接成功後打開CMD查詢藍牙適配器的ip
5.下載應用這個不用說了。運行超級終端。
開啟WiFi鎖
6.運行以下命令:
1. su //如果前面顯示的符號是$ ,則運行此命令切換到root。如果是# ,可以不用此命令
2. setprop service.adb.tcp.port 5555
3. stop adbd
4. start adbd
7.PC端在CMD中找到adb目錄運行
1. adb connect 藍牙網關
如果顯示「connected to192.168.44.1:5555」表示連接成功
8.運行adb shell 如果能進入,則大功告成。否則,需要將手機先通過數據線連接電腦,在手機上允許電腦的連接,即可使用。
⑻ 怎麼用android獲取bluetooth的信號強度
Android 藍牙編程的基本步驟:
1. 獲取藍牙適配器BluetoothAdapter blueadapter=BluetoothAdapter.getDefaultAdapter();
如果BluetoothAdapter 為null,說明android手機沒有藍牙模塊。
判斷藍牙模塊是否開啟,blueadapter.isEnabled() true表示已經開啟,false表示藍牙並沒啟用。
2.啟動配置藍牙可見模式,即進入叢頃嫌可配對模式Intent in=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
in.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 200);
startActivity(in); ,200就表示200秒。
3.獲取藍牙適配器中已乎鏈經配對的設備Set<BluetoothDevice> device=blueadapter.getBondedDevices();
當然,還需要在androidManifest.xml中聲明藍牙的許可權
<uses-permission android:name="android.permission.BLUETOOTH" /滲手>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
4.接下來就是根據自己的需求對BluetoothAdapter 的操作了。
⑼ Android藍牙開發怎麼檢查遠程藍牙設備是否打開
通過下面的代碼判斷藍牙是否鏈接:
BluetoothHeadset mBluetoothHeadset;
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
// Define Service Listener of BluetoothProfile
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = null;
}
}
};
//call functions on mBluetoothHeadset to check if Bluetooth SCO audio is connected.
List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
for ( final BluetoothDevice dev : devices ) {
return mBluetoothHeadset.isAudioConnected(dev);
}
// finally Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);
⑽ Android藍牙怎麼檢測連接狀態
自己可以設置跡枯空一個標記符flag,可以在連接敗核時定義為true,當發生問題是變為false,姿瞎便於客戶端的接受