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

android蓝牙ble4.0开发

2015-11-18 22:26 483 查看
1、权限配置

AndroidManifest.xml里配置,“android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行。

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


2、判断是否支持蓝牙

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}


3、打开和关闭蓝牙

先获取蓝牙适配器:

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


如果蓝牙关闭,则打开蓝牙:

if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}


public void onActivityResult(int requestCode, int resultCode, Intent data){  
       if(requestCode == REQUEST_ENABLE_BT){  
              if(requestCode == RESULT_OK){  
                   //蓝牙已经开启   
              }  
       }  
}


// 也可以用enable()方法来开启,无需询问用户(无声息的开启蓝牙设备),这时就需要用到android.permission.BLUETOOTH_ADMIN权限。

// mBluetoothAdapter.enable(); //打开蓝牙

// mBluetoothAdapter.disable();//关闭蓝牙

注意,如果用静默的方式打开蓝牙,不能马上开始扫描,这样会失败,因为打开蓝牙要一两秒时间。

4、搜索蓝牙

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);
}
在4.3之前的api是通过注册广播来处理搜索时发生的一些事件,使用startDiscovery()这个函数搜索,而支持ble的新的api中,是通过回调的方式来处理的,mLeScanCallback就是一个接口对象。

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


device代表蓝牙设备,rssi是信号强度,scanRecord是广播数据,一些项目要求广播匹配蓝牙设备才能被发现,就是根据把产品ID写到广播里来判别。如下:



4.3以下的通过广播方式来搜索,如下:

// 设置广播信息过滤
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
// 注册广播接收器,接收并处理搜索结果
context.registerReceiver(receiver, intentFilter);
// 寻找蓝牙设备,android会将查找到的设备以广播形式发出去
adapter.startDiscovery();
private BroadcastReceiver receiver = new BroadcastReceiver() {   
   @Override   
  public void onReceive(Context context, Intent intent) {   
       String action = intent.getAction();   
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {   
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);   
            System.out.println(device.getName());   
       }   
   }   
}


另外,还可以配置本机蓝牙是否可见,被对方搜索到:

//使本机蓝牙在300秒内可被搜索
private void ensureDiscoverable() {
if (mBluetoothAdapter.getScanMode() !=   BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
还有查找以前配对过的设备:

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
//device.getName() +" "+ device.getAddress());
}
} else {
mPairedDevicesArrayAdapter.add("没有找到已匹对的设备");
}


5、蓝牙连接

两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。
连接GATT Server,你需要调用BluetoothDevice的connectGatt()方法。此函数带三个参数:Context、autoConnect(boolean)和BluetoothGattCallback对象。调用示例:
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
函数成功,返回BluetoothGatt对象,它是GATT
profile的封装。通过这个对象,我们就能进行GATT Client端的相关操作。BluetoothGattCallback用于传递一些连接状态及结果。

BluetoothGatt常规用到的几个操作示例:
connect() :连接远程设备。
discoverServices() : 搜索连接设备所支持的service。
disconnect():断开与远程设备的GATT连接。
close():关闭GATT Client端。
readCharacteristic(characteristic) :读取指定的characteristic。
setCharacteristicNotification(characteristic, enabled) :设置当指定characteristic值变化时,发出通知。
getServices() :获取远程设备所支持的services。

google的demo里,连接蓝牙,首先绑定一个服务:

Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);


// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName componentName,
IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service)
.getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
// Automatically connects to the device upon successful start-up
// initialization.
mBluetoothLeService.connect(mDeviceAddress);
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};



initialize()初始化函数里,主要是获得mBluetoothManager和mBluetoothAdapter:

/**
* Initializes a reference to the local Bluetooth adapter.
*
* @return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}

mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}

return true;
}
连接函数mBluetoothLeService.connect里,先用getRemoteDevice获取BluetoothDevice,然后调用connectGatt函数连接,连接成功返回BluetoothGatt。

/* Connects to the GATT server hosted on the Bluetooth LE device.
*
* @param address The device address of the destination device.
*
* @return Return true if the connection is initiated successfully. The connection result
*         is reported asynchronously through the
*         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
*         callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}

// Previously connected device.  Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}

final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found.  Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
System.out.println("device.getBondState=="+device.getBondState());
return true;
}

这里的mGattCallback是蓝牙连接和通讯读写和收到通知时的回调函数。
//蓝牙数据返回
// Implements callback methods for GATT events that the app cares about.  For example,
// connection change and services discovered.
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.");
// Attempts to discover services after successful connection.
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 onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
System.out.println("onServicesDiscovered received: " + status);
}
}

public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
Log.e(TAG, "onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"onCharRead "+gatt.getDevice().getName()
+" read "
+characteristic.getUuid().toString()
+" -> "
+UMDataProcessUtil.bytesToHexString(characteristic.getValue()));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);

}
}
/**
* 返回数据。
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
//数据
Log.i("onCharacteristicChanged", "返回读出的值");
Log.e("notify data:", UMDataProcessUtil.bytesToHexString(characteristic.getValue()));

}

};


6、蓝牙通讯

BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value

我们一般需要操作的是Characteristic,需要先获取Service,然后可以进行读、写和打开通知操作。

public static final UUID SERVIE_UUID = UUID.fromString("0000FE95-0000-1000-8000-00805f9b34fb");

BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);

1)、Characteristic读操作
    public static final UUID LIGHT_UUID = UUID.fromString("00001006-0000-1000-8000-00805F9B34FB");
public void readLlsAlertLevel(){
BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
if (linkLossService == null) {
showMessage("readLlsAlertLevel, link loss Alert service not found!");
return;
}
BluetoothGattCharacteristic alertLevel = linkLossService.getCharacteristic(STATE_UUID);
if(mBluetoothGatt.readCharacteristic(alertLevel)) {
Log.e("test","ble read success");
} else {
Log.e("test","ble read fail");
}

}

蓝牙读操作对应上面mGattCallback的函数是onCharacteristicRead,执行完读之后可以在onCharacteristicRead里收到读的数据。

2)Characteristic写操作
public void writeLlsAlertLevel(int iAlertLevel, byte[] bb) {

BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
if (linkLossService == null) {
showMessage("writeLlsAlertLevel,link loss Alert service not found!");
return;
}

BluetoothGattCharacteristic alertLevel = null;
alertLevel = linkLossService.getCharacteristic(KEY_UUID);
if (alertLevel == null) {
showMessage("writeLlsAlertLevel,link loss Alert Level charateristic not found!");
return;
}

int storedLevel = alertLevel.getWriteType();
Log.d(TAG, "storedLevel() - storedLevel=" + storedLevel);

alertLevel.setValue(bb);
Log.e("发送的指令", "bb" + bb[0]);

alertLevel.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
boolean status = mBluetoothGatt.writeCharacteristic(alertLevel);
Log.d(TAG, "writeLlsAlertLevel() - status=" + status);
}
蓝牙写操作对应上面mGattCallback的函数是onCharacteristicWrite,但是我们一般没有必要监视这个,直接从返回的status判断是否写成功就行了。

3)Characteristic打开\关闭notify
如果我们要长期监视蓝牙设备的状态变化,一般需要用到notify功能。
public boolean enableStateNotification(boolean enable){

BluetoothGattService linkLossService = mBluetoothGatt.getService(SERVIE_UUID);
if (linkLossService == null) {
showMessage("enableStateNotification, link loss Alert service not found!");
return false;
}
BluetoothGattCharacteristic characteristic = linkLossService.getCharacteristic(STATE_UUID);
int charaProp = characteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) <= 0)
{
showMessage("getProperties wrong!Not PROPERTY_NOTIFY !");
return false;
}
return setCharacteristicNotification(characteristic,enable);
}


public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
 /**
     * Enables or disables notification on a give characteristic.
     * @param characteristic Characteristic to act on.
     * @param enabled If true, enable notification.  False otherwise.
     */
    public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return false;
        }
        boolean result =mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        if(!result){
         <span style="white-space:pre">	</span>Log.e(TAG, "setCharacteristicNotification fail!!!!!!!!!!!");
        <span style="white-space:pre">	</span>return false;
        }

        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                UUID.fromString(UMGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        return  mBluetoothGatt.writeDescriptor(descriptor);
       
    }


蓝牙notify操作对应上面mGattCallback的函数是onCharacteristicChanged,打开之后,可以在这个函数里监视notify的数据变化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: