广

android开发

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

    Android提高之Android手机与BLE终端通信

    2018-04-16 10:57:24 次阅读 稿源:互联网
    广告

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

    注:笔者的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,还有一些必要的读写蓝牙方法,应该算是简化到大家一看就可以懂了。本文完整代码可以点击此处本站下载。

    接下来贴出本文运行的结果,首先是连接BLE设备后,枚举出设备所有Service、Characteristic、Descriptor,并且手机会往Characteristic uuid=0000ffe1-0000-1000-8000-00805f9b34fb写入“send data->”字符串,BLE终端收到数据通过串口传到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));   }      }      }    }//  }}

    感兴趣的读者可以动手测试一下代码的运行情况,希望能对大家的Android项目开发有所帮助。

    一起学吧部分文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与一起学吧进行文章共享合作。

    广告
    广告
    广告