欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?藍(lán)牙BLE開(kāi)發(fā)完全指南

 更新時(shí)間:2021年11月24日 10:36:12   作者:RalfNick  
BLE藍(lán)牙的興起主要因?yàn)榻陙?lái)可穿戴設(shè)備的流行,由于傳統(tǒng)藍(lán)牙功耗高不能滿(mǎn)足可穿戴設(shè)備對(duì)于續(xù)航的要求,所以大部分可穿戴設(shè)備采用藍(lán)牙4.0,即BLE藍(lán)牙技術(shù),這篇文章主要給大家介紹了關(guān)于Android?藍(lán)牙BLE開(kāi)發(fā)的相關(guān)資料,需要的朋友可以參考下

?介紹

1.BLE 是 Bluetooth Low Energy 的縮寫(xiě),意思為低功耗藍(lán)牙。由藍(lán)牙技術(shù)聯(lián)盟(Bluetooth SIG)設(shè)計(jì)的無(wú)線(xiàn)通訊技術(shù),主要用于醫(yī)療,健身,安全和家庭娛樂(lè)行業(yè)。 與傳統(tǒng)藍(lán)牙相比,藍(lán)牙低功耗旨在大幅降低功耗和成本,同時(shí)也能夠達(dá)到相同的通訊效果。

支持多個(gè)平臺(tái),包括 IOS,Android,Windows Phone 和 BlackBerry 以及 macOS,Linux,Windows 8 和 Windows 10 在內(nèi)的移動(dòng)操作系統(tǒng)本身支持藍(lán)牙低功耗。 藍(lán)牙 SIG 預(yù)測(cè),到 2018 年,超過(guò) 90% 的藍(lán)牙智能手機(jī)將支持藍(lán)牙低功耗。

在安卓平臺(tái),

在 Android 4.3 (API level 18) 以后引進(jìn)來(lái)的,通過(guò)這些 API 可以?huà)呙杷{(lán)牙設(shè)備、連接設(shè)備,查詢(xún) services、讀寫(xiě)設(shè)備的 characteristics(屬性特征),然后通過(guò)屬性進(jìn)行數(shù)據(jù)傳輸。

特點(diǎn):

低功耗,使用 BLE 與周?chē)O(shè)備進(jìn)行通訊時(shí),其峰值功耗為傳統(tǒng)藍(lán)牙的一半

傳輸距離提升到 100 米

低延時(shí),最短可在3 ms內(nèi)完成連接并開(kāi)始進(jìn)行數(shù)據(jù)傳輸

缺點(diǎn):

傳輸數(shù)據(jù)量較小,最大 512 個(gè)字節(jié),超過(guò) 20 個(gè)字節(jié)需要分包處理

應(yīng)用領(lǐng)域:

主要用于智能硬件,像健康護(hù)理、運(yùn)動(dòng)和健身、設(shè)備電源管理等

連接模式

對(duì)于BLE單設(shè)備來(lái)講常見(jiàn)的藍(lán)牙模塊的工作模有四種:

主設(shè)備模式

從設(shè)備模式

廣播模式

Mesh組網(wǎng)模式

主設(shè)備模式

可以與一個(gè)從設(shè)備進(jìn)行連接。在此模式下可以對(duì)周?chē)O(shè)備進(jìn)行搜索并選擇需要連接的從設(shè)備進(jìn)行連接。同時(shí)可以設(shè)置默認(rèn)連接從設(shè)備的MAC地址,這樣模塊上電之后就可以查找此模塊并進(jìn)行連接。

從設(shè)備模式

BLE支持從設(shè)備模式,在此模式下完全符合BLE4.1協(xié)議,用戶(hù)可以根據(jù)協(xié)議自己開(kāi)發(fā)APP。此模式下包含一個(gè)串口收發(fā)的Service,用戶(hù)可以通過(guò)UUID找到它,里面有兩個(gè)通道,分別是讀和寫(xiě)。用戶(hù)可以操作這兩個(gè)通道進(jìn)行數(shù)據(jù)的傳輸。

廣播模式

在這種模式下模塊可以一對(duì)多進(jìn)行廣播。用戶(hù)可以通過(guò)AT指令設(shè)置模塊廣播的數(shù)據(jù),模塊可以在低功耗的模式下持續(xù)的進(jìn)行廣播,應(yīng)用于極低功耗,小數(shù)據(jù)量,單向傳輸?shù)膽?yīng)用場(chǎng)合,比如無(wú)線(xiàn)抄表,室內(nèi)定位等功能。

Mesh組網(wǎng)模式

在這種模式下模塊可以實(shí)現(xiàn)簡(jiǎn)單的自組網(wǎng)絡(luò),每個(gè)模塊只需要設(shè)置相同的通訊密碼就可以加入到同一網(wǎng)絡(luò)當(dāng)中,每一個(gè)模塊都可以發(fā)起數(shù)據(jù),每個(gè)模塊可以收到數(shù)據(jù)并且進(jìn)行回復(fù)。并且不需要網(wǎng)關(guān),即使某一個(gè)設(shè)備出現(xiàn)故障也會(huì)跳過(guò)并選擇最近的設(shè)備進(jìn)行傳輸。

GATT協(xié)議

GATT generic Attributes的縮寫(xiě),中文是通用屬性,是低功耗藍(lán)牙設(shè)備之間進(jìn)行通信的協(xié)議。

GATT定義了一種多層的數(shù)據(jù)結(jié)構(gòu),已連接的低功耗藍(lán)牙設(shè)備用它來(lái)進(jìn)行通信,GATT層是傳輸真正數(shù)據(jù)所在的層。一個(gè)GATT服務(wù)器通過(guò)一個(gè)稱(chēng)為屬性表的表格組織數(shù)據(jù),這些數(shù)據(jù)就是用于真正發(fā)送的數(shù)據(jù)。

GATT定義的多層數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)要概括起來(lái)就是服務(wù)(service)可以包含多個(gè)特征(characteristic),每個(gè)特征包含屬性(properties)和值(value),還可以包含多個(gè)描述(descriptor)。它形象的結(jié)構(gòu)如下圖:

profile(數(shù)據(jù)配置文件)

一個(gè)profile文件可以包含一個(gè)或者多個(gè)服務(wù),一個(gè)profile文件包含需要的服務(wù)的信息或者為對(duì)等設(shè)備如何交互的配置文件的選項(xiàng)信息。設(shè)備的GAP和GATT的角色都可能在數(shù)據(jù)的交換過(guò)程中改變,因此,這個(gè)文件應(yīng)該包含廣播的種類(lèi)、所使用的連接間隔、所需的安全等級(jí)等信息。

需要注意的是: 一個(gè)profile中的屬性表不能包含另一個(gè)屬性表。

屬性

一個(gè)屬性包含句柄、UUID(類(lèi)型)、值,句柄是屬性在GATT表中的索引,在一個(gè)設(shè)備中每一個(gè)屬性的句柄都是唯一的。UUID包含屬性表中數(shù)據(jù)類(lèi)型的信息,它是理解屬性表中的值的每一個(gè)字節(jié)的意義的關(guān)鍵信息。在一個(gè)GATT表中可能有許多屬性,這些屬性能可能有相同的UUID。

個(gè)人理解,屬性指的是 Service、Characteristic 這樣的對(duì)象

Service

一個(gè)低功耗藍(lán)牙設(shè)備可以定義許多 Service, Service 可以理解為一個(gè)功能的集合。設(shè)備中每一個(gè)不同的 Service 都有一個(gè) 128 bit 的 UUID 作為這個(gè) Service 的獨(dú)立標(biāo)志。藍(lán)牙核心規(guī)范制定了兩種不同的UUID,一種是基本的UUID,一種是代替基本UUID的16位UUID。所有的藍(lán)牙技術(shù)聯(lián)盟定義UUID共用了一個(gè)基本的UUID:

0x0000xxxx-0000-1000-8000-00805F9B34FB

為了進(jìn)一步簡(jiǎn)化基本UUID,每一個(gè)藍(lán)牙技術(shù)聯(lián)盟定義的屬性有一個(gè)唯一的16位UUID,以代替上面的基本UUID的‘x'部分。例如,心率測(cè)量特性使用0X2A37作為它的16位UUID,因此它完整的128位UUID為:

0x00002A37-0000-1000-8000-00805F9B34FB

Characteristic

在 Service 下面,又包括了許多的獨(dú)立數(shù)據(jù)項(xiàng),我們把這些獨(dú)立的數(shù)據(jù)項(xiàng)稱(chēng)作 Characteristic。同樣的,每一個(gè) Characteristic 也有一個(gè)唯一的 UUID 作為標(biāo)識(shí)符。在 Android 開(kāi)發(fā)中,建立藍(lán)牙連接后,我們說(shuō)的通過(guò)藍(lán)牙發(fā)送數(shù)據(jù)給外圍設(shè)備就是往這些 Characteristic 中的 Value 字段寫(xiě)入數(shù)據(jù);外圍設(shè)備發(fā)送數(shù)據(jù)給手機(jī)就是監(jiān)聽(tīng)這些 Charateristic 中的 Value 字段有沒(méi)有變化,如果發(fā)生了變化,手機(jī)的 BLE API 就會(huì)收到一個(gè)監(jiān)聽(tīng)的回調(diào)。

DesCriptor

任何在特性中的屬性不是定義為屬性值就是為描述符。描述符是一個(gè)額外的屬性以提供更多特性的信息,它提供一個(gè)人類(lèi)可識(shí)別的特性描述的實(shí)例。然而,有一個(gè)特別的描述符值得特別地提起:客戶(hù)端特性配置描述符(Client Characteristic Configuration Descriptor,CCCD),這個(gè)描述符是給任何支持通知或指示功能的特性額外增加的。在CCCD中寫(xiě)入“1”使能通知功能,寫(xiě)入“2”使能指示功能,寫(xiě)入“0”同時(shí)禁止通知和指示功能。

使用過(guò)程

常采用的模式是主機(jī)模式,然后掃描客戶(hù)端硬件,然后連接,獲取相關(guān)服務(wù)和特性,然后進(jìn)行數(shù)據(jù)傳輸。

掃描

權(quán)限獲取

<uses-permission android:name="android.permission.BLUETOOTH"/> 使用藍(lán)牙所需要的權(quán)限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> 使用掃描和設(shè)置藍(lán)牙的權(quán)限(申明這一個(gè)權(quán)限必須申明上面一個(gè)權(quán)限)

在Android5.0之前,是默認(rèn)申請(qǐng)GPS硬件功能的。而在Android 5.0 之后,需要在manifest 中申明GPS硬件模塊功能的使用。

    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
    <uses-feature android:name="android.hardware.location.gps" />

在 Android 6.0 及以上,還需要打開(kāi)位置權(quán)限。如果應(yīng)用沒(méi)有位置權(quán)限,藍(lán)牙掃描功能不能使用(其它藍(lán)牙操作例如連接藍(lán)牙設(shè)備和寫(xiě)入數(shù)據(jù)不受影響)。

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

除了上面的設(shè)置之外,如果想設(shè)置設(shè)備只支持 BLE,可以加上下面這句話(huà)

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

同樣,如果不想添加 BLE 的支持,那么可以設(shè)置 required="false"

然后可以在運(yùn)行時(shí)判斷設(shè)備是否支持 BLE,

    // Use this check to determine whether BLE is supported on the device. Then
    // you can selectively disable BLE-related features.
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
        finish();
    }

初始化

判斷 BLE 在設(shè)備上是否支持,如果不支持的話(huà),那么可以不用繼續(xù)后面的操作了;如果支持,但是有可能藍(lán)牙被禁掉了,因?yàn)殚_(kāi)著藍(lán)牙比較好點(diǎn),用戶(hù)一般都會(huì)關(guān)閉藍(lán)牙,這時(shí)候可以發(fā)送請(qǐng)求,來(lái)打開(kāi)藍(lán)牙,可以通過(guò)兩個(gè)步驟來(lái)完成。

1.獲取 BluetoothAdapter

BluetoothAdapter 對(duì)于一個(gè)設(shè)備來(lái)說(shuō)唯一的,整個(gè)系統(tǒng)或者應(yīng)用,對(duì)藍(lán)牙進(jìn)行操作時(shí)都是需要這個(gè)的適配器。它的獲取需要通過(guò)系統(tǒng)服務(wù)來(lái)獲取。

    private BluetoothAdapter mBluetoothAdapter;
    ...
    // Initializes Bluetooth adapter.
    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();

2.打開(kāi)藍(lán)牙

一般對(duì)于用戶(hù)來(lái)說(shuō),在手機(jī)上藍(lán)牙是關(guān)閉,當(dāng)開(kāi)啟你的應(yīng)用時(shí)就需要開(kāi)啟藍(lán)牙,有兩種方式,一種是跳轉(zhuǎn)到設(shè)置界面,由用戶(hù)自己開(kāi)啟藍(lán)牙;

