亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android提高之Android手機與BLE終端通信

2020-04-11 11:45:29
字體:
來源:轉載
供稿:網友

最近穿戴設備發展得很火,把相關技術也帶旺了,其中一項是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項目開發有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美丰满少妇xxxxx做受| 精品日韩视频在线观看| 欧美日韩国产一区中文午夜| 国产成人精品在线| 欧美精品久久一区二区| 日韩中文字幕欧美| 国产精品美女999| 亚洲欧洲xxxx| 欧美激情高清视频| 中文字幕亚洲欧美日韩在线不卡| 亚洲欧美国产一区二区三区| 一本大道久久加勒比香蕉| 色综合视频一区中文字幕| 欧美性xxxxxxxxx| 欧美激情a在线| 国产精品激情av在线播放| 成人免费视频xnxx.com| 欧美激情视频一区| 亚洲色图偷窥自拍| 欧美日韩免费在线观看| 日韩中文字幕精品| 91国偷自产一区二区三区的观看方式| 亚洲精选一区二区| 91高潮精品免费porn| 夜夜嗨av一区二区三区免费区| 国产亚洲一区二区精品| 日韩在线免费视频观看| 日韩视频在线免费观看| 成人在线视频福利| 亚洲欧洲日产国码av系列天堂| 欧美情侣性视频| 成人激情电影一区二区| 日韩美女在线观看| 亚洲午夜av电影| 国产精品狠色婷| 日韩成人激情视频| 欧美日韩免费网站| 欧美激情va永久在线播放| 亚洲va码欧洲m码| www日韩中文字幕在线看| 欧美一区二区三区免费视| 欧美午夜激情小视频| 国内精品久久久久久影视8| 亚洲自拍欧美色图| 欧美激情第一页xxx| 国产玖玖精品视频| 国产精品久久久久久久久久久新郎| 国产精品爽爽爽爽爽爽在线观看| 亚洲jizzjizz日本少妇| 亚洲自拍偷拍色片视频| 亚洲精品美女免费| 国产成人精品免费视频| 91精品国产色综合久久不卡98| 亚洲丝袜一区在线| 成人在线免费观看视视频| 92看片淫黄大片看国产片| 欧美激情手机在线视频| 欧美专区第一页| 欧美一级免费视频| 国产日韩精品入口| 国产日韩欧美视频在线| 国产欧美日韩专区发布| 国产亚洲xxx| 国产精品成人一区二区三区吃奶| 色偷偷av亚洲男人的天堂| 国产精品欧美日韩| 55夜色66夜色国产精品视频| 日韩精品免费在线观看| 97人人做人人爱| 亚洲精品98久久久久久中文字幕| 午夜美女久久久久爽久久| 91欧美精品成人综合在线观看| 久久久久国色av免费观看性色| 成人欧美在线观看| 国产99在线|中文| 日韩高清人体午夜| 国产精品xxx视频| 亚洲加勒比久久88色综合| 国产香蕉一区二区三区在线视频| 亚洲国产精品久久91精品| 亚洲无线码在线一区观看| 青青久久av北条麻妃海外网| 欧美国产日韩在线| 欧美日韩综合视频| 91久久精品一区| 亚洲美女www午夜| 亚洲深夜福利网站| 亚洲aⅴ日韩av电影在线观看| 成人黄色av免费在线观看| 亚洲成人动漫在线播放| 亚洲欧美999| 91在线中文字幕| 国产欧美精品一区二区三区-老狼| 78m国产成人精品视频| 日韩欧美在线字幕| 亚洲国产精品va在线看黑人| 中文字幕亚洲第一| 久久6免费高清热精品| 95av在线视频| 美女av一区二区三区| 日韩亚洲一区二区| 久久久综合av| 俺也去精品视频在线观看| 久久精品福利视频| 欧美久久久精品| 97高清免费视频| 国产一区玩具在线观看| 欧美激情精品久久久久久大尺度| 91中文字幕在线观看| 浅井舞香一区二区| 另类美女黄大片| 亚洲精品视频网上网址在线观看| 自拍偷拍亚洲在线| 日韩欧美a级成人黄色| 136fldh精品导航福利| 黄色成人av网| 欧美一级bbbbb性bbbb喷潮片| 97在线视频免费观看| 久久99热精品| 日韩欧美在线视频观看| 久久欧美在线电影| 91chinesevideo永久地址| 日韩高清av一区二区三区| 最新亚洲国产精品| 亚洲欧美激情视频| 欧美性视频网站| 欧美日韩一二三四五区| 美日韩丰满少妇在线观看| 国产精品成熟老女人| 欧美国产视频日韩| 国产午夜精品久久久| 国产精品国产三级国产aⅴ浪潮| 国产91精品视频在线观看| 精品视频9999| 青青a在线精品免费观看| 精品成人国产在线观看男人呻吟| 992tv成人免费视频| 日韩久久精品电影| 欧美成人激情视频| 国产精品视频免费在线| 欧美一区二区视频97| 欧美激情精品久久久久久蜜臀| 久久精品久久精品亚洲人| 日韩最新中文字幕电影免费看| 欧美综合激情网| 国产精品美女免费| 欧美交受高潮1| 伦伦影院午夜日韩欧美限制| 欧美另类老肥妇| 久久精品一本久久99精品| 欧美成人午夜激情在线| 国产精品亚洲激情| 欧美国产日韩中文字幕在线| 日韩美女写真福利在线观看| 亚洲欧美综合另类中字| 日本三级久久久| 欧美限制级电影在线观看| 欧美黄色性视频| 久久精品免费电影| 成人黄色网免费| 色噜噜国产精品视频一区二区| 91啪国产在线| 国产99久久精品一区二区永久免费| 成人av.网址在线网站|