BLE(BLuetooth Lower Energy)蓝牙

来源:互联网 发布:网络约车软件有哪些 编辑:程序博客网 时间:2024/05/01 12:50

BLE获得权限


为了在应用程序中使用蓝牙功能,你必须声明 使用蓝牙的权限 。 你需要这个权限执行任何蓝牙通信, 如请求连接,接受连接,传输数据。

如果你想让你的应用程序启动或操作蓝牙设备被发现 设置,您也必须声明 BLUETOOTH_ADMIN 许可。 注意: 如果你使用 BLUETOOTH_ADMIN 权限,那么你必须 也有 蓝牙 权限

在您的应用程序清单文件声明蓝牙权限(s)。 为 例子:

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

如果你想声明应用程序仅BLE-capable设备可用, 在你的应用程序的清单包括以下:

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

然而,如果你想让你的应用程序在不支持BLE设备上可用, 你应该在清单文件中设置 required= " false " 。 然后在程序运行时可以选择BLE功能是否可用 PackageManager.hasSystemFeature() :

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

配置BLE


在您的应用程序通过BLE交流前,你需要验证设备是否支持BLE,如果是这样,确保它是启用的。 注意,这个检查如果仅仅是必要的 < uses-feature…/ > 设置为false。

如果不支持BLE,那么你应该优雅地禁用任何 BLE特性。 如果有幸获得支持,但禁用,那么你可以请求 用户启用蓝牙不离开您的应用程序。 此设置 在两个步骤完成,使用 BluetoothAdapter 

  1. 得到了 BluetoothAdapter

    的 BluetoothAdapter 所有需要吗 蓝牙的活动。 的 BluetoothAdapter 代表 设备的蓝牙适配器(蓝牙无线电)。 有一个蓝牙 对整个系统适配器,使用您的应用程序可以与之交互 这个对象。 下面的代码片段显示了如何获取适配器。 注意,这种方法 使用 getSystemService() 返回 的一个实例 BluetoothManager ,然后 使用适配器。 Android 4.3(API级别18)介绍 BluetoothManager :

    // Initializes Bluetooth adapter.final BluetoothManager bluetoothManager =        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter();
  2. 支持蓝牙

    接下来,您需要确保启用蓝牙。 调用 isEnabled() 检查蓝牙是否 目前启用。 如果这个方法返回false,那么蓝牙是禁用的。 下面的代码片段检查是否启用蓝牙。 如果不是, 片段显示一个错误提示用户设置启用 蓝牙:

    private BluetoothAdapter mBluetoothAdapter;...// Ensures Bluetooth is available on the device and it is enabled. If not,// displays a dialog requesting user permission to enable Bluetooth.if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}

发现BLE设备


找到BLE设备使用 startLeScan() 方法。 该方法以一个 BluetoothAdapter.LeScanCallback 作为参数。 你必须实现这个回调,因为这就是扫描 返回结果。 因为扫描battery-intensive,你应该观察 以下指南:

  • 一旦你找到所需的设备,停止扫描。
  • 从来没有扫描一个循环,设定一个时间限制你的扫描。 一个设备 以前可能搬出去的范围,并继续扫描下水道 电池。

以下代码片段显示了如何启动和停止扫描:

/** * Activity for scanning and displaying available BLE devices. */public class DeviceScanActivity extends ListActivity {    private BluetoothAdapter mBluetoothAdapter;    private boolean mScanning;    private Handler mHandler;    // Stops scanning after 10 seconds.    private static final long SCAN_PERIOD = 10000;    ...    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);                }            }, SCAN_PERIOD);            mScanning = true;            mBluetoothAdapter.startLeScan(mLeScanCallback);        } else {            mScanning = false;            mBluetoothAdapter.stopLeScan(mLeScanCallback);        }        ...    }...}

如果你想只扫描特定类型的外设,可以代替 调用 startLeScan(UUID[],BluetoothAdapter.LeScanCallback) , 提供一个数组的 UUID 对象指定关贸总协定 应用程序支持服务。

这是一个实现的 BluetoothAdapter.LeScanCallback , 接口是用来传递BLE扫描结果:

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

注意: 你只能扫描蓝牙设备 或 扫描经典的蓝牙设备,如中描述 蓝牙 。 你不能 扫描蓝牙勒和经典的设备在同一时间。

连接到一个GATTserver


相互作用的第一步BLE设备连接到它 更具体地说,连接到设备上的关贸总协定服务器。 来 连接到关贸总协定服务器BLE设备上,使用 connectGatt() 方法。 这个方法取三个参数:一个 上下文 对象, 符 (布尔表示是否自动连接 BLE设备尽快可用),和一个引用 BluetoothGattCallback :

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

这个连接到GATT服务器主办的BLE设备,并返回一个 BluetoothGatt 实例,您就可以使用 实施GATT客户操作。 调用者(Android应用程序)是GATT的客户。 的 BluetoothGattCallback 用于交付结果 客户端,如连接状态,以及任何进一步的GATT客户机 操作。

在这个例子中,有幸获得应用程序提供了一个活动 ( DeviceControlActivity )连接, 显示数据,显示关贸总协定的服务和特点 支持的设备。 基于用户输入,这个活动与一个 服务 被称为 BluetoothLeService , 这与BLE设备通过Android BLE API:

// A service that interacts with the BLE device via the Android BLE API.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);    // Various callback methods defined by the 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        // New services discovered        public void onServicesDiscovered(BluetoothGatt gatt, int status) {            if (status == BluetoothGatt.GATT_SUCCESS) {                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);            } else {                Log.w(TAG, "onServicesDiscovered received: " + status);            }        }        @Override        // Result of a characteristic read operation        public void onCharacteristicRead(BluetoothGatt gatt,                BluetoothGattCharacteristic characteristic,                int status) {            if (status == BluetoothGatt.GATT_SUCCESS) {                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);            }        }     ...    };...}

当一个特定的触发回调,它调用合适的 broadcastUpdate() 助手方法并将其传递一个动作。 注意,数据 解析执行本节按照蓝牙心率 测量 概要文件规范 :

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);    // This is special handling for the Heart Rate Measurement profile. Data    // parsing is carried out as per profile specifications.    if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {        int flag = characteristic.getProperties();        int format = -1;        if ((flag & 0x01) != 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 {        // For all other profiles, writes the data formatted in HEX.        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 :

// Handles various events fired by the Service.// ACTION_GATT_CONNECTED: connected to a GATT server.// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.// ACTION_DATA_AVAILABLE: received data from the device. This can be a// result of read or notification operations.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)) {            // Show all the supported services and characteristics on the            // user interface.            displayGattServices(mBluetoothLeService.getSupportedGattServices());        } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {            displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));        }    }};

阅读BLE属性


一旦你的Android应用程序连接到一个服务器关贸总协定和发现服务, 它可以读取和写入属性,支持。 例如,这个片段迭代 通过服务器的服务和特点并将它们显示在UI中:

public class DeviceControlActivity extends Activity {    ...    // Demonstrates how to iterate through the supported GATT    // Services/Characteristics.    // In this sample, we populate the data structure that is bound to the    // ExpandableListView on the UI.    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>>();        // Loops through available 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>();           // Loops through available 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);         }    ...    }...}

接收GATT通知


它的普遍应用要求在某一特定时得到通知 设备上的变化特点。 这个代码片段展示了如何设置一个通知 的特点,使用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// Characteristic notificationpublic void onCharacteristicChanged(BluetoothGatt gatt,        BluetoothGattCharacteristic characteristic) {    broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);}

关闭客户端应用程序


一旦你的应用程序使用BLE设备已经完成,它应该叫 close() 因此,系统可以适当释放资源:

public void close() {    if (mBluetoothGatt == null) {        return;    }    mBluetoothGatt.close();    mBluetoothGatt = null;}
0 0