天天看點

Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼

BLE藍牙4.2資料透傳操作

  • 藍牙子產品服務檢視
  • 測試代碼
    • 建立工程
    • 添權重限
    • 初始化幾個工具控件
    • 代碼流程
  • Android版本有網友提到需要7.0以上(未求證)
  • 本文所測試的藍牙子產品是CC2640,不适用藍牙2.0版本。
    Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼
    實作大概效果如下(發送資料在點選事件中寫的固定的字元串):
    Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼

藍牙子產品服務檢視

這裡用到一個軟體可以檢視使用的藍牙子產品廣播的服務,打開手機藍牙後開啟軟體即可掃描到附近的藍牙信号,找到自己的藍牙子產品名字,點選旁邊的CONNECT按鈕:

Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼

連接配接成功後就可以看到正在廣播的服務,找到類似如下的描述:

Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼
Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼

上面的UUIDf000fff1-0451-4000-b000-000000000000到來進行寫操作,描述Client Characteristic Configuration的UUID0x2902補充完整就是00002902-0000-1000-8000-00805f9b34fb是用來監聽資料接收。這裡有網友提供的UUID的解釋,不同廠家的藍牙子產品UUID可能會不一樣。這裡的兩個UUID在後面編寫程式的時候會用到。

測試代碼

為使工程簡潔,就不建立别的類了,所有代碼就都在MainActivity裡面來寫,代碼量也不大。

建立工程

建立一個Android空白工程,使用的是Android Studio,具體建立步驟就不描述了:

Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼

添權重限

<!-- 藍牙權限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <!-- 定位權限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
           
Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼

初始化幾個工具控件

Android BLE藍牙4.2資料透傳操作藍牙子產品服務檢視測試代碼
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/scan_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="掃描" />
        <Button
            android:id="@+id/send_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="發送" />
    </LinearLayout>
    <TextView
        android:id="@+id/re_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <ListView
        android:id="@+id/bluetooth_lv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></ListView>
</LinearLayout>
           

代碼流程

藍牙的操作流程網友介紹得比較詳細,這裡不再做重複介紹,上面的示範效果除了布局,寫的代碼其餘都在這一個MainActivity類裡,也就沒有做太多優化(抄起來友善),其中比較關鍵的就是一定要檢查那兩個UUID:

package com.example.bluetooth4;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    // 布局控件
    private Button scanBtn;
    private Button sendBtn;
    private TextView reTv;

    // 藍牙相關的變量
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothLeScanner mBluetoothManager;
    private List<BluetoothDevice> mBluetoothDevice;
    private BluetoothGatt mBluetoothGatt;
    private BluetoothGattCharacteristic mWriteCharacteristic;

    // 用于顯示搜尋到的藍牙清單
    private ArrayAdapter arrayAdapter;
    private ListView bluetoothLv;
    private LinkedList<String> bluetoothList =  new LinkedList();


    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化控件
        scanBtn = findViewById(R.id.scan_btn);
        sendBtn = findViewById(R.id.send_btn);
        bluetoothLv = findViewById(R.id.bluetooth_lv);
        reTv =  findViewById(R.id.re_tv);
        // 設定監聽事件
        scanBtn.setOnClickListener(this);
        sendBtn.setOnClickListener(this);

        mBluetoothDevice = new ArrayList<>();
        arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, bluetoothList);
        bluetoothLv.setAdapter(arrayAdapter);
        bluetoothLv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.d("Bluetooth", "選擇的藍牙名稱:" +mBluetoothDevice.get(position).getName());
                mBluetoothGatt = mBluetoothAdapter.getRemoteDevice(mBluetoothDevice.get(position).getAddress()).connectGatt(getApplicationContext(), true, mGattCallback);
                Message msg = new Message();
                msg.obj = "正在連接配接...";
                mHandlerLog.sendMessage(msg);
            }
        });

        // 直接擷取手機藍牙是配置,沒有再寫判斷藍牙的狀态(用軟體之前那先把藍牙打開)
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        mBluetoothManager = mBluetoothAdapter.getBluetoothLeScanner();
    }


    // 重新整理藍牙清單
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            BluetoothDevice device = (BluetoothDevice)msg.obj;
            Log.d("Bluetooth", "藍牙名稱:" + device.getAddress()+"  "+device.getName());
            String temp = device.getAddress()+"  "+device.getName();
            if(bluetoothList.contains(temp)==false) {
                mBluetoothDevice.add(device);
                bluetoothList.add(temp);
                arrayAdapter.notifyDataSetChanged();
            }
        }
    };

    // 提示連接配接狀态
    private Handler mHandlerLog = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_SHORT).show();
        }
    };

    // 用來重新整理接收控件
    private Handler mHandlerRes = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            reTv.setText((String)msg.obj);
        }
    };


    // 掃描藍牙的回調,把掃描到的用mHandler重新整理到界面上
    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BluetoothDevice device = result.getDevice();

            Message msg = new Message();
            msg.obj = device;
            mHandler.sendMessage(msg);
        }
    };

    // 兩個按鈕的點選事件
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.scan_btn) {

            if(scanBtn.getText().toString().equals("掃描"))
            {
                mBluetoothDevice.clear();
                scanBtn.setText("停止");
                mBluetoothManager.startScan(scanCallback);
            }
            else
            {
                scanBtn.setText("掃描");
                mBluetoothManager.stopScan(scanCallback);
            }
        }
        if(v.getId()==R.id.send_btn) {
            mWriteCharacteristic.setValue("bluetest");
            Log.d("Bluetooth", "發送資料");
            mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);
        }

    }

    // 藍牙的服務回調
    private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) { //連接配接成功
                Log.d("Bluetooth", "連接配接成功");

                Message msg = new Message();
                msg.obj = "連接配接成功";
                mHandlerLog.sendMessage(msg);
                mBluetoothGatt.discoverServices(); //連接配接成功後就去找出該裝置中的服務 private BluetoothGatt mBluetoothGatt;
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {  //連接配接失敗
            }
        }

        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {   //找到服務了
                List<BluetoothGattService> serviceList= mBluetoothGatt.getServices();

                //在這裡可以對服務進行解析,尋找到你需要的服務
                Log.d("Bluetooth", "找到服務了"+serviceList.size());
                for(int i=0;i<serviceList.size();i++)
                {
                    Log.d("Bluetooth", "服務:"+serviceList.get(i).getUuid().toString());
                    List<BluetoothGattCharacteristic> gattCharacteristics = serviceList.get(i).getCharacteristics();
                    for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { // 周遊每條服務裡的所有Characteristic
                        Log.d("Bluetooth", "服務Characteristic:"+gattCharacteristic.getUuid().toString());
                        if (gattCharacteristic.getUuid().toString().equals("f000fff1-0451-4000-b000-000000000000")) {
                            mBluetoothGatt.setCharacteristicNotification(gattCharacteristic,true);
                            //擷取一個描述符
                            BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
                            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                            mBluetoothGatt.readCharacteristic(gattCharacteristic);
                            mBluetoothGatt.writeDescriptor(descriptor);
                            mWriteCharacteristic = gattCharacteristic;
                        }
                    }
                }
            } else {
                Log.d("Bluetooth", "onServicesDiscovered received: " + status);
            }
        }



        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            Log.d("Bluetooth", "onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + characteristic.getUuid().toString());
        }


		//有資料過來就會回調到這個方法
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            Log.d("Bluetooth", "接收資料:"+ characteristic.getStringValue(0));
            if (characteristic.getValue() != null) {
                Message msg = new Message();
                msg.obj = characteristic.getStringValue(0);
                mHandlerRes.sendMessage(msg);
            }
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            Log.d("Bluetooth", "--------onDescriptorWrite-----");
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            Log.d("Bluetooth", "--------onReadRemoteRssi-----"+rssi);
        }
    };
}

           

提供demo以作參考