Android BLE开发之Android手机与BLE终端通信

               

本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

 最近穿戴设备发展得很火,把相关技术也带旺了,其中一项是BLE(Bluetooth Low Energy)。BLE是蓝牙4.0的核心Profile,主打功能是快速搜索,快速连接,超低功耗保持连接和传输数据,弱点是数据传输速率低,由于BLE的低功耗特点,因此普遍用于穿戴设备。Android 4.3才开始支持BLE API,所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统,另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。

PS:我的i9100刷了4.4系统后,竟然也能跟BLE蓝牙模块通信。


 BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value。一般来说,Characteristic是手机与BLE终端交换数据的关键,Characteristic有较多的跟权限相关的字段,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY,本文所用的BLE蓝牙模块竟然没有标准的Characteristic的PERMISSION。Characteristic的PROPERTY可以通过位运算符组合来设置读写属性,例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY,因此读取PROPERTY后要分解成所用的组合(本文代码已含此分解方法)。


 本文代码改自Android 4.3 Sample的BluetoothLeGatt,把冗余代码去掉,获取的BLE设备信息都通过Log,还有一些必要的读写蓝牙方法,应该算是简化到大家一看就可以懂了。本文代码可以到http://download.csdn.net/detail/hellogv/7228819下载。接下来贴出本文运行的结果,首先是连接BLE设备后,枚举出设备所有Service、Characteristic、Descriptor,并且手机会往Characteristic uuid=0000ffe1-0000-1000-8000-00805f9b34fb写入“send data->”字符串,BLE终端收到数据通过串口传到PC串口助手(见PC串口助手的截图):

04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service type:PRIMARY
04-21 18:28:25.465: E/DeviceScanActivity(12254): -->includedServices size:0
04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service uuid:00001800-0000-1000-8000-00805f9b34fb
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a00-0000-1000-8000-00805f9b34fb
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char property:READ
04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a01-0000-1000-8000-00805f9b34fb
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a02-0000-1000-8000-00805f9b34fb
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a03-0000-1000-8000-00805f9b34fb
04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char uuid:00002a04-0000-1000-8000-00805f9b34fb
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ
04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service type:PRIMARY
04-21 18:28:25.475: E/DeviceScanActivity(12254): -->includedServices size:0
04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service uuid:00001801-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:00002a05-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:INDICATE
04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service type:PRIMARY
04-21 18:28:25.480: E/DeviceScanActivity(12254): -->includedServices size:0
04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service uuid:0000ffe0-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:0000ffe1-0000-1000-8000-00805f9b34fb
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:READ|WRITE_NO_RESPONSE|NOTIFY|
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002901-0000-1000-8000-00805f9b34fb
04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
04-21 18:28:26.025: E/DeviceScanActivity(12254): onCharRead BLE DEVICE read 0000ffe1-0000-1000-8000-00805f9b34fb -> 00

这里红字是由BluetoothGattCallback的onCharacteristicRead()回调而打出Log




以下Log是PC上的串口工具通过BLE模块发送过来,由BluetoothGattCallback的 onCharacteristicChanged()打出Log
04-21 18:30:18.260: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:18.745: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.085: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.350: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.605: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:19.835: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.055: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.320: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.510: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:20.735: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
04-21 18:30:21.000: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone

接下来贴出本文核心代码:

