Firefly开源社区

Android Ble简析

1183

积分

56

威望

1049

贡献

中级创客

Rank: 4

积分
1183
发表于 2014-11-27 15:58:22     
本帖最后由 Liu 于 2014-11-28 10:38 编辑

       蓝牙BLE设备是目前比较热门的设备。由于BLE有低功耗等特点,被广泛应用到身边的电子产品上。如智能手表、手环、防丢器等各种产品上。最近研究一下android上的ble应用开发。跟大家分享一下相关的内容。
       我的实现使用两台android手机做ble相关的通信,一台机器作为服务端接收发过来的消息,另一台作为客户端发送消息。
       客户端基本流程如下:
       ble.png


1.添加蓝牙相关权限
  1. <uses-permission android:name="android.permission.BLUETOOTH"/>
  2. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
复制代码
2.BLE设备扫描
使用BluetoothAdapter.startLeScan来扫描发现设备,这个方法需要参数BluetoothAdapter.LeScanCallback,所以还需要实现此回调方法,来获取扫描结果。
注意:BLE扫描耗电量比较大,尽可能缩短扫描时间。发现用户所需连接的设备后立即停止扫描
  1. public class DeviceScanActivity extends ListActivity {
  2.     private BluetoothAdapter mBluetoothAdapter;
  3.     private boolean mScanning;
  4.     private Handler mHandler;
  5.     // 10秒后停止寻找.
  6.     private static final long SCAN_PERIOD = 10000;
  7.     ...
  8.     private void scanLeDevice(final boolean enable) {
  9.         if (enable) {
  10.             // 经过预定扫描期后停止扫描
  11.             mHandler.postDelayed(new Runnable() {
  12.                 @Override
  13.                 public void run() {
  14.                     mScanning = false;
  15.                     mBluetoothAdapter.stopLeScan(mLeScanCallback);
  16.                 }
  17.             }, SCAN_PERIOD);
  18.             mScanning = true;
  19.             mBluetoothAdapter.startLeScan(mLeScanCallback);
  20.         } else {
  21.             mScanning = false;
  22.             mBluetoothAdapter.stopLeScan(mLeScanCallback);
  23.         }
  24.         ...
  25.     }
  26. ...
  27. }
复制代码
BLE扫描结果的接口,下面是BluetoothAdapter.LeScanCallback的实现。可以获取到扫描到设备的蓝牙名称和蓝牙地址等。
  1. private LeDeviceListAdapter mLeDeviceListAdapter;
  2. ...
  3. // Device scan callback.
  4. private BluetoothAdapter.LeScanCallback mLeScanCallback =
  5.     new BluetoothAdapter.LeScanCallback() {
  6.     @Override
  7.     public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
  8.         runOnUiThread(new Runnable() {
  9.     @Override
  10.     public void run() {
  11.          device.getName();//获得扫描到设备名称
  12.          device.getAddress();//获取设备蓝牙地址
  13.         }
  14.      });
  15.    }
  16. };
复制代码
3.连接
先获取BluetoothAdapterd,再获取BluetoothDevice。根据扫描的蓝牙设备地址获取BluetoothDevice对象。使用BluetoothDevice.connectGatt进行连接。返回BluetoothGatt实例。
然后使用connectGatt( )方法进行链接。这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接到它),和BluetoothGattCallback调用。后面会详细介绍BluetoothGattCallback的实现。
  1. BluetoothManager mBluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
  2. BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
  3. BluetoothDevice mDevice = mBluetoothAdapter.getRemoteDevice(address);
复制代码
4.发现BLE设备服务
  1. mBluetoothGatt.discoverServices();
复制代码
5.发送Characteristic
发送消息通过读写Characteristic来完成,app完成与GATT服务端连接和发现services后,就可以读写 writeCharacteristic,每个服务和characteristic都有一个UUID来唯一确定,所有想要开发BLE必须知道你想要用哪个服务的那个characteristic也就是要知道对应的UUID。
  1. private void writeCharacteristic(String writeValue) {
  2.         BluetoothGattCharacteristic characteristic =
  3.         getCharacteristic(CHARACTERISTIC_UUID);
  4.         if (characteristic == null) return;
  5.         characteristic.setValue(writeValue);
  6.         mBluetoothGatt.writeCharacteristic(characteristic);
  7. }
  8. private void readCharacteristic() {
  9.         BluetoothGattCharacteristic characteristic =
  10.          getCharacteristic(CHARACTERISTIC_UUID);
  11.         if (characteristic != null) mBluetoothGatt.readCharacteristic(characteristic);
  12. }
