欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android蓝牙4.0BLE

程序员文章站 2024-03-24 23:32:04
...

android4.4以后支持蓝牙4.0BLE,android5.0以后支持作为BLE外部设备peripheral,android5.0之前的版本只能作为BLE的中心设备central。

android的例子BluetoothAdvertisements,可以作为外设被发现,但没有提供服务,和收发数据。

下面的代码提供了服务,可以被中心设备发现,和收发数据。

import java.util.UUID;
import android.app.Notification;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

public class GattServerService extends Service {
	private static final String TAG = GattServerService.class.getSimpleName();

	public static final String START_ADVERTISING = "GattServerService.start.advertising";
	public static final String ADVERTISING_STATE = "GattServerService.advertising.state";
	public static final String ADVERTISING_ON = "on";
	public static final String ADVERTISING_OFF = "off";

	public static final String BLE_CMD = "GattServerService.ble.cmd";
	public static final String LOCAL_CMD = "GattServerService.local.cmd";

	private static final String BLE_ERROR = "ble_error";

	public static final int MAX_SENDED_VALUE_LEN = 255;

	private static final long ADVERTISING_TIME = 60 * 1000;
	private static final UUID CMD_UUID = UUID
			.fromString("0000b81d-0000-1000-8000-00805f9b34fb");

	private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
	private BluetoothGattServer mBluetoothGattServer;

	private AdvertiseCallback mAdvertiseCallback;

	private Handler mHandler = new Handler();
	private Runnable mStopAdvertisingRunnable;

	private BluetoothDevice mConnectedDevice;
	private BluetoothGattCharacteristic mCmdCharacteristic;

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		super.onCreate();

		startForeground(0, new Notification());

		initBluetooth();

		final IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction(START_ADVERTISING);
		intentFilter.addAction(LOCAL_CMD);
		registerReceiver(mBroadcastReceiver, intentFilter);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG, "onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();

		stopAdvertising();

		mBluetoothLeAdvertiser = null;

		if (mBluetoothGattServer != null) {
			if (mConnectedDevice != null) {
				mBluetoothGattServer.cancelConnection(mConnectedDevice);
				mConnectedDevice = null;
			}
			mBluetoothGattServer.close();
			mBluetoothGattServer = null;
		}
	}

	private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			final String action = intent.getAction();
			if (START_ADVERTISING.equals(action)) {
				startAdvertising();
			} else if (LOCAL_CMD.equals(action)) {
				byte[] value = intent.getByteArrayExtra(LOCAL_CMD);
				onLocalCmdReceived(value);
			}
		}
	};

	private void startAdvertising() {
		Log.d(TAG, "startAdvertising");
		if (mAdvertiseCallback == null && mBluetoothLeAdvertiser != null) {
			mAdvertiseCallback = new AdvertiseCallback() {
				@Override
				public void onStartSuccess(AdvertiseSettings settingsInEffect) {
					super.onStartSuccess(settingsInEffect);
					Log.d(TAG, "AdvertiseCallback.onStartSuccess");
					if (mStopAdvertisingRunnable != null) {
						mHandler.removeCallbacks(mStopAdvertisingRunnable);
						mStopAdvertisingRunnable = null;
					}

					mStopAdvertisingRunnable = new Runnable() {
						@Override
						public void run() {
							mStopAdvertisingRunnable = null;
							stopAdvertising();
						}
					};
					mHandler.postDelayed(mStopAdvertisingRunnable,
							ADVERTISING_TIME);

					onAdvertisingStateChanged();
				}

				@Override
				public void onStartFailure(int errorCode) {
					super.onStartFailure(errorCode);
					Log.d(TAG, "AdvertiseCallback.onStartFailure");
					mAdvertiseCallback = null;
					onAdvertisingStateChanged();
				}
			};

			AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
			settingsBuilder
					.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER);
			settingsBuilder.setTimeout(0);
			AdvertiseSettings advertiseSettings = settingsBuilder.build();

			AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
			// dataBuilder.addServiceUuid(Constants.Service_UUID);
			dataBuilder.setIncludeDeviceName(true);
			AdvertiseData advertiseData = dataBuilder.build();

			mBluetoothLeAdvertiser.startAdvertising(advertiseSettings,
					advertiseData, mAdvertiseCallback);
		}
	}

	private void stopAdvertising() {
		Log.d(TAG, "stopAdvertising");

		if (mStopAdvertisingRunnable != null) {
			mHandler.removeCallbacks(mStopAdvertisingRunnable);
			mStopAdvertisingRunnable = null;
		}

		if (mAdvertiseCallback != null) {
			if (mBluetoothLeAdvertiser != null) {
				mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
			}
			mAdvertiseCallback = null;
			onAdvertisingStateChanged();
		}
	}

	private void initBluetooth() {
		BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

		if (mBluetoothLeAdvertiser == null) {
			mBluetoothLeAdvertiser = bluetoothManager.getAdapter()
					.getBluetoothLeAdvertiser();
		}

		if (mBluetoothGattServer == null) {
			mBluetoothGattServer = bluetoothManager.openGattServer(
					GattServerService.this, mBluetoothGattServerCallback);

			BluetoothGattService gattService = new BluetoothGattService(
					CMD_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
			BluetoothGattCharacteristic gattCharacteristic = new BluetoothGattCharacteristic(
					CMD_UUID, BluetoothGattCharacteristic.PROPERTY_READ
							| BluetoothGattCharacteristic.PROPERTY_WRITE
							| BluetoothGattCharacteristic.PROPERTY_NOTIFY,
					BluetoothGattCharacteristic.PERMISSION_READ
							| BluetoothGattCharacteristic.PERMISSION_WRITE);
			gattCharacteristic.setValue("");
			gattService.addCharacteristic(gattCharacteristic);
			mBluetoothGattServer.addService(gattService);
		}
	}

	private void notifyCmdCharacteristicChanged(byte[] value) {
		Log.d(TAG, "notifyCmdCharacteristicChanged: ");
		if (mBluetoothGattServer != null && mConnectedDevice != null
				&& mCmdCharacteristic != null && value != null
				&& value.length < MAX_SENDED_VALUE_LEN) {
			dumpBytes(value);
			mCmdCharacteristic.setValue(value);
			boolean rst = mBluetoothGattServer.notifyCharacteristicChanged(
					mConnectedDevice, mCmdCharacteristic, true);
			if (!rst) {
				try {
					throw new Exception(BLE_ERROR);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	private BluetoothGattServerCallback mBluetoothGattServerCallback = new BluetoothGattServerCallback() {
		private byte[] cmdBuffer = null;

		@Override
		public void onConnectionStateChange(BluetoothDevice device, int status,
				int newState) {
			super.onConnectionStateChange(device, status, newState);
			Log.d(TAG, "onConnectionStateChange: status=" + status
					+ ", newState=" + newState);
			if (newState == BluetoothProfile.STATE_CONNECTED) {
				mConnectedDevice = device;
				stopAdvertising();
			} else {
				mConnectedDevice = null;
			}
		}

		@Override
		public void onServiceAdded(int status, BluetoothGattService service) {
			super.onServiceAdded(status, service);
			Log.d(TAG, "onServiceAdded: status=" + status);
			if (status == BluetoothGatt.GATT_SUCCESS) {
				mCmdCharacteristic = service.getCharacteristic(CMD_UUID);
			}
		}

		@Override
		public void onCharacteristicReadRequest(BluetoothDevice device,
				int requestId, int offset,
				BluetoothGattCharacteristic characteristic) {
			super.onCharacteristicReadRequest(device, requestId, offset,
					characteristic);
			Log.d(TAG, "onCharacteristicReadRequest: requestId=" + requestId
					+ ", offset=" + offset);
			byte[] value = characteristic.getValue();
			dumpBytes(value);

			if (mBluetoothGattServer != null) {
				mBluetoothGattServer.sendResponse(device, requestId,
						BluetoothGatt.GATT_SUCCESS, offset, new byte[] { 0 });
			}
		}

		@Override
		public void onCharacteristicWriteRequest(BluetoothDevice device,
				int requestId, BluetoothGattCharacteristic characteristic,
				boolean preparedWrite, boolean responseNeeded, int offset,
				byte[] value) {
			super.onCharacteristicWriteRequest(device, requestId,
					characteristic, preparedWrite, responseNeeded, offset,
					value);
			Log.d(TAG, "onCharacteristicWriteRequest: requestId=" + requestId
					+ ", offset=" + offset + ", preparedWrite=" + preparedWrite
					+ ", responseNeeded=" + responseNeeded);
			dumpBytes(value);
			if (value != null && value.length > 0) {
				if (preparedWrite) {
					if (cmdBuffer == null) {
						cmdBuffer = value;
					} else {
						byte[] tmp = new byte[cmdBuffer.length + value.length];
						System.arraycopy(cmdBuffer, 0, tmp, 0, cmdBuffer.length);
						System.arraycopy(value, 0, tmp, cmdBuffer.length,
								value.length);
						cmdBuffer = tmp;
					}
				} else {
					cmdBuffer = null;
					onBleCmdReceived(value);
				}
			}

			if (mBluetoothGattServer != null) {
				mBluetoothGattServer.sendResponse(device, requestId,
						BluetoothGatt.GATT_SUCCESS, offset, value);
			}
		}

		@Override
		public void onDescriptorReadRequest(BluetoothDevice device,
				int requestId, int offset, BluetoothGattDescriptor descriptor) {
			super.onDescriptorReadRequest(device, requestId, offset, descriptor);
			Log.d(TAG, "onDescriptorReadRequest: requestId=" + requestId
					+ ", offset=" + offset);
		}

		@Override
		public void onDescriptorWriteRequest(BluetoothDevice device,
				int requestId, BluetoothGattDescriptor descriptor,
				boolean preparedWrite, boolean responseNeeded, int offset,
				byte[] value) {
			super.onDescriptorReadRequest(device, requestId, offset, descriptor);
			Log.d(TAG, "onDescriptorWriteRequest: requestId=" + requestId
					+ ", offset=" + offset);
		}

		@Override
		public void onExecuteWrite(BluetoothDevice device, int requestId,
				boolean execute) {
			super.onExecuteWrite(device, requestId, execute);
			Log.d(TAG, "onExecuteWrite: requestId=" + requestId + ", execute="
					+ execute);
			onBleCmdReceived(cmdBuffer);
			cmdBuffer = null;

			if (mBluetoothGattServer != null) {
				mBluetoothGattServer.sendResponse(device, requestId,
						BluetoothGatt.GATT_SUCCESS, 0, null);
			}
		}

		@Override
		public void onNotificationSent(BluetoothDevice device, int status) {
			super.onNotificationSent(device, status);
			Log.d(TAG, "onNotificationSent: status=" + status);
		}

		@Override
		public void onMtuChanged(BluetoothDevice device, int mtu) {
			super.onMtuChanged(device, mtu);
			Log.d(TAG, "onMtuChanged: mtu=" + mtu);
		}
	};

	private void onAdvertisingStateChanged() {
		Intent intent = new Intent(ADVERTISING_STATE);
		String state = mAdvertiseCallback != null ? ADVERTISING_ON
				: ADVERTISING_OFF;
		intent.putExtra(ADVERTISING_STATE, state);
		sendBroadcast(intent);
		Log.d(TAG, "onAdvertisingStateChanged:" + state);
	}

	private void onLocalCmdReceived(byte[] value) {
		notifyCmdCharacteristicChanged(value);
	}

	private void onBleCmdReceived(byte[] value) {
		Intent intent = new Intent(BLE_CMD);
		intent.putExtra(BLE_CMD, value);
		sendBroadcast(intent);
		Log.d(TAG, "onBleCmdReceived: ");
		dumpBytes(value);
	}

	private void dumpBytes(byte[] value) {
		if (value != null && value.length > 0) {
			StringBuilder sb = new StringBuilder(2 * value.length);
			for (byte b : value) {
				sb.append(Byte.toHexString(b, true));
			}
			Log.d(TAG, sb.toString());
		}

		Log.d(TAG, "empty value");
	}
}

下面的代码参照android的例子BluetoothLeGatt,和BLE外设收发数据

package com.example.android.bluetoothlegatt;

import java.util.UUID;

import android.app.Notification;
import android.app.Service;
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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;

public class GattClientService extends Service {
	private static final String TAG = GattClientService.class.getSimpleName();

	private static final UUID CMD_UUID = UUID
			.fromString("0000b81d-0000-1000-8000-00805f9b34fb");

	public static final String GATT_CONNECT = "com.example.android.bluetoothlegatt.connect";
	public static final String GATT_CONNECT_ON = "on";
	public static final String GATT_CONNECT_OFF = "off";
	public static final String GATT_CONNECT_ADDR = "com.example.android.bluetoothlegatt.connect.addr";

	public static final String CONNECT_STATE = "com.example.android.bluetoothlegatt.connect.state";

	public static final String CMD_LOCAL = "com.example.android.bluetoothlegatt.cmd.local";
	public static final String CMD_BLE = "com.example.android.bluetoothlegatt.cmd.ble";

	public static final int STATE_DISCONNECTED = 0;
	public static final int STATE_CONNECTED = 1;

	private BluetoothAdapter mBluetoothAdapter;
	private BluetoothGatt mBluetoothGatt;
	private BluetoothGattCharacteristic mCmdGattCharacteristic;
	private String mBleAddr;

	private int mConnectionState = STATE_DISCONNECTED;

	private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
		@Override
		public void onConnectionStateChange(BluetoothGatt gatt, int status,
				int newState) {
			if (newState == BluetoothProfile.STATE_CONNECTED) {
				mConnectionState = STATE_CONNECTED;
				mBluetoothGatt.discoverServices();
			} else {
				mConnectionState = STATE_DISCONNECTED;
			}

			onBleConnectionStateChange(mConnectionState);
		}

		@Override
		public void onServicesDiscovered(BluetoothGatt gatt, int status) {
			if (status == BluetoothGatt.GATT_SUCCESS) {
				BluetoothGattService service = gatt.getService(CMD_UUID);
				if (service != null) {
					mCmdGattCharacteristic = service
							.getCharacteristic(CMD_UUID);
					if (mCmdGattCharacteristic != null) {
						mBluetoothGatt.setCharacteristicNotification(
								mCmdGattCharacteristic, true);
					}
				}
			}
		}

		@Override
		public void onCharacteristicChanged(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic) {
			Log.d(TAG, "onCharacteristicChanged");
			byte[] value = characteristic.getValue();
			onValueReaded(value);
		}
	};

	private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			final String action = intent.getAction();
			if (GATT_CONNECT.equals(action)) {
				String on = intent.getStringExtra(GATT_CONNECT);
				String addr = intent.getStringExtra(GATT_CONNECT_ADDR);
				if (GATT_CONNECT_ON.equals(on)) {
					connect(addr);
				} else {
					disconnect();
				}
			} else if (CMD_LOCAL.equals(action)) {
				byte[] value = intent.getByteArrayExtra(CMD_LOCAL);
				writeValue(value);
			}
		}
	};

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();

		startForeground(0, new Notification());

		BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
		mBluetoothAdapter = mBluetoothManager.getAdapter();

		final IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction(GATT_CONNECT);
		intentFilter.addAction(CMD_LOCAL);
		registerReceiver(mBroadcastReceiver, intentFilter);
	}

	private boolean connect(String address) {
		if (TextUtils.isEmpty(address)) {
			return false;
		}

		if (address.equals(mBleAddr) && mBluetoothGatt != null
				&& mConnectionState == STATE_CONNECTED) {
			return true;
		} else if (address.equals(mBleAddr) && mBluetoothGatt != null) {
			return mBluetoothGatt.connect();
		} else if (mBluetoothGatt != null) {
			mBluetoothGatt.close();
			mBluetoothGatt = null;
			mBleAddr = null;
		}

		final BluetoothDevice device = mBluetoothAdapter
				.getRemoteDevice(address);
		if (device == null) {
			return false;
		}

		mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
		if (mBluetoothGatt == null) {
			return false;
		}

		mBleAddr = address;
		return true;
	}

	private void disconnect() {
		if (mBluetoothGatt != null) {
			mBluetoothGatt.disconnect();
		}
	}

	private void onBleConnectionStateChange(int state) {
		final Intent intent = new Intent(CONNECT_STATE);
		intent.putExtra(CONNECT_STATE, state);
		sendBroadcast(intent);
	}

	private void writeValue(byte[] value) {
		Log.d(TAG, "writeValue");
		dumpBytes(value);
		if (mCmdGattCharacteristic != null && mBluetoothGatt != null
				&& mConnectionState == STATE_CONNECTED) {
			mCmdGattCharacteristic.setValue(value);
			mBluetoothGatt.writeCharacteristic(mCmdGattCharacteristic);
		}
	}

	private void onValueReaded(byte[] value) {
		Log.d(TAG, "onValueReaded");
		dumpBytes(value);

		final Intent intent = new Intent(CMD_BLE);
		intent.putExtra(CMD_BLE, value);
		sendBroadcast(intent);
	}

	private void dumpBytes(byte[] value) {
		if (value != null && value.length > 0) {
			StringBuilder sb = new StringBuilder(2 * value.length);
			for (byte b : value) {
				sb.append(Byte.toHexString(b, true));
			}
			Log.d(TAG, sb.toString());
			return;
		}

		Log.d(TAG, "empty value");
	}
}

 

转载于:https://my.oschina.net/kyle960/blog/847638