问题描述
我正在使用BluetoothGatt进行BLE设备和Android设备的通信。 我已经使用示例代码来连接这两个设备。 但是我真的很想在这两个设备之间传输数据。
我的代码如下。
public class DeviceControlActivity extends Activity {
private final static String TAG = DeviceControlActivity.class.getSimpleName();
public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
private PreferenceHelper preferenceHelper;
private TextView mConnectionState;
private TextView mdatafield;
private String mDeviceName;
private String mDeviceAddress;
private ExpandableListView mGattServicesList;
private BluetoothLeService mBluetoothLeService;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattcharacteristics =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
private boolean mConnected = false;
private BluetoothGattCharacteristic mNotifyCharacteristic;
private final String LIST_NAME = "NAME";
private final String LIST_UUID = "UUID";
private ServerApiService serverApiService;
private GPSTracker gps;
private String address;
private String filename,outputFile;
private BluetoothGattCharacteristic bluetoothGattCharacteristicHM_10;
// 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;
}
};
private final broadcastReceiver mGattUpdateReceiver = new broadcastReceiver() {
@Override
public void onReceive(Context context,Intent intent) {
final String action = intent.getAction();
Log.d("Test","action: " + action);
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
preferenceHelper.setConnected(true);
mConnected = true;
updateConnectionState(R.string.connected);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_disCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_disCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.d("Test","extra: " + intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
final byte[] rxBytes = bluetoothGattCharacteristicHM_10.getValue();
final byte[] insertSomething = {(byte) '\n'};
byte[] txBytes = new byte[insertSomething.length + rxBytes.length];
System.arraycopy(insertSomething,txBytes,insertSomething.length);
System.arraycopy(rxBytes,insertSomething.length,rxBytes.length);
if (bluetoothGattCharacteristicHM_10 != null) {
bluetoothGattCharacteristicHM_10.setValue(txBytes);
mBluetoothLeService.writeCharacteristic(bluetoothGattCharacteristicHM_10);
mBluetoothLeService.setCharacteristicNotification(bluetoothGattCharacteristicHM_10,true);
}
}
}
};
private final ExpandableListView.OnChildClickListener servicesListClickListner =
new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent,View v,int groupPosition,int childPosition,long id) {
if (mGattcharacteristics != null) {
final BluetoothGattCharacteristic characteristic =
mGattcharacteristics.get(groupPosition).get(childPosition);
final int charaProp = characteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
// If there is an active notification on a characteristic,clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(
mNotifyCharacteristic,false);
mNotifyCharacteristic = null;
}
Log.d("Test","read characteristic: " + characteristic.getUuid());
if (characteristic.getUuid().equals("0000fff2-0000-1000-8000-00805f9b34fb")) {
sendLongSMS();
}
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
mNotifyCharacteristic = characteristic;
mBluetoothLeService.setCharacteristicNotification(
characteristic,true);
}
return true;
}
return false;
}
};
private void clearUI() {
mGattServicesList.setAdapter((Simpleexpandablelistadapter) null);
mdatafield.setText(R.string.no_data);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gatt_services_characteristics);
preferenceHelper = new PreferenceHelper(this);
serverApiService = ServiceGenerator.getInstance(this).create(ServerApiService.class);
final Intent intent = getIntent();
mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
// Sets up UI references.
((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress);
mGattServicesList = (ExpandableListView) findViewById(R.id.gatt_services_list);
mGattServicesList.setonChildClickListener(servicesListClickListner);
mConnectionState = (TextView) findViewById(R.id.connection_state);
mdatafield = (TextView) findViewById(R.id.data_value);
getActionBar().setTitle(mDeviceName);
getActionBar().setdisplayHomeAsUpEnabled(true);
Intent gattServiceIntent = new Intent(this,BluetoothLeService.class);
bindService(gattServiceIntent,mServiceConnection,BIND_AUTO_CREATE);
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(mGattUpdateReceiver,makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
Log.d(TAG,"Connect request result=" + result);
}
}
@Override
protected void onPause() {
super.onPause();
// unregisterReceiver(mGattUpdateReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
// unbindService(mServiceConnection);
// mBluetoothLeService = null;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.gatt_services,menu);
if (mConnected) {
menu.findItem(R.id.menu_connect).setVisible(false);
menu.findItem(R.id.menu_disconnect).setVisible(true);
} else {
menu.findItem(R.id.menu_connect).setVisible(true);
menu.findItem(R.id.menu_disconnect).setVisible(false);
}
return true;
}
@Override
public boolean onoptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_connect:
mBluetoothLeService.connect(mDeviceAddress);
return true;
case R.id.menu_disconnect:
mBluetoothLeService.disconnect();
return true;
case android.R.id.home:
onBackpressed();
return true;
}
return super.onoptionsItemSelected(item);
}
private void updateConnectionState(final int resourceId) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mConnectionState.setText(resourceId);
}
});
}
private void displayData(String data) {
if (data != null) {
mdatafield.setText(data);
}
}
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
String uuid = null;
String unkNownServiceString = getResources().getString(R.string.unkNown_service);
String unkNownCharaString = getResources().getString(R.string.unkNown_characteristic);
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();
currentServiceData.put(LIST_NAME,SampleGattAttributes.lookup(uuid,unkNownServiceString));
currentServiceData.put(LIST_UUID,uuid);
// mBluetoothLeService.setCharacteristicNotification(currentServiceData,true);
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();
currentCharaData.put(LIST_NAME,unkNownCharaString));
currentCharaData.put(LIST_UUID,uuid);
mBluetoothLeService.setCharacteristicNotification(gattCharacteristic,true);
gattCharacteristicGroupData.add(currentCharaData);
}
mGattcharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
Simpleexpandablelistadapter gattServiceAdapter = new Simpleexpandablelistadapter(
this,gattServiceData,android.R.layout.simple_expandable_list_item_2,new String[]{LIST_NAME,LIST_UUID},new int[]{android.R.id.text1,android.R.id.text2},gattCharacteristicData,android.R.id.text2}
);
mGattServicesList.setAdapter(gattServiceAdapter);
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_disCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_disCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
}
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_disCONNECTED;
private static final int STATE_disCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_disCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_disCONNECTED";
public final static String ACTION_GATT_SERVICES_disCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_disCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// 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);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,int status) {
Log.d(TAG,"onCharacteristicRead characteristic: " + characteristic.getUuid());
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE,characteristic);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
Log.d(TAG,"onCharacteristicChanged characteristic: " + characteristic.getUuid());
broadcastUpdate(ACTION_DATA_AVAILABLE,characteristic);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,int status) {
byte[] data;
byte b = 0x00;
data = new byte[]{b};
// BluetoothGattService service = gatt.getService(IMMEDIATE_ALERT_UUID);
// if (service != null) {
// characteristic = service.getCharacteristic(IMMEDIATE_ALERT_LEVEL_UUID);
// characteristic.setValue(data);
// gatt.writeCharacteristic(characteristic);
// }
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
Log.d(TAG,"broadcastUpdate characteristic: action | " + action);
sendbroadcast(intent);
}
private void broadcastUpdate(final String action,final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
Log.d(TAG,"broadcastUpdate characteristic: " + characteristic.getUuid());
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG,"Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG,"Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format,1);
Log.d(TAG,String.format("Received heart rate: %d",heartRate));
intent.putExtra(EXTRA_DATA,String.valueOf(heartRate));
} else {
// For all other profiles,writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
Log.d("Test ble","byte: " + data);
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ",byteChar));
intent.putExtra(EXTRA_DATA,new String(data) + "\n" + stringBuilder.toString());
Log.d("Test ble",new String(data) + "\n" + stringBuilder.toString());
}
}
Log.w(TAG,"broadcastUpdate()");
final byte[] data = characteristic.getValue();
Log.v(TAG,"data.length: " + data.length);
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data) {
stringBuilder.append(String.format("%02X ",byteChar));
Log.v(TAG,String.format("%02X ",byteChar));
}
intent.putExtra(EXTRA_DATA,new String(data) + "\n" + stringBuilder.toString());
}
sendbroadcast(intent);
}
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// After using a given device,you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example,close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* 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;
}
/**
* 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,true,mGattCallback);
Log.d(TAG,"Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
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)}
* 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) {
Log.d(TAG,"readCharacteristic characteristic: " + characteristic.getUuid());
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,true);
Log.d(TAG,"setCharacteristicNotification characteristic: " + characteristic.getUuid());
// This is specific to Heart Rate Measurement.
// if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
// BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
// UUID.fromString(SampleGattAttributes.CLIENT_CHaraCTERISTIC_CONfig));
// descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
// mBluetoothGatt.writeDescriptor(descriptor);
// }
}
/**
* 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 List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
mBluetoothGatt.writeCharacteristic(characteristic);
}
}
在哪里进行编辑以进行设备的数据通信?
解决方法
我创建了一个使用Bluettoth LE与其他设备进行通信的开源库(您可以发送文本和原始数据),我将库的github页面链接到您: https://github.com/niedev/BluetoothCommunicator
您可以直接使用该库,也可以查看代码以获取可正常工作的蓝牙示例,
如果您发现代码太长,请不要担心,它的大部分目的是改善连接(在意外丢失设备信号,错误检查,拆分和重建长消息的情况下进行重新连接等)正常工作的蓝牙文件不是必需的。
我做了一些测试,它比附近的连接(仅当设备不在同一个wifi网络下)和wifi Direct更好地工作时,唯一的缺点是如果蓝牙之间有4/5个以上的设备连接,则蓝牙会出现问题它们(也许是星形拓扑,您可以增加数量),并且我的库没有消息加密,但是您可以随时自己添加,代码是开源的:)