另外一種時(shí),直接在應(yīng)用開(kāi)啟藍(lán)牙,不需要用戶(hù)打開(kāi),而是直接幫用戶(hù)開(kāi)啟手機(jī)上的藍(lán)牙。

跳轉(zhuǎn)到設(shè)置界面

// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}

直接開(kāi)啟藍(lán)牙

    // 打開(kāi)藍(lán)牙
    if (!mBluetoothAdapter.isEnabled()) {
        mBluetoothAdapter.enable();
    }

掃描

掃描藍(lán)牙設(shè)備可以通過(guò)startLeScan(),其中有一個(gè)參數(shù)是 ScanCallback,通過(guò)它返回掃描結(jié)果,因?yàn)閽呙柽^(guò)程是很耗電的,所以在掃描過(guò)程需要保證

1.一旦找到目標(biāo)設(shè)備,需要停止掃描

2.掃描不要設(shè)置循環(huán),而且需要設(shè)置一個(gè)時(shí)間

回調(diào)如下

// 設(shè)備掃描回調(diào)
    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, final ScanResult result) {

            runOnUiThread(new Runnable() {
                @Override
                public void run() {

                    // 廣播的信息,可以在result中獲取
                    MDevice mDev = new MDevice(result.getDevice(), result.getRssi());
                    if (!mList.contains(mDev)) {
                        mList.add(mDev);
                    }
                    if (mList.size() > 0) {
                        mScanner.stopScan(mScanCallback);
                        Toast.makeText(MainActivity.this, "掃描結(jié)束,設(shè)備數(shù) " + mList.size()
                                , Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    };

開(kāi)始掃描

private BluetoothAdapter mBluetoothAdapter;
    private boolean mScanning;
    private Handler mHandler;

    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;
    ...
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
        ...
    }

這里遇到一個(gè)坑,就是實(shí)際中手機(jī)與一些智能硬件連接時(shí),也就是需要連接指定的硬件,設(shè)備有一個(gè)UUID,所以可以通過(guò)如下方法連接

    startLeScan(UUID[], BluetoothAdapter.LeScanCallback)

但是實(shí)際中使用時(shí),連接時(shí)會(huì)出錯(cuò),仍需要再次驗(yàn)證。

我當(dāng)時(shí)的做法是采用了另外一種方法,當(dāng)時(shí)這種方法,要求 API 高于 21。

    private void scanLeDevice() {

        //50秒后停止掃描
        mHander.postDelayed(stopScanRunnable, 50000);

        List<ScanFilter> filters = new ArrayList<>();
        ScanFilter filter = new ScanFilter.Builder()
                //"D8:B0:4C:E8:66:DC" 測(cè)試MAC 1
                //"D8:B0:4C:E2:45:2A"  測(cè)試MAC 2
                .setDeviceAddress("D8:B0:4C:E2:45:2A")
                .build();
        filters.add(filter);

        // 掃描
        mScanner.startScan(filters, new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(), mScanCallback);

    }

掃描結(jié)束后需要停止掃描

boolean startLeScan(BluetoothAdapter.LeScanCallback callback)

連接

設(shè)備連接

通過(guò)掃描能夠獲得設(shè)備 BluetoothDevice,包含地址和名字

通過(guò)設(shè)備連接并獲取 BluetoothGatt,后面通過(guò) BluetoothGatt 的實(shí)例來(lái)進(jìn)行client的操作,如使用該實(shí)例去發(fā)現(xiàn)服務(wù),獲取讀、寫(xiě)、通知等屬性

public static BluetoothGatt mBluetoothGatt;

 mBluetoothGatt = device.connectGatt(context, false, mGattCallback);

通過(guò)連接回調(diào)來(lái)監(jiān)聽(tīng)連接的狀態(tài),包含三種狀態(tài),連接、斷開(kāi)、正在連接,根據(jù)狀態(tài)可以發(fā)送廣播,

在接收廣播的位置進(jìn)行做相應(yīng)的處理

    private final static BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                            int newState) {

            String intentAction;
            // GATT Server connected
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                System.out.println("---------------------------->已經(jīng)連接");
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastConnectionUpdate(intentAction);
            }
            // GATT Server disconnected
            else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                System.out.println("---------------------------->連接斷開(kāi)");
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                broadcastConnectionUpdate(intentAction);

            }
            // GATT Server disconnected
            else if (newState == BluetoothProfile.STATE_DISCONNECTING) {
                System.out.println("---------------------------->正在連接");
//                intentAction = ACTION_GATT_DISCONNECTING;
//                mConnectionState = STATE_DISCONNECTING;
//                broadcastConnectionUpdate(intentAction);
            }
        }
    }

