當前位置:首頁 » 安卓系統 » android藍牙廣播

android藍牙廣播

發布時間: 2022-12-11 11:18:58

❶ Android開發之藍牙(Bluetooth)

在上一篇中有介紹了Wifi與網路連接處理
Android開發之WiFi與網路連接處理
下面,來繼續說說Android中藍牙的基本使用。

Bluetooth是目前使用的最廣泛的無線通訊協議之一,主要針對短距離設備通訊(10米),常用於連接耳機、滑鼠和移動通訊設備等。

值得一提的是:
android4.2新增了部分新功能,但是對於Bluetooth熟悉的人或許開始頭疼了,那就是Android4.2引入了一個新的藍牙協議棧針BLE。谷歌和Broadcom之間的合作,開發新的藍牙協議棧,取代了基於堆棧的Bluez。因此市場上出現了老設備的兼容問題,很多藍牙設備在android4.2手機上不能正常使用。

BluetoothAdapter簡單點來說就是代表了本設備(手機、電腦等)的藍牙適配器對象。

first:we need permission
要操作藍牙,先要在AndroidManifest.xml里加入許可權

**下面來看看如何使用藍牙。 **↓↓↓****
Demo已就緒:

返回值:如果設備具備藍牙功能,返回BluetoothAdapter 實例;否則,返回null對象。

打開藍牙設備的方式:
1.直接調用函數enable()去打開藍牙設備 ;
2.系統API去打開藍牙設備,該方式會彈出一個對話框樣式的Activity供用戶選擇是否打開藍牙設備。

注意: 1.如果藍牙已經開啟,不會彈出該Activity界面。2.在目前大多數Android手機中,是不支持在飛行模式下開啟藍牙的。如果藍牙已經開啟,那麼藍牙的開關 ,狀態會隨著飛行模式的狀態而發生改變。

1. 搜索藍牙設備
使用BluetoothAdapter的startDiscovery()方法來搜索藍牙設備
startDiscovery()方法是一個非同步方法,調用後會立即返回。該方法會進行對其他藍牙設備的搜索,該過程會持續12秒。該方法調用後,搜索過程實際上是在一個System Service中進行的,所以可以調用cancelDiscovery()方法來停止搜索(該方法可以在未執行discovery請求時調用)。

系統開始搜索藍牙設備
^( *  ̄(oo) ̄ ) ^ 系統會發送以下三個廣播:

2.掃描設備

3.定義廣播接收器接收搜索結果

4.注冊廣播

獲取附近的藍牙設備

第一步建立連接:首先Android sdk(2.0以上版本)支持的藍牙連接是通過BluetoothSocket建立連接,服務端BluetoothServerSocket和客戶端(BluetoothSocket)需指定同樣的UUID,才能建立連接,因為建立連接的方法會阻塞線程,所以伺服器端和客戶端都應啟動新線程連接。

(這里的服務端和客戶端是相對來說的)
兩個藍牙設備之間的連接,則必須實現服務端與客戶端的機制。
當兩個設備在同一個RFCOMM channel下分別擁有一個連接的BluetoothSocket,這兩個設備才可以說是建立了連接。

服務端設備與客戶端設備獲取BluetoothSocket的途徑是不同的。
1,服務端設備是通過accepted一個incoming connection來獲取的,
2,客戶端設備則是通過打開一個到服務端的RFCOMM channel來獲取的。

服務端
通過調用BluetoothAdapter的(String, UUID)方法來獲取BluetoothServerSocket(UUID用於客戶端與服務端之間的配對)

客戶端
調用BluetoothService的(UUID)方法獲取BluetoothSocket(該UUID應該同於服務端的UUID)。
調用BluetoothSocket的connect()方法(該方法為block方法),如果UUID同服務端的UUID匹配,並且連接被服務端accept,則connect()方法返回。

數據傳遞,通過以上操作,就已經建立的BluetoothSocket連接了,數據傳遞無非是通過流的形式
獲取流

該類就是關於遠程藍牙設備的一個描述。通過它可以和本地藍牙設備---BluetoothAdapter連接通信。

好多東西我也不知道怎麼描述,下面給出Demo:
剛好有剛學習的小夥伴問我ListView怎麼用,那我就用ListView。

源碼
RairDemo
GitHub: https://github.com/Rairmmd/android-demo
Coding: https://coding.net/u/Rair/p/RairDemo/git

❷ Android 藍牙開發(三)-藍牙的詳細介紹

前面的兩篇文章,主要是在 Android 官網關於藍牙介紹的基礎上加上自己的理解完成的。主要針對的是 Android 開發中的一些 API 的使用。
第一篇文章 Android 藍牙開發(一) 主要是介紹了普通的藍牙在 Android 開發中的運用。
第二篇文章 Android 藍牙開發(二) 主要是介紹了低功耗藍牙的開發。
這篇文章主要介紹的是藍牙的歷史和一些關於藍牙的通用知識,還有廣播包的知識。要想徹底了解藍牙開發,這些基礎的知識也是需要的,就像網路協議一樣,這些都是基礎的內容。我們的 API 的調用都是以這個為基礎的,了解這些,開發過程中遇到問題,才可以知道什麼怎麼一回事。

下篇文章主要講的就是實際開發中的一些坑。

藍牙其實就是一種近距離無線通信技術。

從下到上分別為:控制器(Controller)-->主機(host)-->應用(Application)

詳細介紹各個層的含義:

BLE 應用可以分為兩大類:基於非連接的和基於連接的

意思就是外設和周邊設備不發生連接,主要靠掃描到的廣播來獲取信息。發送廣播的一方叫做 broadcaster 監聽廣播的一方叫做 oberver 在 GAP 層有對應的角色定義。

網路拓撲圖:

這種方式就是廣播設備不斷的向外發送廣播(含有特定的信息),然後觀察者接受到廣播按照兩者之間約定好的協議進行解析拿到有用的信息。例如:iBeacon,通過這種設備我們可以實現室內定位。

其實這些設備的角色可以即使廣播者又是觀察者。接收到廣播後作出了處理,然後又發送廣播。這樣就形成了雙向的網路,類似於網際網路,這就是藍牙 Mesh 組網。

廣播數據包格式:

每個廣播數據包由 31 byte 組成。分為有效數據和無效數據兩部分。

例子:

這里是掃描的數據包(轉換成了 16 進制,兩個代表一個位元組),第一個位元組是 02 表示後面的兩個位元組是數據部分,然後第二個位元組是 01 表示了數據的類型。後面一個位元組就是真正的數據了。這個廣播數據單元就分析完了。下面就是另一個數據單元了。依次類推,關於數據類型的解釋,官網有。

這是數據類型對應的含義表。

網路拓撲圖:

一個中心設備可連接多個外設,但是一個外設只能連接一個中心(外設連接成功後就會停止對外廣播,別人就發現不了它了)。其中一個中心設備的連接外設的數量也是有限的。

鏈接: https://mp.weixin.qq.com/s?__biz=MzU5NzA2NjQzMg==&mid=2247484141&idx=1&sn=&scene=21#wechat_redirect

❸ android開發SPP經典藍牙

Android 開發SPP經典藍牙。

1、傳統藍牙採用的是SPP(Serial Port Profile)協議進行數據傳輸。

2、SPP的UUID:00001101-0000-1000-8000-00805F9B34FB

3、手機一般以客戶端的角色主動連接SPP協議設備

概念:

BluetoothAdapter:

本地藍牙適配器,是所有藍牙交互的入口,表示藍牙設備自身的一個藍牙適配器,整個系統只有一個藍牙適配器,通過他可以發現其他藍牙設備,查詢綁定(配對)設備列表,使用MAC地址實例化BluetoothDevice以及創建BluetoothServerSocket用來偵聽來自其他設備的通信。

myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//獲取默認的藍牙Adapter

BluetoothDevice:

遠程的藍牙設備。

private static BluetoothDevice myDevice;

myDevice = myBluetoothAdapter.getRemoteDevice(BDAddr);//獲取遠程設備,通過藍牙的MAC地址來獲取一個遠程對象

兩種連接方式

BluetoothSocket

客戶端:調用BluetoothDevice的()可以獲取該對象;調用connect()方法可以建立連接。

private static BluetoothSocket mySocket = null;

private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

Method m = myDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});//由BluetoothDevice衍生出BluetoothSocket, createRfcommSocket來選擇連接的服務和協議

mySocket = (BluetoothSocket) m.invoke(myDevice, 1);

BluetoothServerSocket:

服務端:通過BluetoothServerSocket對象可以創建BluetoothSocket對象,調用BluetoothServerSocket的accept()的方法可以得到改對象。

開發流程:

1:聲明許可權:

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

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

2:啟動和關閉藍牙

獲取藍牙適配器,使用close()介面可以關閉藍牙適配器

myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//獲取默認的藍牙Adapter

啟動藍牙

if (!blueadapter.isEnabled())

        //判斷本機藍牙是否打開

        {//如果沒打開,則打開藍牙

        blueadapter.enable();

        }

3.使用BlueAdatper搜索 

使用bluetoothAdapter搜索設備,bluetoothAdapter.startDiscovery()在搜索過程中,系統會發出三個廣播信息: 

ACTION_DISCOVERY_START:開始搜索 

ACTION_DISCOVERY_FINISHED:搜索結束 

ACTION_FOUND:找到設備

if (bluetoothAdapter.isDiscovering()) {

        bluetoothAdapter.cancelDiscovery();//如果藍牙設備未連接則取消搜索

    }

    bluetoothAdapter.startDiscovery();

}

4:(1)通過注冊廣播獲取搜索到的設備。

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//找到設備廣播

intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索完成廣播

registerReceiver(receiver, intentFilter);//注冊廣播接收器

// receiver

private final BroadcastReceiver receiver = new BroadcastReceiver(){

    @Override

    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();

        if (BluetoothDevice.ACTION_FOUND.equals(action)) {

            // find a device

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

            if (device.getBondState() != BluetoothDevice.BOND_BONDED) {

                //未配對設備

                newDeviceArrayAdapter.add(device.getName() + "\n" + device.getAddress());

            }else {

                //已經配對過的設備

                TextView tvPaired = (TextView)findViewById(R.id.tv_paired);

                tvPaired.setVisibility(View.VISIBLE);

                lvPairedDevices.setVisibility(View.VISIBLE);

                pairedDeviceArrayAdapter.add(device.getName() + "\n" + device.getAddress());

            }

            Log.i(TAG,"name:" + device.getName() + " address"+ device.getAddress());

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

            // search finish

            Log.i(TAG, "search finish!");

        }

    }

};

(2),直接得到當前的藍牙設備後,就可用通過遍歷pairedDevices ,得到當前手機已經配對過的藍牙設備。

Set<BluetoothDevice> pairedDevices = myBluetoothAdapter.getBondedDevices();//獲取當前藍牙設備

if (pairedDevices.size() <= 0) return false;

for (BluetoothDevice device : pairedDevices) {

    Map<String, String> map = new HashMap<String, String>();

    map.put("DeviceName", device.getName());

    map.put("BDAddress", device.getAddress());

    list.add(map);

5.建立連接

private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

Method m = myDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});//由BluetoothDevice衍生出BluetoothSocket, createRfcommSocket來選擇連接的服務和協議

mySocket = (BluetoothSocket) m.invoke(myDevice, 1);

mySocket.connect();//使用BluetoothSocket來連接設備

6.把得到的藍牙設備給通過點擊ListView選擇設備。