复制代码
6.BluetoothGattCallback实现
根据BluetoothGattCallback判断当前状态。获取是否连接成功、是否断开连接、读写Characteristic是否成功等。
  1. private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {
  2.      @Override
  3.      //获取连接状态方法,BLE设备连接上或断开时,会调用到此方
  4.      public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
  5.          if (DEBUG) Log.d(TAG, "onConnectionStateChange");
  6.          if (status == BluetoothGatt.GATT_SUCCESS) {
  7.          if (newState == BluetoothProfile.STATE_CONNECTED) {
  8.              showMessage("Bluetooth LE connected");
  9.         }
  10.         else if (status == BluetoothProfile.STATE_DISCONNECTED) {
  11.              showMessage("Bluetooth LE disconnected");
  12.          }
  13.       }
  14.     }
  15.    
  16.      //成功发现设备的services时,调用此方法
  17.      @Override
  18.      public void onServicesDiscovered(BluetoothGatt gatt, int status) {
  19.          if ((status == BluetoothGatt.GATT_SUCCESS) &&
  20.          (mBluetoothGatt.getService(SERVICE_UUID) != null)) {
  21.              showMessage("Discover service Successful !!!");
  22.          }
  23.       }

  24.     //读写characteristic时会调用到以下方法
  25.      @Override
  26.      public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  27.          if ((status == BluetoothGatt.GATT_SUCCESS) &&
  28.              (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) {
  29.                  showMessage(characteristic.getStringValue(0));
  30.             }
  31.      }

  32.      @Override
  33.      public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
  34.           BluetoothGattCharacteristic mCharacteristic =
  35.              getCharacteristic(CHARACTERISTIC_UUID);
  36.             if ((status == BluetoothGatt.GATT_SUCCESS) &&
  37.                 (characteristic.getStringValue(0).equals(mCharacteristic.getStringValue(0)))) {
  38.                 showMessage("CharacteristicWrite Successful !!!");
  39.             }
  40.         }
  41.     };
复制代码
7.断开链接
  1. mBluetoothGatt.disconnect();
复制代码

以上是客户端(进行消息发送)的实现,下面介绍服务端实现方法。
服务端实现比较简单,首先创建BluetoothManager,使用openGattServer实例mGattServer。openGattServer需要一个BluetoothGattServerCallback回调。创建BluetoothGattService,再把BluetoothGattService添加到BluetoothGattServer中。
  1. BluetoothManager  mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
  2. BluetoothGattServer mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
  3. BluetoothGattService mService = createService();
  4. mGattServer.addService(mService);
复制代码
BluetoothGattServerCallback回调的实现,在这个回调里面可以获取到服务端发送过来的消息,连接状态等
                              
  1. private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {
  2.     @Override
  3.     //获取连接状态方法,BLE设备连接上或断开时,会调用到此方
  4.     public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
  5.         if (DEBUG) Log.d(TAG, "onConnectionStateChange: newState=" + newState);
  6.         if (status == BluetoothGatt.GATT_SUCCESS) {
  7.             if (newState == BluetoothProfile.STATE_CONNECTED) {
  8.                 mDevice = device;
  9.                 String devicename = device.getName();
  10.                 String address = device.getAddress();
  11.                 notifyConnected(devicename);
  12.                 beginNotification();
  13.             } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
  14.                 stopNotification();
  15.                 notifyDisconnected();
  16.                 mDevice = null;
  17.             }
  18.         }
  19.     }

  20.     //service添加成功会调用此方
  21.     @Override
  22.     public void onServiceAdded(int status, BluetoothGattService service) {
  23.         if (DEBUG) Log.d(TAG, "onServiceAdded()");
  24.         if (status == BluetoothGatt.GATT_SUCCESS) notifyServiceAdded();
  25.     }
  26.    
  27.     //读写Characteristic,在此获得客户端发来的消息
  28.     @Override
  29.     public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,BluetoothGattCharacteristic characteristic,
  30.         boolean preparedWrite, boolean responseNeeded,int offset, byte[] value) {
  31.         if (DEBUG) Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);
  32.             try{
  33.                 mCharacteristicString = new String(value); //客户端发来的消息
  34.             }catch(Exception e){
  35.             }
  36.             notifyCharacteristicWriteRequest(mCharacteristicString);
  37.         }
  38.     }

  39.      @Override
  40.     public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
  41.         int offset, BluetoothGattCharacteristic characteristic) {
  42.         if (DEBUG) Log.d(TAG, "onCharacteristicReadRequest()");
  43.             notifyCharacteristicReadRequest();
  44.         }
  45. };
