很久没记录东西了,前段时间研究了一哈android4.0控制多个外设的情况,注意,需要使用android版本4.3以上,蓝牙4.0及以上。

我这里使用的控制蓝牙灯泡,使用android4.3的手机,手机上的蓝牙是4.0.

记得在manifest文件中加入权限:

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

先拿到BluetoothManager和BluetoothAdapter的对象。

        // 初始化 Bluetooth adapter, 通过蓝牙管理器得到一个参考蓝牙适配器(API必须在以上android4.3或以上和版本)
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter(); // 检查设备上是否支持蓝牙
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);
}
}

调用startScan方法开始扫描,stopScan方法停止扫描,扫描到的设备都在回调函数里。

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

扫描后的BluetoothDevice加入到列表中,这时列表中就会有设备,通过getName可以获取设备的蓝牙名字,getAddress获取设备的蓝牙地址。

列表出来了之后,点击某个设备进行连接。

注意这里的连接跟2.0的蓝牙的连接不一样,通过设备的connectGatt方法进行连接,连接完成后会获得一个BluetoothGatt的对象,这个对象中有连接的一些重要信息,切记要保存好。

public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
} if (mBluetoothDeviceAddress != null
&& address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG,
"Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
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, true, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
bluetoothGatts.add(mBluetoothGatt);
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) {
System.out.println("onConnectionStateChange");
String intentAction;
if (status == BluetoothProfile.STATE_DISCONNECTED
&& newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:"
+ mBluetoothGatt.discoverServices());
Log.e("shang", "连接成功");
mHandler.sendEmptyMessage(MESSAGE_START_SUCCESS);
} else if (status == BluetoothProfile.STATE_DISCONNECTED
&& newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
setConnStatus(false);
Log.e("shang", "连接失败");
Log.i(TAG, "Disconnected from GATT server.");
mHandler.sendEmptyMessage(STATE_CONNECTFAILED);
}
} @Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
System.out.println("onServicesDiscovered-----");
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
displayGattServices(getSupportedGattServices());
mHandler.sendEmptyMessage(MESSAGE_BLUETOOTH_INIT);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
} @Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
System.out.println("onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
} @Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor, int status) { System.out.println("onDescriptorWriteonDescriptorWrite = " + status
+ ", descriptor =" + descriptor.getUuid().toString());
} @Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
if (characteristic.getValue() != null) { System.out.println(characteristic.getStringValue(0));
}
System.out.println("--------onCharacteristicChanged-----");
} @Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { } public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
System.out.println("--------write success----- status:" + status);
};
};

连接时会走这个方法onConnectionStateChange,传过来的新状态是连接状态,这时在这个方法中调用一下这句:mBluetoothGatt.discoverServices(),

mBluetoothGatt是连接完成时的对象,还记得吧,调用这句后,会走回调函数的onServicesDiscovered方法。在这个方法中去获取设备的一些服务,蓝牙通道,然后通过这些通道去发送数据给外设。

查看该外设中支持的一些服务通道:

public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null)
return null; return mBluetoothGatt.getServices();
}
// 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;
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();
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();
gattCharacteristicGroupData.add(currentCharaData);
}
mGattCharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
bluetoothGattChacteristics.add(mGattCharacteristics);
}

然后就可以通过Gatt这个对像,就是蓝牙连接完成后获取到的对象,通过这个对象设置好指定的通道向设备中写入和读取数据。

写数据:

public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
} mBluetoothGatt.writeCharacteristic(characteristic);
}

读数据:

/**
* Request a read on a given {@code BluetoothGattCharacteristic}. The read
* result is reported asynchronously through the
* {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* @param characteristic
* The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}

注意:BluetoothGattCharacteristic这个是指定的通道,蓝牙服务:

BluetoothGattCharacteristic characteristic = null;
characteristic = mGattCharacteristics.get(4).get(4);

这两个数字就是从指定的服务中找到你要发送数据的那个服务。

  最后,如果要进行多个连接,每次连接完成后可以将BluetoothGatt的对象放到一个list里面,获取到的服务也放到一个List里面,然后发送数据的时候调用不同的Gatt发送不同的通道数据即可。

关于蓝牙4.0的BluetoothLeGatt连接,android Samples有一个例子,发上来吧,需要的朋友可以下载看看。

BluetoothLeGatt

android 蓝牙4.0多通道的更多相关文章

  1. Android 蓝牙4.0 BLE

    Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用. BLE是蓝牙4.0的核心Profil ...

  2. Android 蓝牙4.0 BLE (onServicesDiscovered 返回 status 是 129,133时)

    Android ble (Bluetooth Low Energy) 蓝牙4.0,也就是说android 4.3+, API level >= 18,且支持蓝牙4.0的手机才可以使用. BLE是 ...

  3. android 蓝牙4.0 开发介绍

    最近一直在研究一个蓝牙功能 由于本人是菜鸟  学起来比较忙 一直搞了好久才弄懂 , 网上对蓝牙4.0也就是几个个dome 抄来抄去,全是英文注解 , 对英语不好的朋友来说 真是硬伤 , 一些没必要的描 ...

  4. ym——物联网入口之中的一个Android蓝牙4.0

    转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 假设还有同学不知道蓝牙4.0能够做什么请查看Android+蓝牙 4.0 将带来什么? ...

  5. Android 蓝牙4.0的连接和通讯

    1.加入权限 <uses-sdk android:minSdkVersion=" android:targetSdkVersion="/> <uses-featu ...

  6. android蓝牙4.0(BLE)开发之ibeacon初步

    一个april beacon里携带的信息如下 ? 1 <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC ...

  7. Android蓝牙2.0连接以及数据接收发送

    1.加入权限 <uses-feature android:name="android.hardware.bluetooth_le" android:required=&quo ...

  8. Bluetooth---初步了解Android 蓝牙4.0

    http://developer.android.com/reference/android/bluetooth/package-summary.html android.bluttooth 提供管理 ...

  9. 深入了解Android蓝牙Bluetooth——《进阶篇》

    在 [深入了解Android蓝牙Bluetooth--<基础篇>](http://blog.csdn.net/androidstarjack/article/details/6046846 ...

随机推荐

  1. haartraining生成.xml过程

    继续向大神学习http://www.cnblogs.com/tornadomeet/archive/2012/03/28/2420936.html

  2. 让jar程序在linux上一直执行

    当我们把java程序打成jar包后,放到linux上通过putty或其它终端执行的时候,如果按照:java -jar xxxx.jar执行,当我们退出putty或终端的时候,xxxx.jar这个程序也 ...

  3. HDU3466背包01

    Proud Merchants Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) ...

  4. poj 3020 最短路径覆盖 Antenna Placement

    Antenna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7329   Accepted: 3635 ...

  5. FlashDevelop快捷键

    将鼠标点到变量上面后,同时按ctrl+shift+1(左键盘),可以自动添加变量或者函数.复制一行代码.CTRL+D:ctrl+shift+k 颜色代码拾取器 ctrl+shift+b 注释年选代码段 ...

  6. [MySQL] - MySQL的Grant命令

    本文实例,运行于 MySQL 5.0 及以上版本. MySQL 赋予用户权限命令的简单格式可概括为: grant 权限 on 数据库对象 to 用户 一.grant 普通数据用户,查询.插入.更新.删 ...

  7. hdu5832 A water problem

    A water problem Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  8. POJ 3904 Sky Code (容斥原理)

    B - Sky Code Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit ...

  9. 队列——解密QQ号

    队列——解密QQ号 --转自啊哈磊[坐在马桶上看算法]算法4:队列——解密QQ号 新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问QQ号,小哈当然不会直接告诉小哼啦,原因嘛你懂的 ...

  10. ANT 环境搭建

      一.ant的下载 ant是Apache的一个项目(http://ant.apache.org/),目前的最新版是1.8.4(http://ant.apache.org/bindownload.cg ...