浅谈Android BLE编程

来源:互联网 发布:剑网3脸型数据 编辑:程序博客网 时间:2024/05/16 18:45

   网上关于BLE编程,都是通过Service来进行的,但我写的简单实例,是通过子线程来进行连接获得characteristic,虽然会存在一些问题,

   但仅供BLE部分学习的参考与理解应该还是有帮助的。下面通过代码来逐一分析BLE编程的流程,以及注意的事项。

/*
程序的总体思路:
 1:先判断本地设备是否支持BLE功能,如果支持则打开设备BLE,否则退出
 2:打开本地BLE后,依据MAC(远程设备的MAC地址)获得BluetoothDevice(远程BLE设备实例)
 3:依据获得的设备建立连接,获得BluetoothGatt对象,此中会自动回调一些方法,在回调方法中可以实现某些操作
 4:根据characteristic实现数据接发的传输
*/

注意:BLE中characteristic是数据接发的“基本单位”,我们需要通过MAC地址连接到蓝牙模块,通过UUID获得两者characteristic

            对characteristic操作来实现数据的接发。这里MAC地址是通过广播的形式抓取到的,在后续博客中我将更加完善的说明,UUID一般蓝牙模块文档会提供。

package com.example.administrator.bluetooth42;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class MainActivity extends AppCompatActivity {
   /* 定义布局中控件变量  */
    private Button connect;
    private Button send;
    private Button received;
    private TextView text;

    private BluetoothManager bluetoothManager; // 定义系统蓝牙管理器
    private BluetoothAdapter bluetoothAdapter; // 定义本地蓝牙实例
    private BluetoothDevice bluetoothDevice;  // 定义远程蓝牙实例
    private BluetoothGatt bluetoothGatt; // 定义蓝牙连接成功的BluetoothGatt对象,用于获取接发封装的信息
// 定义一个泛型List,用于获取连接后产生的service
    private List<BluetoothGattService> bluetoothGattServices = new ArrayList<BluetoothGattService>();
/*  在BLE中,通信与传统Bluetooth是有区别的,不是根据MAC和UUID采用类Socket的方法  
BLE中,接发信息是存在characteristic中的,其为数据接发的直接操作载体(完成BLE的基本单位)
BLE编程,首先根据MAC地址建立连接,通过回调方法,获取service(一般有多个),通过service获得characteristic(一个service也可以含有多个)
characteristic中则包含value或Descriptor。
我们需要的是具有接发功能的characteristic(根据UUID获得)
*/
    private final String address = "20:91:48:31:2B:CD"; // MAC地址
    private final String uuid="0000ffe1-0000-1000-8000-00805f9b34fb";

   // Android中是不能在子线程中进行View更新的,需要将更新信息返回主线程,在主线程中操作,这里一般采用Handler Message的方式 
    private Handler handler = new Handler() // 获得子线程或回调方法发送的消息,一般用于主线程View的处理更新
    {
        @Override
        public void handleMessage(Message msg)
        {
            String str = (String)msg.obj;
            text.setText(str); // 将数据转化为String,在界面中显示出来
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        connect = (Button)findViewById(R.id.connect);
        send = (Button)findViewById(R.id.send);
        received = (Button)findViewById(R.id.received);
        text = (TextView)findViewById(R.id.text);

        View.OnClickListener listener = new View.OnClickListener()
        { // 时间监听器,根据ID值,判断是点击了哪个按钮
            @Override
            public void onClick(View v)
            {
                switch(v.getId())
                {
                    case R.id.connect : Connect();break;
                    case R.id.send : Send();break;
                    case R.id.received : Received();break;
                }
            }
        };
        connect.setOnClickListener(listener);
        send.setOnClickListener(listener);
        received.setOnClickListener(listener);
        InitBluetooth();
    }
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    private void InitBluetooth() {  // 初始化本地蓝牙设备

        bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if(bluetoothAdapter==null || !bluetoothAdapter.isEnabled())
        {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent,1);
        }
    }
  // 在获得BluetoothGatt对象进行操作时,就会调用这里面的某些方法
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override //设备连接成功并回调该方法
        public void onConnectionStateChange(BluetoothGatt gatt, int status,final int newState) {
           // super.onConnectionStateChange(gatt,status,newState);
            runOnUiThread(new Runnable(){
                @Override
                public void run()
                {
                    switch(newState)
                    {
                        case BluetoothGatt.STATE_CONNECTED:
                            System.out.println("......Hello......");
                            bluetoothGatt.discoverServices(); // 连接成功后查询该设备的服务
                            break;
                        //正在连接
                        case BluetoothGatt.STATE_CONNECTING:
                            break;
                        //连接断开
                        case BluetoothGatt.STATE_DISCONNECTED:
                            break;
                        //正在断开
                        case BluetoothGatt.STATE_DISCONNECTING:
                            break;
                    }
                }
            });
        }
        @Override // 发现服务后回调该方法
        public void onServicesDiscovered(BluetoothGatt gatt,int status)
        {
            //super.onServicesDiscovered(gatt,status);
            if(status==bluetoothGatt.GATT_SUCCESS)
            {
                System.out.println("下面开始获得服务!");
                bluetoothGattServices = gatt.getServices(); // 获得所有的Service
                if(bluetoothGattServices.size()==0)
                {
                    System.out.println("服务列表为空!");
                }
            }
        }
        @Override  // 当读取设备时,会回调该函数
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,int status)
        { 
            if (status == BluetoothGatt.GATT_SUCCESS) {
                       byte[] mByte = characteristic.getValue();
                    Message msg = new Message(); // 这里使用了一个消息机制,将信息返回主线程,在回调方法和子线程中是不允许进行View更新的
                    System.out.println("......"+mByte.length+".......");
                    System.out.println("......"+mByte[0]+".....");
                    String res = new String(mByte);
                    System.out.println("++++"+res+"------");
                    msg.obj = res;
                    handler.sendMessage(msg);
                }catch(Exception e)
                {
                    System.out.println("抛出异常!");
                }

            } /** end of if (status == BluetoothGatt.GATT_SUCCESS) */
            System.out.println("aoaoaoaoaoao");
        }


        @Override  // 设备发出通知时会调用到该接口
        public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic)
        {
            byte[] mByte = characteristic.getValue();
            StringBuilder mStrBuilder = new StringBuilder(mByte.length);
            /** 逐byte转换 */
            for (byte mByteChar : mByte) {
                mStrBuilder.append(String.format("%02x", mByteChar));
            } /** end of for (byte mByteChar : mByte) */
            System.out.println("bcbcbcbcbcbco");
        }


        @Override
        public void onCharacteristicWrite(final BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic,int status) {
            //super.onCharacteristicWrite(gatt, characteristic, status);
            System.out.println("发送数据成功!");
            if(status==BluetoothGatt.GATT_SUCCESS)
            {
                try
                {
                    byte[] mByte = characteristic.getValue();
                    StringBuilder mStrBuilder = new StringBuilder(mByte.length);
                    for (byte mByteChar : mByte) {
                        mStrBuilder.append(String.format("%02x", mByteChar));
                        System.out.println("222000");
                    }
                }catch (Exception e) {
                    System.out.println("111000");
                    e.printStackTrace();
                }
            }
            System.out.println("dddeeeddedede");
        }
    };

    private void Connect() {
/*  这里的MAC地址是通过广播的形式,抓取到的,为了便于说明,这里直接使用了,省略了相应代码  */
// BLE 的MAC地址一般是唯一的
        bluetoothDevice = bluetoothAdapter.getRemoteDevice(address); // 通过MAC地址,获得远程设备实例
        bluetoothGatt = bluetoothDevice.connectGatt(this,false,mGattCallback);
        System.out.println("建立连接成功!");
    }
    private void Received() { // 接收按钮执行的事件监听函数
        System.out.println("执行接收函数!");
// 开启一个子线程,通过characteristic实现从BLE接收数据
        runOnUiThread(new Runnable() {
            @Override
            public void run()
            {
                for(BluetoothGattService GattService : bluetoothGattServices)
                {
                    List<BluetoothGattCharacteristic> bluetoothGattCharacteristics = GattService.getCharacteristics();
                    for(BluetoothGattCharacteristic characteristic : bluetoothGattCharacteristics)
                    { //接收与发送是一样的道理,不过这里是获得characteristic,在回调方法中操作结果
                        if(characteristic.getUuid().toString().equals(uuid))
                        {
                            System.out.println("lisajjashaJ");  // 在会调方法中执行读取数据的显示工作
                            bluetoothGatt.readCharacteristic(characteristic); // 获得接收的数据载体characteristic,成功后会回调onCharacteristicRead方法
                            System.out.println("等待回调接收相应方法!");
                        }
                    }
                }
            }
        });
    }

    private void Send() { // 发送按钮点击后执行的函数:
        System.out.println("执行发送函数");
// 开启一个子线程用于通过获得的characteristic发送数据至远程BLE设备
        runOnUiThread(new Runnable(){
            @Override
            public void run()
            {
                for(BluetoothGattService GattService : bluetoothGattServices)
                { // 遍历Service数组,获得该服务中的characteristic
                    List<BluetoothGattCharacteristic> bluetoothGattCharacteristics = GattService.getCharacteristics();
                    for(BluetoothGattCharacteristic characteristic : bluetoothGattCharacteristics)
                    { // 遍历service对应的characteristic,看是否具有用于收发的characteristic
     // 这是根据UUID确定的,UUID一般厂家会给出,这里接发对应的UUID在前面定义了

 // 其实每个service,characteristic,descriptor都有一个对应的UUID
                        if(characteristic.getUuid().toString().equals(uuid))
                        {
                            byte[] sum = {(byte)0x00};
                            System.out.println("Lalalalala");
                            characteristic.setValue(sum); // 设置要发送的characteristic,为其赋予值,它像个载体
                            bluetoothGatt.writeCharacteristic(characteristic); // 此方法执行会回调onCharacteristicWrite方法
                            System.out.println("等待回调发送信息函数是否成功");
                        }
                    }
                }
            }
        });
    }
}

/*

  先获得Service,再获得需要的characteristic,利用characteristic来进行数据操作。

  在characteristic进行数据接发后,会调用BluetoothGattCallback 中重载的相应方法。

*/

  第一篇博客,不足之处还请多多包涵。写博客一来是想记录,梳理自己所学的东西,二来是想和大家多多分享交流。

  不足之处,或是有错误还望留言指正,谢谢。微笑



0 0