Android下的BLE编程解析(一)

蓝牙技术联盟在2010年6月30号公布了蓝牙4.0标准,4.0标准在蓝牙3.0+HS标准的基础上增加了对低功耗蓝牙(Bluetooth Low Energy, BLE)的支持。相比原有的普通蓝牙和高速蓝牙,BLE最大的特点就是低功耗,低延时,快速的搜索和连接速度,但数据传输速度相比传统蓝牙低。接下去将从BLE的概念以及代码两个方面介绍Android下的BLE。

1.BLE相关概念

Generic Attribute Profile (GATT):

GATT是蓝牙4.0特有的Profile通用规范,BLE应用的Profile均基于GATT。Gatt定义了一个服务框架规范,该框架包括对蓝牙服务(Service)和服务特性(Characteristic)的定义和规范,和其中读写、通知的特性等。可以将GATT理解成BLE框架,我们在GATT上面实现BLE功能。

Service:

Service是完成一个特定功能的数据和行为集合。在Gatt中,一个Service可能包含Service引用以及强制或者可选的Characteristic。

Characteristic:

一个Characteristic的定义包含了Characteristic本身,数值以及描述(Descriptor)的声明。Characteristic是完成BLE具体功能的基本单位。

Descriptor:

Descriptor定义了Characteristic中数据的具体含义。

下图是GATT中的Service,Characteristic, Descriptor三者之间的关系图,在Android的BLE源码中这三类变量也经常出现。

        

2.BLE编程

BLE的Android App和设备的连接过程如下。

2.1 SDK版本和权限

BLE程序需要Android 4.3(SDK VERSION >= 18)以上的版本,并且需要相关的蓝牙权限。

<uses-sdk
    android:minSdkVersion="18"
    android:targetSdkVersion="21" />
    
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
2.2 检测设备是否支持BLE蓝牙

/** 是否支持BLE */
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
    finish();
} /** end of if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) */
		
mBleManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
mBleAdapter = (BluetoothAdapter)mBleManager.getAdapter();
		
/** 蓝牙初始化失败 */
if (mBleAdapter == null) {
	Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
	finish();
} /** end of if (mBleAdapter == null) */

2.3 开启BLE

/** BLE是否开启 */
if (!mBleAdapter.isEnabled()) {
    Intent mBleIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    this.startActivityForResult(mBleIntent, REQUEST_ENABLE_BLE);
} /** end of if (!mBleAdapter.isEnabled()) */

开启蓝牙功能也可以使用
mBleAdapter.enable();
两者的区别: enable()方式打开蓝牙不需要用户确认,但打开蓝牙之后不能立即连接设备。BluetoothAdapter.ACTION_REQUEST_ENABLE的方式在打开蓝牙后可立即进行连接,但是需要用户确认。

2.4 绑定蓝牙Service

bindService(new Intent(this, BleServicePresenter.class), 
			mBleConnection, 
			Context.BIND_AUTO_CREATE); //BleServicePresenter封装了与BLE相关的操作和回调函数

2.5 Service绑定完成, 开始扫描BLE设备

private class BleServiceConnection implements ServiceConnection{

	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
		mBleMediator = ((BleServicePresenter.LocalBinder)service).getService();
		BleScan(true);	
	}

	@Override
	public void onServiceDisconnected(ComponentName name) {
			
	}		
}

2.6 扫描结果回调函数

private class BleScanCallback implements IAdapterBle.LeScanCallback {

	@Override
	public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {

		/** 根据MAC地址判断是否是目标设备 */
		if (device.getAddress().equals(BleUtil.getDeviceMAC())) {
			LogUtil.info(TAG, "device: " + device.getAddress().toString() + " "
									+ "name: " + device.getName().toString());
			BleConnect(device);
		} /** end of if (device.getAddress().equals(BleUtil.getDeviceMAC())) */	
	
	}
}

onLeScan()中的三个参数分别为device:蓝牙设备,rssi:设备返回的接收信号强度, scanRecord:设备广播消息

2.7 连接BLE

private void BleConnect(BluetoothDevice device) {
	mBleMediator.stopScan(mBleScanCallback); //停止扫描
	mBleMediator.connectBle(this, true, device); //连接设备
}
对其中直接连接的BLE函数做了封装,直接连接的函数为
public IBaseBle connectBle(Context context, boolean autoConnect, BluetoothDevice bleDevice) {
		
	/** BLE连接已经初始化 */
	if (mBaseBle != null) {
		closeBle();
	} /** end of if (mBaseBle != null) */
		
	mBaseBle = mAdapterBle.connectBle(context, //Activity实例
					autoConnect, //false:直接连接设备 true:当设备可用时自动连接
					mCallbackBle, //BLE回调函数
					bleDevice); //BLE设备实例
	return mBaseBle;
}

2.8 BLE连接成功回调

/**
 * 当主设备与客户端之间的连接状态发生改变时回调
 * 
 * @param bleGatt GATT客户端连接
 * @param status 设备之间的连接状态, 如果连接成功时返回{@link BluetoothProfile#GATT_SUCCESS}  
 * @param newState 返回设备之间最新的连接状态, 是{@link BluetoothProfile#STATE_DISCONNECTED}
 * 或者{@link BluetoothProfile#STATE_CONNECTED}其中之一
 */
public void onConnectionStateChange(BluetoothGatt bleGatt, int status, int newState) {
			
	/** 判断设备之间是否连接 */
	if (status == BluetoothGatt.GATT_SUCCESS) {
				
		/** 判断当前连接状态 */
		if (newState == BluetoothProfile.STATE_CONNECTED) {
			LogUtil.info(TAG, "connect state : " + BleUtil.DEVICE_CONNECTED);
			mBleView.ConnectState(true);
		} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
				LogUtil.info(TAG, "connect state : " + BleUtil.DEVICE_DISCONNECTED);
				mBleView.ConnectState(false);
			} /** end of if (newState == BluetoothProfile.STATE_CONNECTED) */
			
	} /** end of if (status != BluetoothGatt.GATT_SUCCESS) */
			
}

2.9 扫描BLE设备服务

/**
 * 搜索设备service
 */
private void DiscoveryServices() {
		
	/** 当前设备的连接状态 */
	if (mBleMediator.getConnectionState(mBleDevice) == BluetoothProfile.STATE_CONNECTED) {
		LogUtil.info(TAG, "start discovery servcie");
		mBleMediator.discoverServices();
	} else {
		mBleMediator.connectBle(this, true, mBleDevice);
		mBleMediator.connect();
	} /** end of if (mBleMediator.getConnectionState(mBleDevice) == BluetoothProfile.STATE_CONNECTED) */
	
}

2.10 BLE设备服务项回调

/**
 * 当设备的服务项(services)、characteristics)、属性(descriptors)被发现或者更新时回调
 * 
 * @param bleGatt GATT客户端连接, 被{@link BluetoothGatt#discoverServices}调用
 * @param status 设备连接状态, 如果连接成功返回{@link BluetoothGatt#GATT_SUCCESS}
 */
public void onServicesDiscovered(BluetoothGatt bleGatt, int status) {
			
	/** 判断设备之间是否连接  */
	if (status == BluetoothGatt.GATT_SUCCESS) {
		mBleView.ServiceDiscover();
	} else {
		mBleView.GattState(status);
	} /** end of if (status == BluetoothGatt.GATT_SUCCESS) */
			
}
获取到相应的Service之后整个连接过程完成,BLE连接部分到此结束。下一篇BLOG将介绍BLE之间的读写通信。

发布了10 篇原创文章 · 获赞 2 · 访问量 6万+
展开阅读全文

android studio 中蓝牙BLE设备搜索

01-17

同样的代码在eclipse下能执行LeScanCallback的onLeScan方法 而到了android studio 中就不执行了 权限都加了,是不是android studio中还有配置别的东西? public class Blues { Context con; Blues.M_LeScanCallback_interface callback_interface; private BluetoothAdapter mBluetoothAdapter; private LeScanCallback mLeScanCallback = new LeScanCallback() { public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { Blues.this.callback_interface.get_address(device.getAddress()); } }; public Blues(Context con, Blues.M_LeScanCallback_interface callback_interface) { //在eclipse中 就加执行到这里 在android studio中就不会 BluetoothManager bluetoothManager = (BluetoothManager)con.getSystemService("bluetooth"); this.mBluetoothAdapter = bluetoothManager.getAdapter(); this.con = con; this.callback_interface = callback_interface; } public void scanLeDevice(boolean enable) { if(enable) { this.mBluetoothAdapter.startLeScan(this.mLeScanCallback); } else { this.mBluetoothAdapter.stopLeScan(this.mLeScanCallback); } } public interface M_LeScanCallback_interface { void get_address(String var1); } } //下面是activity中的调用 public class MainActivity extends Activity implements Blues.M_LeScanCallback_interface { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onResume() { super.onResume(); Blues blues = new Blues(this, this); blues.scanLeDevice(true); } @Override public void get_address(String str) { Toast.makeText(getApplicationContext(), "" + str, Toast.LENGTH_SHORT).show(); } } 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览