當(dāng)操作完成后,需要關(guān)閉連接,必須調(diào)用 BluetoothGatt#close 方法釋放連接資源

發(fā)現(xiàn)服務(wù)

由于有了 mBluetoothGatt,就可以去發(fā)現(xiàn)服務(wù),再通過(guò)服務(wù)去獲取可以操作的屬性

mBluetoothGatt.discoverServices();

發(fā)現(xiàn)服務(wù)以及獲取其他屬性,如write和read,notify,Descriptor相關(guān)的屬性,均是在 BluetoothGattCallback 中有回調(diào),在回調(diào)中就可以通過(guò)發(fā)送廣播,然后在其他位置做處理,

如接收數(shù)據(jù)就會(huì)有回調(diào),然后將數(shù)據(jù)傳遞出去,對(duì)數(shù)據(jù)解析等

 @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            // GATT Services discovered
            //發(fā)現(xiàn)新的服務(wù)
            if (status == BluetoothGatt.GATT_SUCCESS) {
                System.out.println("---------------------------->發(fā)現(xiàn)服務(wù)");
                broadcastConnectionUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            } 
        }

        //通過(guò) Descriptor 寫(xiě)監(jiān)聽(tīng)
        @Override 
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
                                      int status) {

        }

        // 通過(guò) Descriptor 讀監(jiān)聽(tīng)
        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
                                     int status) {

        }


        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
                characteristic, int status) {
            //write操作會(huì)調(diào)用此方法
            if (status == BluetoothGatt.GATT_SUCCESS) {
                System.out.println("onCharacteristicWrite ------------------->write success");
                Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_WRITE_SUCCESS);
                mContext.sendBroadcast(intent);
            } else {
                Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_ERROR);
                intent.putExtra(Constants.EXTRA_CHARACTERISTIC_ERROR_MESSAGE, "" + status);
                mContext.sendBroadcast(intent);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic, int status) {
            // 接收數(shù)據(jù)
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {

            //notify 會(huì)回調(diào)用此方法
            broadcastNotifyUpdate(characteristic);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
           super.onMtuChanged(gatt, mtu, status);

        }

數(shù)據(jù)傳輸

1、數(shù)據(jù)讀取

這里有兩個(gè)方法:

方法一: 一般數(shù)據(jù)讀取的話(huà),想到的是用 read 屬性,所以需要獲取特定通道的 BluetoothGattCharactristic。

1)BluetoothGatt#getService 得到服務(wù)

2)BluetoothGattService#getCharactristic 獲取 BluetoothGattCharactristic,這里獲取的 BluetoothGattCharactristic 是有指定 UUID 的,也就是說(shuō)不同的 Charactristic的 UUID 是不同的,讀和寫(xiě)的通道不同,根據(jù)不同的操作,然后通過(guò)UUID獲取相應(yīng)的通道

3)BluetoothGattCharactristic#readCharacteristic 方法可以通知系統(tǒng)去讀取特定的數(shù)據(jù)

4)BluetoothGattCallback#onCharacteristicRead 方法。通過(guò) BluetoothGattCharacteristic#getValue 可以讀取到藍(lán)牙設(shè)備的數(shù)據(jù)

方法二:采用 notify 屬性,客戶(hù)端發(fā)送數(shù)據(jù),服務(wù)端監(jiān)聽(tīng)屬性變化,然后根據(jù) 屬性的 UUID 判斷是否是 notify 的屬性,如果是的話(huà),說(shuō)確實(shí)是由遠(yuǎn)程設(shè)備發(fā)過(guò)來(lái)的數(shù)據(jù)。

1)BluetoothGatt#getService 得到服務(wù)

2)BluetoothGattService#getCharactristic 獲取 BluetoothGattCharactristic,這里的這個(gè)屬性是 notify 屬性

3)獲得屬性后需要進(jìn)行判斷設(shè)備是否支持notify操作,然后再設(shè)備打開(kāi)notify通知

void prepareBroadcastDataNotify(
            BluetoothGattCharacteristic characteristic) {

        final int charaProp = characteristic.getProperties();

        Toast.makeText(this, " " + charaProp, Toast.LENGTH_SHORT).show();

        if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
            BluetoothLeService.setCharacteristicNotification(characteristic, true);
        }

    }

