您的位置:首页 > 移动开发 > Android开发

android蓝牙4.0开发

2016-05-12 12:14 423 查看
最近在开发智能手环的东西,了解了关于蓝牙4.0方面的东西,提供给大家:

蓝牙开发的基本步骤

1 添加权限 

   <uses-permission android:name="android.permission.BLUETOOTH"/>

   <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

2 app只为具有BLE的设备提供

   <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

3 但是如果想让你的app提供给那些不支持BLE的设备,需要在manifest中包括上面代码并设置required="false",然后在运行时可以通过使用PackageManager.hasSystemFeature()确定BLE的可用性。

   if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {

    Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();

    finish();

  }

4 获取 BluetoothAdapter

  所有的蓝牙活动都需要蓝牙适配器。BluetoothAdapter代表设备本身的蓝牙适配器(蓝牙无线)。整个系统只有一个蓝牙适配器,而且你的app使用它与系统交互。

  下面的代码片段显示了如何得到适配器。注意该方法使用getSystemService()]返回BluetoothManager,然后将其用于获取适配器的一个实例。Android 4.3(API 18)引入BluetoothManager。

 

  // 初始化蓝牙适配器

  final BluetoothManager bluetoothManager =(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

  mBluetoothAdapter = bluetoothManager.getAdapter();

5  开启蓝牙

   你需要确认蓝牙是否开启。调用isEnabled())去检测蓝牙当前是否开启。如果该方法返回false,蓝牙被禁用。下面的代码检查蓝牙是否开启,如果没有开启,将显示错误提示用户去设置开启蓝牙。

   // 确保蓝牙在设备上可以开启

   if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {

   Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

   startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

   }

  

6  发现BLE设备

   为了发现BLE设备,使用startLeScan())方法。这个方法需要一个参数BluetoothAdapter.LeScanCallback。你必须实现它的回调函数,那就是返回的扫描结果。因为扫描非常消耗电量,你应当遵守以下准则:

   •只要找到所需的设备,停止扫描。

  •不要在循环里扫描,并且对扫描设置时间限制。以前可用的设备可能已经移出范围,继续扫描消耗电池电量。

 

   下面代码显示了如何开始和停止一个扫描:

   /**

 * 扫描和显示可以提供的蓝牙设备.

 */

public class DeviceScanActivity extends ListActivity {

    private BluetoothAdapter mBluetoothAdapter;

    private boolean mScanning;

    private Handler mHandler;

    // 10秒后停止寻找.

    private static final long SCAN_PERIOD = 10000;

    ...

    private void scanLeDevice(final boolean enable) {

        if (enable) {

            // 经过预定扫描期后停止扫描

            mHandler.postDelayed(new Runnable() {

                @Override

                public void run() {

                    mScanning = false;

                    mBluetoothAdapter.stopLeScan(mLeScanCallback);

                }

            }, SCAN_PERIOD);

            mScanning = true;

            mBluetoothAdapter.startLeScan(mLeScanCallback);

        } else {

            mScanning = false;

            mBluetoothAdapter.stopLeScan(mLeScanCallback);

        }

        ...

    }

...

}

  如果你只想扫描指定类型的外围设备,可以改为调用startLeScan(UUID[], BluetoothAdapter.LeScanCallback)),需要提供你的app支持的GATT services的UUID对象数组。

作为BLE扫描结果的接口,下面是BluetoothAdapter.LeScanCallback的实现。

  private LeDeviceListAdapter mLeDeviceListAdapter;

...

// 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();

           }

       });

   }

};

注意:只能扫描BLE设备或者扫描传统蓝牙设备,不能同时扫描BLE和传统蓝牙设备。

7  连接到GATT服务端

  

   与一个BLE设备交互的第一步就是连接它——更具体的,连接到BLE设备上的GATT服务端。为了连接到BLE设备上的GATT服务端,需要使用connectGatt( )方法。这个方法需要三个参数:一个Context对象,

   自动连接(boolean值,表示只要BLE设备可用是否自动连接到它),和BluetoothGattCallback调用。

   mBluetoothGatt = device.connectGatt(this, false, mGattCallback);

   连接到GATT服务端时,由BLE设备做主机,并返回一个BluetoothGatt实例,然后你可以使用这个实例来进行GATT客户端操作。请求方(Android app)是GATT客户端。BluetoothGattCallback用于传递结果给用户,

   例如连接状态,以及任何进一步GATT客户端操作。

   在这个例子中,这个BLE APP提供了一个activity(DeviceControlActivity)来连接,显示数据,显示该设备支持的GATT services和characteristics。根据用户的输入,这个activity与BluetoothLeService通信,

   通过Android BLE API实现与BLE设备交互。

   //通过BLE API服务端与BLE设备交互

  

public class BluetoothLeService extends Service {

    private final static String TAG = BluetoothLeService.class.getSimpleName();

    private BluetoothManager mBluetoothManager; //蓝牙管理器

    private BluetoothAdapter mBluetoothAdapter; //蓝牙适配器

    private String mBluetoothDeviceAddress; //蓝牙设备地址

    private BluetoothGatt mBluetoothGatt;

    private int mConnectionState = STATE_DISCONNECTED;

    private static final int STATE_DISCONNECTED = 0; //设备无法连接

    private static final int STATE_CONNECTING = 1;  //设备正在连接状态

    private static final int STATE_CONNECTED = 2;   //设备连接完毕

    public final static String ACTION_GATT_CONNECTED =

            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";

    public final static String ACTION_GATT_DISCONNECTED =

            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";

    public final static String ACTION_GATT_SERVICES_DISCOVERED =

            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";

    public final static String ACTION_DATA_AVAILABLE =

            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";

    public final static String EXTRA_DATA =

            "com.example.bluetooth.le.EXTRA_DATA";

    public final static UUID UUID_HEART_RATE_MEASUREMENT =

            UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);

    //通过BLE API的不同类型的回调方法

    private final BluetoothGattCallback mGattCallback =

            new BluetoothGattCallback() {

        @Override

        public void onConnectionStateChange(BluetoothGatt gatt, int status,

                int newState) {//当连接状态发生改变

            String intentAction;

            if (newState == BluetoothProfile.STATE_CONNECTED) {//当蓝牙设备已经连接

                intentAction = ACTION_GATT_CONNECTED;

                mConnectionState = STATE_CONNECTED;

                broadcastUpdate(intentAction);

                Log.i(TAG, "Connected to GATT server.");

                Log.i(TAG, "Attempting to start service discovery:" +

                        mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {//当设备无法连接

                intentAction = ACTION_GATT_DISCONNECTED;

                mConnectionState = STATE_DISCONNECTED;

                Log.i(TAG, "Disconnected from GATT server.");

                broadcastUpdate(intentAction);

            }

        }

        @Override

        // 发现新服务端

        public void onS
be11
ervicesDiscovered(BluetoothGatt gatt, int status) {

            if (status == BluetoothGatt.GATT_SUCCESS) {

                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);

            } else {

                Log.w(TAG, "onServicesDiscovered received: " + status);

            }

        }

        @Override

        // 读写特性

        public void onCharacteristicRead(BluetoothGatt gatt,

                BluetoothGattCharacteristic characteristic,

                int status) {

            if (status == BluetoothGatt.GATT_SUCCESS) {

                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);

            }

        }

     ...

    };

...

}

   当一个特定的回调被触发的时候,它会调用相应的broadcastUpdate()辅助方法并且传递给它一个action。注意在该部分中的数据解析按照蓝牙心率测量配置文件规格进行。

  

   private void broadcastUpdate(final String action) {

    final Intent intent = new Intent(action);

    sendBroadcast(intent);

}

private void broadcastUpdate(final String action,

                             final BluetoothGattCharacteristic characteristic) {

    final Intent intent = new Intent(action);

    // 这是心率测量配置文件。

    if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {

        int flag = characteristic.getProperties();

        int format = -1;

        if ((flag & x01) != 0) {

            format = BluetoothGattCharacteristic.FORMAT_UINT16;

            Log.d(TAG, "Heart rate format UINT16.");

        } else {

            format = BluetoothGattCharacteristic.FORMAT_UINT8;

            Log.d(TAG, "Heart rate format UINT8.");

        }

        final int heartRate = characteristic.getIntValue(format, 1);

        Log.d(TAG, String.format("Received heart rate: %d", heartRate));

        intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));

    } else {

        // 对于所有其他的配置文件,用十六进制格式写数据

        final byte[] data = characteristic.getValue();

        if (data != null && data.length > 0) {

            final StringBuilder stringBuilder = new StringBuilder(data.length);

            for(byte byteChar : data)

                stringBuilder.append(String.format("%02X ", byteChar));

            intent.putExtra(EXTRA_DATA, new String(data) + "\n" +

                    stringBuilder.toString());

        }

    }

    sendBroadcast(intent);

}

返回DeviceControlActivity, 这些事件由一个BroadcastReceiver来处理:

// 通过服务控制不同的事件

// ACTION_GATT_CONNECTED: 连接到GATT服务端

// ACTION_GATT_DISCONNECTED: 未连接GATT服务端.

// ACTION_GATT_SERVICES_DISCOVERED: 未发现GATT服务.

// ACTION_DATA_AVAILABLE: 接受来自设备的数据,可以通过读或通知操作获得。

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {

    @Override

    public void onReceive(Context context, Intent intent) {

        final String action = intent.getAction();

        if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {

            mConnected = true;

            updateConnectionState(R.string.connected);

            invalidateOptionsMenu();

        } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {

            mConnected = false;

            updateConnectionState(R.string.disconnected);

            invalidateOptionsMenu();

            clearUI();

        } else if (BluetoothLeService.

                ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {

            // 在用户接口上展示所有的services and characteristics

            displayGattServices(mBluetoothLeService.getSupportedGattServices());

        } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {

            displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));

        }

    }

};

8 读取BLE变量

   你的android app完成与GATT服务端连接和发现services后,就可以读写支持的属性。例如,这段代码通过服务端的services和 characteristics迭代,并且将它们显示在UI上。

   public class DeviceControlActivity extends Activity {

    ...

    // 演示如何遍历支持GATT Services/Characteristics

    // 这个例子中,我们填充绑定到UI的ExpandableListView上的数据结构

    private void displayGattServices(List<BluetoothGattService> gattServices) {

        if (gattServices == null) return;

        String uuid = null;

        String unknownServiceString = getResources().

                getString(R.string.unknown_service);

        String unknownCharaString = getResources().

                getString(R.string.unknown_characteristic);

        ArrayList<HashMap<String, String>> gattServiceData =

                new ArrayList<HashMap<String, String>>();

        ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData

                = new ArrayList<ArrayList<HashMap<String, String>>>();

        mGattCharacteristics =

                new ArrayList<ArrayList<BluetoothGattCharacteristic>>();

        // 循环可用的GATT Services.

        for (BluetoothGattService gattService : gattServices) {

            HashMap<String, String> currentServiceData =

                    new HashMap<String, String>();

            uuid = gattService.getUuid().toString();

            currentServiceData.put(

                    LIST_NAME, SampleGattAttributes.

                            lookup(uuid, unknownServiceString));

            currentServiceData.put(LIST_UUID, uuid);

            gattServiceData.add(currentServiceData);

            ArrayList<HashMap<String, String>> gattCharacteristicGroupData =

                    new ArrayList<HashMap<String, String>>();

            List<BluetoothGattCharacteristic> gattCharacteristics =

                    gattService.getCharacteristics();

            ArrayList<BluetoothGattCharacteristic> charas =

                    new ArrayList<BluetoothGattCharacteristic>();

           // 循环可用的Characteristics.

            for (BluetoothGattCharacteristic gattCharacteristic :

                    gattCharacteristics) {

                charas.add(gattCharacteristic);

                HashMap<String, String> currentCharaData =

                        new HashMap<String, String>();

                uuid = gattCharacteristic.getUuid().toString();

                currentCharaData.put(

                        LIST_NAME, SampleGattAttributes.lookup(uuid,

                                unknownCharaString));

                currentCharaData.put(LIST_UUID, uuid);

                gattCharacteristicGroupData.add(currentCharaData);

            }

            mGattCharacteristics.add(charas);

            gattCharacteristicData.add(gattCharacteristicGroupData);

         }

    ...

    }

...

}

9   接收GATT通知

当设备上的特性改变时会通知BLE应用程序。这段代码显示了如何使用setCharacteristicNotification( )给一个特性设置通知。

private BluetoothGatt mBluetoothGatt;

BluetoothGattCharacteristic characteristic;

boolean enabled;

...

mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

...

BluetoothGattDescriptor descriptor = characteristic.getDescriptor(

        UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));

descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);

mBluetoothGatt.writeDescriptor(descriptor);

如果对一个特性启用通知,当远程蓝牙设备特性发送变化,回调函数onCharacteristicChanged( ))被触发。

@Override

// 广播更新

public void onCharacteristicChanged(BluetoothGatt gatt,

        BluetoothGattCharacteristic characteristic) {

    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);

}

10 关闭客户端App

当你的app完成BLE设备的使用后,应该调用close( )),系统可以合理释放占用资源

public void close() {

    if (mBluetoothGatt == null) {

        return;

    }

    mBluetoothGatt.close();

    mBluetoothGatt = null;

最后提供给大家一个网址,可以了解更多蓝牙方面的知识:
蓝牙4.0——Android BLE开发官方文档翻译的地址:

  http://ricardoli.com/2014/07/31/%E8%93%9D%E7%89%9940%E2%80%94%E2%80%94android-ble%E5%BC%80%E5%8F%91%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%E7%BF%BB%E8%AF%91/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 蓝牙