listView.setOnItemClickListener(new ListView.OnItemClickListener() {

    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

        SelectedBDAddress = list.get(arg2).get("BDAddress");

        if (((ListView) arg0).getTag() != null) {

            ((View) ((ListView) arg0).getTag()).setBackgroundDrawable(null);

        }

        ((ListView) arg0).setTag(arg1);

        arg1.setBackgroundColor(Color.BLUE);

        myDevice = myBluetoothAdapter.getRemoteDevice(SelectedBDAddress);

    }

});

7.客戶端發送數據

當兩個設備成功連接之後,雙方都會有一個BluetoothSocket對象,這時,就可以在設備之間傳送數據了。

       1.使用getOutputStream()方法來獲取輸出流來處理傳輸。

       2.調用write()。

os = socket.getOutputStream();//獲取輸出流

if (os != null) {//判斷輸出流是否為空

    os.write(message.getBytes("UTF-8"));

}

os.flush();//將輸出流的數據強制提交

os.close();//關閉輸出流

}

將輸出流中的數據提交後,要記得關閉輸出流,否則,可能會造成只能發送一次數據。

8.服務端接收數據

1.使用getInputStream()方法來獲取輸入流來處理傳輸。

       2.調用read()。

InputStream im=null;

im=bluetoothSocket.getInputStream();

byte buf[] = new byte[1024];

if (is != null) {

    is.read(buf, 0, buf.length);//讀取發來的數據

    String message = new String(buf);//把發來的數據轉化為String類型

    BuletoothMainActivity.UpdateRevMsg(message);//更新信息在顯示文本框

    is.close();//關閉輸入流

使用服務端接收數據時,要先從客戶端向服務端發起連接,只有接收到連接請求之後,才會返回一個BluetoothSocket對象。有BluetoothSocket對象才能獲取到輸入流。

❹ Android藍牙掃描

藍牙掃描的目的在於發現設備或者接收設備廣播,設備包括經典藍牙設備和BLE藍牙設備,這兩種設備的掃描方式不同。

對於經典藍牙設備,掃描是通過調用startDiscovery介面,返回的結果是通過BroadcastReceiver接收的,可以獲取設備MAC地址,名稱以及RSSI。

startDiscovery是個非同步調用,會立即返回。如果不調用cancelDiscovery主動停止掃描的話,最多掃描12s。

廣播主要監聽以下幾個Action:

BluetoothDevice.ACTION_FOUND

BluetoothAdapter.ACTION_DISCOVERY_STARTED

BluetoothAdapter.ACTION_DISCOVERY_FINISHED

另外要注意startDiscovery返回的設備不包括已配對設備,如要獲取已配對設備,需要額外調用getBondedDevices。

對於BLE藍牙設備,掃描是通過調用startLeScan介面,返回的結果是通過onLeScan回調,除了獲得設備MAC地址,名稱及RSSI之外還能獲取設備廣播,廣播是以byte數組的形式表示的。

較新的Android版本提供了新的掃描介面,可更靈活地配置掃描策略,詳情可參考官網文檔,此處不再贅述。

一,需要打開以下許可權

android.permission.BLUETOOTH

android.permission.ACCESS_COARSE_LOCATION

android.permission.BLUETOOTH_ADMIN

android.permission.ACCESS_FINE_LOCATION

另外還要注意動態許可權問題,在Android 6.0(targetSdkVersion>=23)之後,需要動態申請獲取用戶位置的許可權,不然獲取不到設備掃描結果。

二,startDiscovery在大多數手機上是可以同時發現經典藍牙和Ble的,但是startDiscovery的回調無法返回BLE的廣播,所以無法通過廣播識別設備,且startDiscovery掃描BLE的效率比startLeScan低很多。所以在實際應用中,還是startDiscovery和startLeScan分開掃,前者掃經典藍牙,後者掃低功耗藍牙。

三,startLeScan() 的時候,在onLeScan() 中不能做耗時操作,特別是周圍的BLE設備多的時候,容易導致底層堵塞,如果有耗時操作請丟到子線程中去處理。如解析廣播識別設備等操作可能會較耗時。

四,實踐中發現同樣一個設備,有的手機很容易就掃出來了,有的手機很難掃出來。這種情況建議可以多掃幾次,每次掃描時間短一點。

❺ 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原生BLE藍牙進行操作

之前的涉及的物聯網項目中使用的: BLE 低功耗藍牙(藍牙4.0), 支持android 4.3以上的手機
主從關系: BLE低功耗藍牙只能做從端設備 ,一個藍牙主端設備,可同時與7個藍牙從端設備進行通訊

1)低功耗
低功耗的原理:
1低功耗藍牙僅使用了3個廣播通道,傳統藍牙技術採用 16~32 個頻道
2每次廣播開啟時間也由傳統的 22.5ms 減少到 0.6~1.2ms(毫秒)