public class DeviceScanActivity extends ListActivity private final static String TAG = DeviceScanActivity.class.getSimpleName(); private final static String UUID_KEY_DATA = "0000ffe1-0000-1000-8000-00805f9b34fb";    private LeDeviceListAdapter mLeDeviceListAdapter;    /**搜索BLE终端*/    private BluetoothAdapter mBluetoothAdapter;    /**读写BLE终端*/    private BluetoothLeClass mBLE;    private boolean mScanning;    private Handler mHandler;    // Stops scanning after 10 seconds.    private static final long SCAN_PERIOD = 10000;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        getActionBar().setTitle(R.string.title_devices);        mHandler = new Handler();        // 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();        }        // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to        // BluetoothAdapter through BluetoothManager.        final BluetoothManager bluetoothManager =                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);        mBluetoothAdapter = bluetoothManager.getAdapter();                // Checks if Bluetooth is supported on the device.        if (mBluetoothAdapter == null) {            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();            finish();            return;        }        //开启蓝牙        mBluetoothAdapter.enable();                mBLE = new BluetoothLeClass(this);        if (!mBLE.initialize()) {            Log.e(TAG, "Unable to initialize Bluetooth");            finish();        }        //发现BLE终端的Service时回调        mBLE.setOnServiceDiscoverListener(mOnServiceDiscover);        //收到BLE终端数据交互的事件        mBLE.setOnDataAvailableListener(mOnDataAvailable);    }    @Override    protected void onResume() {        super.onResume();        // Initializes list view adapter.        mLeDeviceListAdapter = new LeDeviceListAdapter(this);        setListAdapter(mLeDeviceListAdapter);        scanLeDevice(true);    }    @Override    protected void onPause() {        super.onPause();        scanLeDevice(false);        mLeDeviceListAdapter.clear();        mBLE.disconnect();    }    @Override    protected void onStop() {        super.onStop();        mBLE.close();    }        @Override    protected void onListItemClick(ListView l, View v, int position, long id) {        final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);        if (device == null) return;        if (mScanning) {            mBluetoothAdapter.stopLeScan(mLeScanCallback);            mScanning = false;        }                mBLE.connect(device.getAddress());    }    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);                    invalidateOptionsMenu();                }            }, SCAN_PERIOD);            mScanning = true;            mBluetoothAdapter.startLeScan(mLeScanCallback);        } else {            mScanning = false;            mBluetoothAdapter.stopLeScan(mLeScanCallback);        }        invalidateOptionsMenu();    }    /**     * 搜索到BLE终端服务的事件     */    private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener(){  @Override  public void onServiceDiscover(BluetoothGatt gatt) {   displayGattServices(mBLE.getSupportedGattServices());  }         };        /**     * 收到BLE终端数据交互的事件     */    private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener(){     /**      * BLE终端数据被读的事件      */  @Override  public void onCharacteristicRead(BluetoothGatt gatt,    BluetoothGattCharacteristic characteristic, int status) {   if (status == BluetoothGatt.GATT_SUCCESS)     Log.e(TAG,"onCharRead "+gatt.getDevice().getName()      +" read "      +characteristic.getUuid().toString()      +" -> "      +Utils.bytesToHexString(characteristic.getValue()));  }       /**      * 收到BLE终端写入数据回调      */  @Override  public void onCharacteristicWrite(BluetoothGatt gatt,    BluetoothGattCharacteristic characteristic) {   Log.e(TAG,"onCharWrite "+gatt.getDevice().getName()     +" write "     +characteristic.getUuid().toString()     +" -> "     +new String(characteristic.getValue()));  }    };    // Device scan callback.    private BluetoothAdapter.LeScanCallback mLeScanCallback =            new BluetoothAdapter.LeScanCallback() {        @Override        public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {            runOnUiThread(new Runnable() {                @Override                public void run() {                    mLeDeviceListAdapter.addDevice(device);                    mLeDeviceListAdapter.notifyDataSetChanged();                }            });        }    };    private void displayGattServices(List<BluetoothGattService> gattServices) {        if (gattServices == null) return;        for (BluetoothGattService gattService : gattServices) {         //-----Service的字段信息-----//         int type = gattService.getType();            Log.e(TAG,"-->service type:"+Utils.getServiceType(type));            Log.e(TAG,"-->includedServices size:"+gattService.getIncludedServices().size());            Log.e(TAG,"-->service uuid:"+gattService.getUuid());                        //-----Characteristics的字段信息-----//            List<BluetoothGattCharacteristic> gattCharacteristics =gattService.getCharacteristics();            for (final BluetoothGattCharacteristic  gattCharacteristic: gattCharacteristics) {                Log.e(TAG,"---->char uuid:"+gattCharacteristic.getUuid());                                int permission = gattCharacteristic.getPermissions();                Log.e(TAG,"---->char permission:"+Utils.getCharPermission(permission));                                int property = gattCharacteristic.getProperties();                Log.e(TAG,"---->char property:"+Utils.getCharPropertie(property));                byte[] data = gattCharacteristic.getValue();          if (data != null && data.length > 0) {           Log.e(TAG,"---->char value:"+new String(data));          }          //UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic          if(gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)){                      //测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()           mHandler.postDelayed(new Runnable() {                        @Override                        public void run() {                         mBLE.readCharacteristic(gattCharacteristic);                        }                    }, 500);                      //接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()           mBLE.setCharacteristicNotification(gattCharacteristic, true);           //设置数据内容           gattCharacteristic.setValue("send data->");           //往蓝牙模块写入数据           mBLE.writeCharacteristic(gattCharacteristic);          }                    //-----Descriptors的字段信息-----//    List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();    for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {     Log.e(TAG, "-------->desc uuid:" + gattDescriptor.getUuid());     int descPermission = gattDescriptor.getPermissions();     Log.e(TAG,"-------->desc permission:"+ Utils.getDescPermission(descPermission));          byte[] desData = gattDescriptor.getValue();     if (desData != null && desData.length > 0) {      Log.e(TAG, "-------->desc value:"+ new String(desData));     }           }            }        }//    }}

           
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值