我正在连接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();

请帮忙 . 如果您需要更多信息,请与我们联系 . 我已经坚持了一个多星期了 .