2)傳輸距離極大提高
傳統藍牙傳輸距離為 2~10m,而藍牙4.0的有效傳輸距離可達到 60~100m

3)安全性
使用AES-128 CCM加密演算法進行數據包加密和認證。
更多BLE藍牙的解析參考博客 : BLE4.0教程一 藍牙協議連接過程與廣播分析

添加許可權
打開藍牙
1.先拿到BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
2.再拿到BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
判斷是否打開藍牙
未打開彈出 系統彈框 ,除了 魅族手機 是打開系統設置

設備/手機都是藍牙信號

在回調方法中:

一般在掃描的過程中,我們還會設置 設備過濾原則 (因為我只想要搜索到我們想要的設備,忽略無關設備)
如:從 scanRecord -- beacon -- beacon.type == 0xFF代表Manufacture,通過與嵌入式軟體定義 自己的 Manufacture值即可

用BluetoothDevice得到BluetoothGatt:

斷連:

關鍵問題:連接後一般要做什麼事?

( 必須在剛連接成功後2秒內app寫一個值給設備,否則會被設備斷開連接)

主要是讀寫 characteristic
gatt.wirteCharacteristic(mCurrentcharacteristic);

gatt.readCharacteristic(characteristic);

bluetoothGatt.setCharacteristicNotification(data, true);

真實工作中使用的藍牙庫BlueToothKit請參考我的另一篇博客:
android藍牙入門知識和優秀藍牙第三方庫BluetoothKit的使用

❼ 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藍牙開發——實現藍牙聊天

與藍牙開發主要的相關類是以下四個

知道對應API後就可以進行對應的藍牙開發,這里以獲取藍牙設備為例子

}

搜索設備的回調則需要通過注冊廣播的形式來獲取

定義廣播

之後就可以進行個人的一些操作

要實現藍牙聊天則涉及到藍牙之間的傳輸通信,前面也說到了,這里肯定就是用到BluetoothServerSocket以及BluetoothSocket。

藍牙傳輸通信相當於伺服器端與客戶端之間的通信,只不過不同是這里每一個藍牙設備本身自己 既充當伺服器端也充當客戶端 ,大致的關系就是

注意,這些連接都是阻塞式的,都要放在線程里去執行。

可以看到,當BluetoothServerSocket監聽到有設備連接的時候,就會調用dataTransfer開啟一個數據傳輸。

需要一個ConnectThread來發起

之後建立連接之後就會調用dataTransfer來進行數據傳輸,同樣也需要一個線程來維護數據傳輸

藍牙聊天則是基於上面三個線程來進行實現,同樣,對於藍牙文件間的傳輸也是同個道理,通過輸入輸出流來進行處理。之後的操作就比較容易處理了

藍牙聊天

Android 藍牙開發基本流程

❾ Android 低功耗藍牙(Ble) 開發總結

Android 從 4.3(API Level 18) 開始支持低功耗藍牙,但是只支持作為中心設備(Central)模式,這就意味著 Android 設備只能主動掃描和鏈接其他外圍設備(Peripheral)。從 Android 5.0(API Level 21) 開始兩種模式都支持。

低功耗藍牙開發算是較偏技術,實際開發中坑是比較多的,網上有很多文章介紹使用和經驗總結,但是有些問題答案不好找,甚至有些誤導人,比如 :獲取已經連接的藍牙,有的是通過反射,一大堆判斷,然而並不是對所有手機有用,關於Ble傳輸速率問題的解決,都是默認Android每次只能發送20個位元組,然而也並不是,,,下面進入正文。

這里用的是 Android5.0 新增的掃描API,

這里說一下,如果做藍牙設備管理頁面,可能區分是否是已連接的設備,網上又通過反射或其他挺麻煩的操作,也不見得獲取到,官方Api 就有提供

與外圍設備交互經常每次發的數據大於 mtu的,需要做分包處理,接收數據也要判斷數據的完整性最後才返回原數據做處理,所以一般交互最少包含包長度,和包校驗碼和原數據。當然也可以加包頭,指令還有其他完整性校驗。下面分享幾個公用方法:

我自己封裝的一個BleUtil ,因為涉及跟公司業務關聯性太強(主要是傳輸包的協議不同)就先不開源出來了,如果這邊文章對大家有幫助反饋不錯,我會考慮上傳個demo到github供大家使用,
在這先給大家推薦一個不錯 Demo ,裡面除了沒有分包,協議,和傳輸速率。基本的功能都有,而且調試數據到列印到界面上了。最主要是它可以用兩個個手機一個當中心設備一個當外圍設備調試。

首先傳輸速率優化有兩個方向,1 外圍設備傳輸到Android 。2 Android傳輸到外圍設備。
我在開發中首先先使用上面那位仁兄的demo調試,兩個Android 設備調試不延時,上一個成功馬上下一個,最多一秒發11個20位元組的包。

後來和我們的藍牙設備調試時發現發送特別快,但是數據不完整,他藍牙模塊接收成功了,但是透傳數據到晶元處理時發現不完整,我們的硬體小夥伴說因為 波特率 限制(差不多每10位元組透傳要耗時1ms)和藍牙模塊的buff (列印時是最多100byte,100列印的)限制,就算藍牙模塊每包都告訴你接收成功,也是沒透傳完就又接收了。後來通過調試每次發20K數據,最後是 Android 發是 20位元組/130ms 穩定。給Android 發是 20位元組/ 8ms 。 (天殺的20位元組,網上都是說20位元組最多了)

後來看了國外一家物聯網公司總結的 Ble 吞吐量的文章(上面有連接),知道Android 每個延時是可以連續接收6個包的。就改為 120位元組/ 16ms (為啥是16ms,不是每次間隔要6個包嗎,怎麼像間隔兩次,這時因為波特率影響,多了5個包100位元組,差不多 我們的單片機透傳到藍牙模塊要多耗時不到10ms )
而Android 發數據可以申請 我們設備的mtu 來得到最多每次能發多少位元組。延時還是130ms,即:241位元組/ 130ms 提高12倍,這個速度還可以。

根據藍牙BLE協議, 物理層physical layer的傳輸速率是1Mbps,相當於每秒125K位元組。事實上,其只是基準傳輸速率,協議規定BLE不能連續不斷地傳輸數據包,否則就不能稱為低功耗藍牙了。連續傳輸自然會帶來高功耗。所以,藍牙的最高傳輸速率並不由物理層的工作頻率決定的。

在實際的操作過程中,如果主機連線不斷地發送數據包,要麼丟包嚴重要麼連接出現異常而斷開。

在BLE裡面,傳輸速度受其連接參數所影響。連接參數定義如下:

1)連接間隔。藍牙基帶是跳頻工作的,主機和從機會商定多長時間進行跳頻連接,連接上才能進行數據傳輸。這個連接和廣播狀態和連接狀態的連接不是一樣的意思。主機在從機廣播時進行連接是應用層的主動軟體行為。而跳頻過程中的連接是藍牙基帶協議的規定,完全由硬體控制,對應用層透明。明顯,如果這個連接間隔時間越短,那麼傳輸的速度就增大。連接上傳完數據後,藍牙基帶即進入休眠狀態,保證低功耗。其是1.25毫秒一個單位。

2)連接延遲。其是為了低功耗考慮,允許從機在跳頻過程中不理會主機的跳頻指令,繼續睡眠一段時間。而主機不能因為從機睡眠而認為其斷開連接了。其是1.25毫秒一個單位。明顯,這個數值越小,傳輸速度也高。

藍牙BLE協議規定連接參數最小是5,即7.25毫秒;而Android手機規定連接參數最小是8,即10毫秒。iOS規定是16,即20毫秒。

連接參數完全由主機決定,但從機可以發出更新參數申請,主機可以接受也可以拒絕。android手機一部接受,而ios比較嚴格,拒絕的概率比較高。

參考:
在iOS和Android上最大化BLE吞吐量
最大化BLE吞吐量第2部分:使用更大的ATT MTU

❿ Android藍牙開發(二)經典藍牙消息傳輸實現

上篇文章中,我們主要介紹了藍牙模塊,傳統/經典藍牙模塊BT和低功耗藍牙BLE及其相關的API,不熟悉的可以查看 Android藍牙開發(一)藍牙模塊及核心API 進行了解。

本篇主要記錄用到的經典藍牙開發流程及連接通訊。

藍牙連接前,給與相關系統許可權:

安卓6.0以上系統要動態請求及獲取開啟GPS內容:

藍牙核心對象獲取,若獲取對象為null則說明設備不支持藍牙:

判斷藍牙是否開啟,沒有則開啟:

藍牙掃描:

取消掃描:

藍牙監聽廣播,監聽藍牙開關,發現設備,掃描結束等狀態,定義狀態回調介面,進行對應操作,例如:監聽到藍牙開啟後,進行設備掃描;發現設備後進行連接等。

客戶端,與服務端建立長連接,進行通訊:

服務端監聽客戶端發起的連接,進行接收及通訊:

客戶端連接及服務端監聽基類,用於客戶端和服務端之前Socket消息通訊,進行消息或文件的發送、接收,進行通訊關閉操作等:

我這里只是簡單記錄了項目中用到的藍牙通訊,兩個設備之間不通過配對進行連接、通訊。
相關詳細內容及使用請查看Github項目: https://github.com/MickJson/BluetoothCS

藍牙配對操作及其它內容,可以詳細查看我下面的參考資料,寫的十分詳細,比如設備通過MAC地址,可以通過BluetoothAdapter獲取設備,再通過客戶端connect方法去進行連接等。

連接中遇到問題:read failed, socket might closed or timeout, read ret: -1。

通過改UUID,反射等方法都還是會出現錯誤。連接時,要確保服務端及客戶端都處於完全斷開狀態,否則連接就會出現以上問題,但偶爾還是會有問題,期待有什麼好的方法可留言告訴我。

參考資料:

Android-經典藍牙(BT)-建立長連接傳輸短消息和文件

Android藍牙開發—經典藍牙詳細開發流程

歡迎點贊/評論,你們的贊同和鼓勵是我寫作的最大動力!

熱點內容
心跳包源碼 發布:2025-03-17 11:03:29 瀏覽:796
安卓蘋果通訊錄怎麼同步 發布:2025-03-17 09:58:12 瀏覽:173
ai緩存 發布:2025-03-17 09:48:27 瀏覽:921
翹嘴水滴輪什麼配置 發布:2025-03-17 09:47:34 瀏覽:582
小蟻攝像機如何雲存儲 發布:2025-03-17 09:42:42 瀏覽:817
如何修改自己的名字和密碼 發布:2025-03-17 09:32:20 瀏覽:788
寶馬3系槍灰色輪轂是哪個配置 發布:2025-03-17 09:28:17 瀏覽:514
鴻蒙系統退回安卓系統怎麼備份 發布:2025-03-17 09:14:33 瀏覽:615
資料庫服務公司 發布:2025-03-17 08:56:43 瀏覽:496
我的世界伺服器載入不了區塊 發布:2025-03-17 08:56:39 瀏覽:818