4) 設(shè)置屬性時(shí),也要通知遠(yuǎn)程設(shè)備端也要開(kāi)啟 notify 屬性

public static void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            return;
        }
        //通知遠(yuǎn)程端開(kāi)啟 notify 
        if (characteristic.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG)) != null) {
            if (enabled == true) {
                BluetoothGattDescriptor descriptor = characteristic
                        .getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mBluetoothGatt.writeDescriptor(descriptor);
            } else {
                BluetoothGattDescriptor descriptor = characteristic
                        .getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
                descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
                mBluetoothGatt.writeDescriptor(descriptor);
            }
        }
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
    }

數(shù)據(jù)寫(xiě)入

對(duì)于 BLE 方式的數(shù)據(jù)傳輸來(lái)說(shuō),數(shù)據(jù)的大小是有限制的,一次性最多可以傳輸512個(gè)字節(jié),這也是BLE小數(shù)據(jù)量傳輸?shù)奶攸c(diǎn),另外,對(duì)于每次傳輸,也有限制,每個(gè)數(shù)據(jù)包大小不超過(guò)20個(gè)字節(jié),超過(guò)20個(gè)字節(jié)的話(huà),需要分包處理。寫(xiě)的步驟和讀取類(lèi)似。

1)BluetoothGatt#getService 得到服務(wù)

2)BluetoothGattService#getCharactristic 獲取 BluetoothGattCharactristic,這里的這個(gè)屬性是 write 屬性

3)寫(xiě)入字節(jié)數(shù)據(jù)

public static void writeCharacteristicGattDb(
            BluetoothGattCharacteristic characteristic, byte[] byteArray) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            return;
        } else {
            byte[] valueByte = byteArray;
            characteristic.setValue(valueByte);
            mBluetoothGatt.writeCharacteristic(characteristic);
        }
    }

4)對(duì)于手機(jī)端,寫(xiě)入數(shù)據(jù)后,遠(yuǎn)程端會(huì)接受,同時(shí)回調(diào)中也會(huì)能夠接收,也可以在回調(diào)中做一下數(shù)據(jù)判斷,看是否是自己發(fā)出的數(shù)據(jù)

 @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic
                characteristic, int status) {
            //write操作會(huì)調(diào)用此方法
            if (status == BluetoothGatt.GATT_SUCCESS) {
                System.out.println("onCharacteristicWrite ------------------->write success");
                Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_WRITE_SUCCESS);
                // 這里通過(guò)屬性能夠讀取你發(fā)送的數(shù)據(jù),可以對(duì)此數(shù)據(jù)進(jìn)行判斷
                characteristic.getValue();
                mContext.sendBroadcast(intent);
            } else {
                Intent intent = new Intent(ACTION_GATT_CHARACTERISTIC_ERROR);
                intent.putExtra(Constants.EXTRA_CHARACTERISTIC_ERROR_MESSAGE, "" + status);
                mContext.sendBroadcast(intent);
            }
        }

其他

一般在通訊過(guò)程中,需要有連接的心跳包,來(lái)檢測(cè)是否仍處于連接狀態(tài),可以通過(guò)設(shè)置定時(shí)器,主機(jī)端定時(shí) write 數(shù)據(jù),客戶(hù)端定時(shí) notify 數(shù)據(jù)

斷開(kāi)連接

操作完成,需要斷開(kāi)藍(lán)牙并釋放資源,通過(guò) BluetoothGatt#disconnect 斷開(kāi)連接,然后回調(diào)中會(huì)收到斷開(kāi)的監(jiān)聽(tīng),可以根據(jù)狀態(tài)釋放資源。BluetoothGattCallback#onConnectionStateChange回調(diào)中通過(guò)這個(gè)方法的 newState 參數(shù)可以判斷是連接成功還是斷開(kāi)成功的回調(diào),斷開(kāi)成功的話(huà),然后調(diào)用 BluetoothGatt#close 方法釋放資源

參考

官方文檔

Android 開(kāi)發(fā)入門(mén)介紹

通用屬性配置文件(GATT)及其服務(wù),特性與屬性介紹

總結(jié)

到此這篇關(guān)于Android?藍(lán)牙BLE開(kāi)發(fā)完全指南的文章就介紹到這了,更多相關(guān)Android?藍(lán)牙BLE開(kāi)發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論