我正在连接iOS - Android . 两者都有中央和外围 . 但是,iOS Central将收到Android Peripheral中已更新值的通知,但Android Central未收到通知且onCharaterisiticChanged未触发 . iOS到iOS可以发送和接收发送的通知和值 . 如果我只有iOS Central和Android Peripheral,则值通知更新可以正常工作 . 如果我只有iOS Peripheral和Android Central,则值通知工作并调用onCharacteristicChanged .
所以我认为Android系统无法运行Central和Peripheral,但是isMultipleAdvertisementSupported()是真的 . 它是运行Android 7的Abla平板电脑 .
Android Central Class
public class Central {
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private AppActivity mAppActivity;
private Context mContext;
private BluetoothGatt mBluetoothGatt;
private boolean isCentralConnected;
public boolean hasBLE() {
boolean hasBT = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
boolean isEnabled = mBluetoothAdapter.isEnabled();
boolean multiAdd = mBluetoothAdapter.isMultipleAdvertisementSupported();
return (hasBT && isEnabled && multiAdd);
}
public void setupBLE(AppActivity _appActivity, Context _Context)
{
mContext = _Context;
mAppActivity = _appActivity;
final BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
public void startScanningBT()
{
isCentralConnected = false;
Log.d("CENTRAL", "BT CENTRAL: SCAN STARTED");
mBluetoothGatt = null;
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
mScanning = true;
bluetoothLeScanner.startScan(mLeScanCallback);
}
public void stopScanningBT() {
Log.d("CENTRAL", "BT CENTRAL: STOP SCAN");
mBluetoothGatt = null;
mScanning = false;
if(mBluetoothAdapter != null) {
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.stopScan(mLeScanCallback);
}
isCentralConnected = false;
}
public Boolean isConnected() {
return isCentralConnected;
}
private ScanCallback mLeScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
List<ParcelUuid> uuidsList = result.getScanRecord().getServiceUuids();
ParcelUuid pUuid = new ParcelUuid( UUID.fromString( mAppActivity.UUID_CEN_Transfer ) );
if(uuidsList != null && uuidsList.contains(pUuid)) {
Log.d("CENTRAL", "BT CENTRAL: Found TransferUUID");
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
}
};
public void connectToDevice(final BluetoothDevice device) {
if (mBluetoothGatt == null) {
Log.d("CENTRAL", "BT CENTRAL: Connect to device");
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.stopScan(mLeScanCallback);
mBluetoothGatt = device.connectGatt(mContext, false, 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) {
super.onConnectionStateChange(gatt,status,newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d("CENTRAL", "BT CENTRAL: mGattcallback CONNECTED Request serivces");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("CENTRAL", "BT CENTRAL: mGattcallback DISCONNECTED");
}
}
@Override
//New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt,status);
List<BluetoothGattService> services = gatt.getServices();
Log.i("onServicesDiscovered", services.toString());
Log.d("CENTRAL", "BT CENTRAL: onServicesDiscovered");
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString(mAppActivity.UUID_CEN_Transfer));
if(mCustomService != null) {
Log.d("CENTRAL", "BT CENTRAL: mCustomService Found");
mBluetoothAdapter.getBluetoothLeScanner().stopScan(mLeScanCallback);
setCharacteristicNotification(mCustomService.getCharacteristics().get
(0),true, 0);
setCharacteristicNotification(mCustomService.getCharacteristics().get
(1),true, 1);
setCharacteristicNotification(mCustomService.getCharacteristics().get
(2),true, 2);
//Central connected, now if Peripheral not connected, start advertising
isCentralConnected = true;
if(!mAppActivity.mNewPeripheral.isConnected())
{
//mAppActivity.mPeripheral.startAdvertising();
mAppActivity.mNewPeripheral.initializeBTLE(mAppActivity,mAppActivity.getContext());
//mAppActivity.mNewPeripheral.startAdvertise();
}
}
else
{
mBluetoothGatt = null;
Log.d("CENTRAL", "BT CENTRAL: mCustomService Error");
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt,characteristic);
//Test to read the value
//Only works when NOT running Peripheral mode too
String str = new String(characteristic.getValue(), Charset.forName("UTF-8"));
}
};
/**
* 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, int arrayNumber) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.i("Characteristic Note:", "BT CENTRAL: CHARACTERISTIC FAILED: " + arrayNumber + characteristic.getUuid());
return;
}
while (!mBluetoothGatt.setCharacteristicNotification(characteristic, enabled));
for (BluetoothGattDescriptor descriptor : characteristic.getDescriptors()) {
Log.i("Characteristic Note:", "BT CENTRAL: SetDescriptor: " + arrayNumber + characteristic.getUuid());
descriptor.setValue( BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
}
Android外围设备
public class NewPeripheral {
private Context mContext;
private AppActivity mAppActivity;
private BluetoothManager mManager;
private BluetoothGattServer mGattServer;
private BluetoothGattCharacteristic mCharacteristicControl;
private BluetoothGattCharacteristic mCharacteristic2;
private BluetoothGattCharacteristic mCharacteristic3;
private BluetoothGattService mService;
private boolean isPeripheralConnected;
private BluetoothDevice mSubscribedDevice;
public Boolean isConnected() {
return isPeripheralConnected;
}
private BluetoothLeAdvertiser mBLEAdvertiser;
private final AdvertiseCallback mAdvCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
Log.d("PERIPHERAL", "Advertise Start Successfully");
}
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.e("PERIPHERAL", "Advertise Start Error, Code " + String.valueOf(errorCode));
}
};
public Boolean initializeBTLE(AppActivity _appActivity, Context _Context) {
isPeripheralConnected = false;
mSubscribedDevice = null;
mContext = _Context;
mAppActivity = _appActivity;
boolean hasBLE = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
if (!hasBLE) {
Log.e("PERIPHERAL", "Bluetooth Low Energy Not Supported On Phone.");
return false;
}
mBLEAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
if (mBLEAdvertiser == null) {
Log.e("PERIPHERAL", "Cannot Initialize BTLE Advertiser.");
return false;
}
// this will mention later about how to create gatt server
return createGattService();
}
public void startAdvertise() {
AdvertiseSettings advSettings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.setConnectable(true)
.build();
ParcelUuid deviceUUID = ParcelUuid.fromString(mAppActivity.UUID_PER_Transfer);
AdvertiseData advData = new AdvertiseData.Builder()
.addServiceUuid(deviceUUID)
.build();
if (advSettings == null || advData == null) {
Log.e("PERIPHERAL", "Cannot create AdvertiseSettings or AdvertiseData");
return;
}
mBLEAdvertiser.startAdvertising(advSettings, advData, mAdvCallback);
}
public void stopAdvertise() {
isPeripheralConnected = false;
mSubscribedDevice = null;
if (mBLEAdvertiser != null && mAdvCallback != null) {
mBLEAdvertiser.stopAdvertising(mAdvCallback);
}
}
private Boolean createGattService() {
mManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
if (mManager == null) {
Log.e("PERIPHERAL", "Cannot Initialize Bluetooth Manager.");
return false;
}
mGattServer = mManager.openGattServer(mContext, mGattServerCallback);
if (mGattServer == null) {
Log.e("PERIPHERAL", "Cannot Create Gatt Server.");
return false;
}
// Setup service and characteristic.
addDeviceService();
return true;
}
private void addDeviceService() {
// Remove previous Service
BluetoothGattService previousService = mGattServer.getService(UUID.fromString(mAppActivity.UUID_PER_Transfer));
if (previousService != null) {
mGattServer.removeService(previousService);
}
// CONTROL
mCharacteristicControl = new BluetoothGattCharacteristic(
UUID.fromString(mAppActivity.UUID_PER_Charateristic_GameControl),
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);
BluetoothGattDescriptor controlDescriptor = new BluetoothGattDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB"),
BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ);
mCharacteristicControl.addDescriptor(controlDescriptor);
//NOTE Characteristics 2 and 3 commented out during onCharacteristicChanged testing
// Characteristic2
/*mCharacteristic2 = new BluetoothGattCharacteristic(
UUID.fromString(mAppActivity.UUID_Charateristic_2),
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);
BluetoothGattDescriptor c2Descriptor = new BluetoothGattDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB"),
BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ);*/
mCharacteristic2.addDescriptor(c2Descriptor);
// Characteristic3
/*mCharacteristic3 = new BluetoothGattCharacteristic(
UUID.fromString(mAppActivity.UUID_Charateristic_3),
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_READ);
BluetoothGattDescriptor c3Descriptor = new BluetoothGattDescriptor(
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB"),
BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ);*/
mCharacteristic3.addDescriptor(32Descriptor);
//SETUP SERVICE
mService = new BluetoothGattService(
UUID.fromString(mAppActivity.UUID_PER_Transfer),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
while (!mService.addCharacteristic(mCharacteristicControl));
mGattServer.addService(mService);
Log.d("PERIPHERIAL:", "BT PERIPHERIAL: Started Advertise");
startAdvertise();
}
private final BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(final BluetoothDevice device, final int status, final int newState) {
super.onConnectionStateChange(device, status, newState);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.d("PERIPHERIAL:", "BT PERIPHERIAL: Connected SUCCESS");
mGattServer.connect(device, false);
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.d("PERIPHERIAL:", "BT PERIPHERIAL: DISCONNECTED");
break;
default:
// do nothing
break;
}
}
@Override
public void onDescriptorWriteRequest(final BluetoothDevice device, final int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
Log.d("PERIPHERIAL:", "BT PERIPHERIAL: onDescriptionWriteRequest");
mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
if(mSubscribedDevice == null) {
mSubscribedDevice = device;
}
//When Peripheral is connected Connect Central
mBLEAdvertiser.stopAdvertising(mAdvCallback);
isPeripheralConnected = true;
if(!mAppActivity.mCentral.isConnected())
{
mAppActivity.mCentral.startScanningBT();
}
}
};
public void sendRandom(float random) {
String numberAsString = String.format ("Rand%.5f", random);
byte[] data = numberAsString.getBytes(Charset.forName("UTF-8"));
mCharacteristicControl.setValue(data);
mGattServer.notifyCharacteristicChanged(mSubscribedDevice, mCharacteristicControl, false);
//NOTE This works and is received by the iOS device.
Log.d("PERIPHERIAL:", "BT PERIPHERIAL: Sent Random");
}
}
每个类都有来自主活动的上下文和活动,这是因为UUID在中心和外围都有 . 它不是const字符串 .
主要活动是创建和保持对类的引用,并将调用更多函数,如SendRandom和Central,当接收通知时将调用主活动中的函数 .
我想也许其中一些需要在另一个线程中工作,我试图在一个没有运气的新线程中运行特定的操作
new Thread(new Runnable() {
@Override
public void run() {
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
}
}).start();
请帮忙 . 如果您需要更多信息,请与我们联系 . 我已经坚持了一个多星期了 .