首先,进行一下科普:

1.BLE(Bluetooth Low Energy),蓝牙4.0核心profile,主要特点是快速搜索,快速连接,超低功耗保持连接和数据传输,缺点:数据传输速率低,由于其具有低功耗特点,故而经常用在可穿戴设备之中。Android4.3才开始支持BLE api。

2.关于BLE数据传输:

a.profile可以理解为一种规范,一个标准的通信协议,其存在于手机中,蓝牙组织规定了一些标准的profile:HID OVER GATT ,防丢器等,每个profile中包含了多个service。

b.service 可以理解为一个服务,在BLE从机中有多个服务,电量信息,系统服务信息等,每一个service中包含了多个characteristic特征值,每一个具体的characteristic特征值才是BLE通信的主题。

举个例子吧:从机当前的电量是80%,从机会借由电量的characteristic特征值将这个信息储存于从机的profile中,主机可以通过该characteristic来读取80%这个数据。

c.characteristic特征值:BLE主机从机通信均是通过characteristic进行,可以将其理解为一个标签,通过该标签可以读取或写入相关信息。

d. UUID(统一标识码):service和characteristic均需要这个唯一的UUID进行标识

/****************************************************************************************/

科普结束,首先上效果图:

Android和BLE模块连接通信-LMLPHP

这个就是实现后的效果,我用的BLE模块是:MicrodunioBT4.0

/*********************************************************分隔符********************************************************************************/

BLE设备和Android应用进行通信,首先要做的就是让Android应用找到BLE设备(代码分析部分,只对关键点进行注释)

package com.TANK.temperature.BT;

import java.util.List;

import com.TANK.temperature.R;
import com.TANK.temperature.BT.BluetoothLeClass.OnDataAvailableListener;
import com.TANK.temperature.BT.BluetoothLeClass.OnServiceDiscoverListener; import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.net.wifi.WifiConfiguration.Status;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast; public class DeviceScanActivity extends Activity {
private final static String TAG = DeviceScanActivity.class.getSimpleName();
private final static String UUID_KEY_DATA = "0000fff6-0000-1000-8000-00805f9b34fb";
private Handler mHandler;
private static final long SCAN_PERIOD = 10000; /** 搜索BLE终端 */
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeClass mBLE;
private boolean mScanning;
private BluetoothDevice BTtoLink = null;
private String BTtoFind = "Microduino"; private TextView BT_find, BT_info, BT_link;//三个textview分别表示:设备是否找到,BLE模块传输的信息,连接状态
private String S_BT_info = "null", info = "111"; @Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState); setContentView(R.layout.temperature);
mHandler = new Handler(); BT_find = (TextView) findViewById(R.id.BT_find);
BT_info = (TextView) findViewById(R.id.BT_info);
BT_link = (TextView) findViewById(R.id.BT_link);
          