复制代码
android ble的内容就暂时介绍到这里,上面介绍的实现方法,是有一台android手机来模拟一个BLE的设备。拿到真实的BLE设备(防丢器),还会继续发帖分享给大家,希望大家继续关注!!

再发几张我这个测试应用的操作截图
1.在server端点击Start Server,上面文本提示BLE SERVICE ADDED

1server.png
2.在Client端,输入服务端手机的蓝牙地址,然后点在onnect
1client.png

3.进行配对,两台手机分别点击配对
2.png

4.客户端点击Discover service,Toast提示Discover service Successful。
    服务端显示Device Connect。

3.png

5.客户端输入要发送的字符"123456",点击Write Characteristic。
   服务端接收到发送过来的字符,显示Device Write:123456

4.png

6.客户端点击Disconnect断开连接
   服务端显示Device Disconnected

5.png







已有 2评分威望 +20 灯泡 +21 贡献 +22 收起 理由
yhyqf + 10 + 10 + 10 有没有做过android 和IOS之间的BLE连接
linjincn + 10 + 11 + 12

查看全部评分

回复

使用道具 举报

279

积分

10

威望

9

贡献

社区版主

Rank: 7Rank: 7Rank: 7

积分
279
QQ
发表于 2014-11-27 17:32:23     
楼主有心整理了,学习了!
Android BLE现在运用挺广泛的,低功耗市场很大,期待楼主有更深入的技术介绍
{:3_48:}
回复

使用道具 举报

10

积分

0

威望

0

贡献

游客

积分
10
发表于 2015-1-7 15:38:54     
楼主威武呀!能否分享一下你用的是什么版本的android和机型...
我手里的小米只能当client,作为server无法发现,不知道啥原因了!
回复

使用道具 举报

1183

积分

56

威望

1049

贡献

中级创客

Rank: 4

积分
1183
发表于 2015-1-9 19:24:43     
linjincn 发表于 2015-1-7 15:38
楼主威武呀!能否分享一下你用的是什么版本的android和机型...
我手里的小米只能当client,作为server无法 ...

手机只能模拟成BLE设备,不能做真实的设备来使用。
模拟设备时可能出现扫描不到的情况。可以跳过扫描,直接通过手机的蓝牙地址进行链接使用。
手机是ANDROID4.4。
回复

使用道具 举报

2

积分

0

威望

0

贡献

游客

积分
2
发表于 2015-3-31 22:10:57     
您好楼主,我在学习BLE,我用的是SONY的 手机,android 系统4.4.2 KitKat,BLE sensortag 在做。
mBluetoothAdapter.startLeScan(mLeScanCallback);
上面的这个方法在API 19已经不能使用了,然而我换用mBluetoothAdapter.startScan(mLeScanCallback);
也不行。
请帮忙解决一下!谢谢了。
回复

使用道具 举报

8

积分

0

威望

0

贡献

游客

积分
8
发表于 2015-4-17 11:19:20     
楼主,我这里怎么也链接不上。能分享下代码吗?
回复

使用道具 举报

330

积分

0

威望

0

贡献

技术达人

Rank: 2

积分
330
发表于 2018-7-3 11:26:31     
楼主的app,能发出来试试吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

友情链接 : 爱板网 电子发烧友论坛 云汉电子社区 粤ICP备14022046号-2
快速回复 返回顶部 返回列表