Typeface typeface = Typeface.createFromAsset(getAssets(),
"fonts/maozedong.ttf");//设置显示字体
BT_find.setTypeface(typeface);
BT_info.setTypeface(typeface);
BT_link.setTypeface(typeface); BT_find.setText("查找中");
BT_info.setText("null");
BT_link.setText("未连接"); if (!getPackageManager().hasSystemFeature( //判断主机是否支BLE牙设备
PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE is not supported", Toast.LENGTH_SHORT)
.show();
finish(); }
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);//获得Android设备中的bluetoothmanager
mBluetoothAdapter = bluetoothManager.getAdapter();//获得bluetoothadapter
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth not supported", Toast.LENGTH_SHORT)
.show();
finish();
return;
}
mBluetoothAdapter.enable(); //强制使能Bluetoothadapter,打开Android设备蓝牙
mBLE = new BluetoothLeClass(this); //BLuetoothLeClass类
if (!mBLE.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish(); } // 发现BLE终端的Service时回调
mBLE.setOnServiceDiscoverListener(mOnServiceDiscover); // 收到BLE终端数据交互的事件
mBLE.setOnDataAvailableListener(mOnDataAvailable); } @Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
scanLeDevice(true);//搜索BLE设备
} @Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
scanLeDevice(false);
mBLE.disconnect();
} @Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
mBLE.close();
} private void scanLeDevice(final boolean enable) {
// TODO Auto-generated method stub
if (enable) { mHandler.postDelayed(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback); }
}, SCAN_PERIOD);//在搜索时间内,关闭搜索标志,不对搜索回调函数进行响应
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback); } } /**
* 搜索到BLE终端服务的事件
*/
private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener() { @Override
public void onServiceDiscover(BluetoothGatt gatt) { displayGattServices(mBLE.getSupportedGattService());
} }; /**
* 收到BLE终端数据交互的事件
*/
private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener() { /**
* BLE终端数据写入的事件
*/
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS)
Log.e(TAG,
"onCharRead "
+ gatt.getDevice().getName()
+ " read "
+ characteristic.getUuid().toString()
+ " -> "
+ Utils.bytesToHexString(characteristic
.getValue())); } /**
* 对BLE终端读取数据
*/
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
info = new String(characteristic.getValue());//对得到的byte数组进行解码,构造新的string
Log.e(TAG, "onCharWrite " + gatt.getDevice().getName() + " write "
+ characteristic.getUuid().toString() + " -> " + info);
if (!S_BT_info.equals(info)) {//判断读取的数据是否发生变化,如果变化,更新UI
DeviceScanActivity.this.runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
BT_link.setText("已连接");
StringBuilder sb = new StringBuilder();//详情参见:http://blog.csdn.net/rmn190/article/details/1492013
sb.append(info);
sb.append("度");
BT_info.setText(sb.toString());
sb = null; }
}); } }
}; private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {//搜索回调函数:
String BT_name = null; @Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
BT_name = device.getName();
if (BT_name.equals(BTtoFind)) { //如果是要找的设备,更新UI上信息,设置搜索标志,停止响应搜索回调函数,连接BLE设备
/** 连接事件 */
BT_find.setText("已找到设备!");
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mBLE.connect(device.getAddress()); } }
}); }
}; private void displayGattServices(BluetoothGattService bluetoothGattService) { if (bluetoothGattService == null)
return; // -----Service的字段信息-----//
int type = bluetoothGattService.getType();
Log.e(TAG, "-->service type:" + Utils.getServiceType(type));
Log.e(TAG, "-->includedServices size:"
+ bluetoothGattService.getIncludedServices().size());
Log.e(TAG, "-->service uuid:" + bluetoothGattService.getUuid()); // -----Characteristics的字段信息-----//
List<BluetoothGattCharacteristic> gattCharacteristics = bluetoothGattService
.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
Log.e(TAG, "---->char uuid:" + gattCharacteristic.getUuid()); int permission = gattCharacteristic.getPermissions();
Log.e(TAG,
"---->char permission:"
+ Utils.getCharPermission(permission)); int property = gattCharacteristic.getProperties();
Log.e(TAG, "---->char property:" + Utils.getCharPropertie(property)); byte[] data = gattCharacteristic.getValue();
if (data != null && data.length > 0) {
Log.e(TAG, "---->char value:" + new String(data));
} // UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic
if (gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)) {
// 测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mBLE.readCharacteristic(gattCharacteristic);
}
}, 500); // 接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()
mBLE.setCharacteristicNotification(gattCharacteristic, true);
// 设置数据内容
gattCharacteristic.setValue("send data->");
// 往蓝牙模块写入数据
mBLE.writeCharacteristic(gattCharacteristic);
} // -----Descriptors的字段信息-----//
List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic
.getDescriptors();
for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {
Log.e(TAG, "-------->desc uuid:" + gattDescriptor.getUuid());
int descPermission = gattDescriptor.getPermissions();
Log.e(TAG,
"-------->desc permission:"
+ Utils.getDescPermission(descPermission)); byte[] desData = gattDescriptor.getValue();
if (desData != null && desData.length > 0) {
Log.e(TAG, "-------->desc value:" + new String(desData));
}
} } } }
 

  

  

package com.TANK.temperature.BT;

import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log; public class BluetoothLeClass{
private final static String TAG = BluetoothLeClass.class.getSimpleName(); private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt; public interface OnConnectListener {
public void onConnect(BluetoothGatt gatt);
}
public interface OnDisconnectListener {
public void onDisconnect(BluetoothGatt gatt);
}
public interface OnServiceDiscoverListener {
public void onServiceDiscover(BluetoothGatt gatt);
}
public interface OnDataAvailableListener {
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status);
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic);
} private OnConnectListener mOnConnectListener;
private OnDisconnectListener mOnDisconnectListener;
private OnServiceDiscoverListener mOnServiceDiscoverListener;
private OnDataAvailableListener mOnDataAvailableListener;
private Context mContext;
public void setOnConnectListener(OnConnectListener l){
mOnConnectListener = l;
}
public void setOnDisconnectListener(OnDisconnectListener l){
mOnDisconnectListener = l;
}
public void setOnServiceDiscoverListener(OnServiceDiscoverListener l){
mOnServiceDiscoverListener = l;
}
public void setOnDataAvailableListener(OnDataAvailableListener l){
mOnDataAvailableListener = l;
} public BluetoothLeClass(Context c){
mContext = c;
} // 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) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
if(mOnConnectListener!=null)
mOnConnectListener.onConnect(gatt);
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) {
if(mOnDisconnectListener!=null)
mOnDisconnectListener.onDisconnect(gatt);
Log.i(TAG, "Disconnected from GATT server.");
}
} @Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS && mOnServiceDiscoverListener!=null) {
mOnServiceDiscoverListener.onServiceDiscover(gatt);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
} @Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (mOnDataAvailableListener!=null)
mOnDataAvailableListener.onCharacteristicRead(gatt, characteristic, status);
} @Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
if (mOnDataAvailableListener!=null)
mOnDataAvailableListener.onCharacteristicWrite(gatt, characteristic);
}
}; /**
* 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) mContext.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;
} /**
* 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()) {
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(mContext, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
return true;
} /**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
} /**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
} /**
* 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);
} /**
* Enables or disables notification on a give characteristic.
*
* @param characteristic Characteristic to act on.
* @param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,//便于更新数据
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
} public void writeCharacteristic(BluetoothGattCharacteristic characteristic){
mBluetoothGatt.writeCharacteristic(characteristic);
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
*
* @return A {@code List} of supported services.
*/
public BluetoothGattService getSupportedGattService() {//根据service的UUID来获取service
if (mBluetoothGatt == null) return null; return mBluetoothGatt.getService(UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb"));
}
}
public class Utils {

    private static HashMap<Integer, String> serviceTypes = new HashMap();
static {
// Sample Services.
serviceTypes.put(BluetoothGattService.SERVICE_TYPE_PRIMARY, "PRIMARY");
serviceTypes.put(BluetoothGattService.SERVICE_TYPE_SECONDARY, "SECONDARY");
} public static String getServiceType(int type){
return serviceTypes.get(type);
} //-------------------------------------------
private static HashMap<Integer, String> charPermissions = new HashMap();
static {
charPermissions.put(0, "UNKNOW");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ, "READ");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED, "READ_ENCRYPTED");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM, "READ_ENCRYPTED_MITM");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE, "WRITE");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED, "WRITE_ENCRYPTED");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM, "WRITE_ENCRYPTED_MITM");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED, "WRITE_SIGNED");
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM, "WRITE_SIGNED_MITM");
} public static String getCharPermission(int permission){
return getHashMapValue(charPermissions,permission);
}
//-------------------------------------------
private static HashMap<Integer, String> charProperties = new HashMap();
static { charProperties.put(BluetoothGattCharacteristic.PROPERTY_BROADCAST, "BROADCAST");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS, "EXTENDED_PROPS");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_INDICATE, "INDICATE");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_NOTIFY, "NOTIFY");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_READ, "READ");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE, "SIGNED_WRITE");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_WRITE, "WRITE");
charProperties.put(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, "WRITE_NO_RESPONSE");
} public static String getCharPropertie(int property){
return getHashMapValue(charProperties,property);
} //--------------------------------------------------------------------------
private static HashMap<Integer, String> descPermissions = new HashMap();
static {
descPermissions.put(0, "UNKNOW");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ, "READ");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED, "READ_ENCRYPTED");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM, "READ_ENCRYPTED_MITM");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE, "WRITE");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED, "WRITE_ENCRYPTED");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM, "WRITE_ENCRYPTED_MITM");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED, "WRITE_SIGNED");
descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM, "WRITE_SIGNED_MITM");
} public static String getDescPermission(int property){
return getHashMapValue(descPermissions,property);
} //这段代码没看明白,欢迎大神指教
private static String getHashMapValue(HashMap<Integer, String> hashMap,int number){
String result =hashMap.get(number);
if(TextUtils.isEmpty(result)){
List<Integer> numbers = getElement(number);
result="";
for(int i=0;i<numbers.size();i++){
result+=hashMap.get(numbers.get(i))+"|";
}
}
return result;
} /**
* 位运算结果的反推函数10 -> 2 | 8;
*/
static private List<Integer> getElement(int number){
List<Integer> result = new ArrayList<Integer>();
for (int i = 0; i < 32; i++){
int b = 1 << i;
if ((number & b) > 0)
result.add(b);
} return result;
} public static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}

  

  

05-11 13:03