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

android5.0 进行蓝牙广播(BLE Peripheral)

程序员文章站 2024-03-24 23:18:10
...

具有低功耗蓝牙模块的设备可以扮演2个角色,中心,周边。周边是数据提供者,中心是数据接收/处理者。自Android 4.3的系统就规定了BLE的API,但是仅限于中心,至于周边一直没有API的支持。直到Android 5.0的出现,才带来了周边API的支持(BluetoothLeAdvertiser)。

public class Main4Activity extends AppCompatActivity implements View.OnClickListener {


public final static UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_LOST_SERVICE = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_LOST_WRITE = UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_LOST_ENABLE = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb");

private static final String TAG = "yushu";
private TextView txtDevice;
private Button btnStart;
private Button btnNotify;
private Button btnStop;

private BluetoothManager mBluetoothManager;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;

private BluetoothGattServer gattServer;
private BluetoothGattCharacteristic characterNotify;
private BluetoothDevice bluetoothDevice;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main4);
    initView();
    initBLE();
    setServer();
}

private void initView() {
    txtDevice = (TextView) findViewById(R.id.txt_device);
    btnStart = (Button) findViewById(R.id.btn_start);
    btnNotify = (Button) findViewById(R.id.btn_notify);
    btnStop = (Button) findViewById(R.id.btn_stop);
    btnNotify.setOnClickListener(this);
    btnStart.setOnClickListener(this);
    btnStop.setOnClickListener(this);
}


/**
 * 初始化蓝牙
 */
private void initBLE() {
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, "不支持BLE", Toast.LENGTH_LONG).show();
        finish();
    }
    mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        Toast.makeText(this, "蓝牙不支持", Toast.LENGTH_LONG).show();
        finish();
    }
    assert mBluetoothAdapter != null;
    mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
    if (mBluetoothLeAdvertiser == null) {
        Toast.makeText(this, "the device not support peripheral", Toast.LENGTH_SHORT).show();
        finish();
    }
}


/**
 * 添加服务,特征
 */
private void setServer() {
    //读写特征
    BluetoothGattCharacteristic characterWrite = new BluetoothGattCharacteristic(
            UUID_LOST_WRITE, BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
            BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
    //使能特征
    characterNotify = new BluetoothGattCharacteristic(UUID_LOST_ENABLE,
            BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ);
    characterNotify.addDescriptor(new BluetoothGattDescriptor(CLIENT_CHARACTERISTIC_CONFIG, BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ));
    //服务
    BluetoothGattService gattService = new BluetoothGattService(UUID_LOST_SERVICE,
            BluetoothGattService.SERVICE_TYPE_PRIMARY);
    //为服务添加特征
    gattService.addCharacteristic(characterWrite);
    gattService.addCharacteristic(characterNotify);
    //管理服务,连接和数据交互回调
    gattServer = mBluetoothManager.openGattServer(this,
            new BluetoothGattServerCallback() {

                @Override
                public void onConnectionStateChange(final BluetoothDevice device,
                                                    final int status, final int newState) {
                    super.onConnectionStateChange(device, status, newState);
                    bluetoothDevice = device;
                    Log.d("Chris", "onConnectionStateChange:" + device + "    " + status + "   " + newState);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            txtDevice.setText(device.getAddress() + "   " + device.getName() + "   " + status + "  " + newState);
                        }
                    });
                }

                @Override
                public void onServiceAdded(int status,
                                           BluetoothGattService service) {
                    super.onServiceAdded(status, service);
                    Log.d("Chris", "service added");
                }

                @Override
                public void onCharacteristicReadRequest(
                        BluetoothDevice device, int requestId, int offset,
                        BluetoothGattCharacteristic characteristic) {
                    super.onCharacteristicReadRequest(device, requestId,
                            offset, characteristic);
                    gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
                    Log.d("Chris", "onCharacteristicReadRequest");
                }

                @Override
                public void onCharacteristicWriteRequest(
                        BluetoothDevice device, int requestId,
                        BluetoothGattCharacteristic characteristic,
                        boolean preparedWrite, boolean responseNeeded,
                        int offset, final byte[] value) {
                    super.onCharacteristicWriteRequest(device, requestId,
                            characteristic, preparedWrite, responseNeeded,
                            offset, value);
                    gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
                    Log.d("Chris", "onCharacteristicWriteRequest" + value[0]);
                    runOnUiThread(new Runnable() {
                        @SuppressLint("SetTextI18n")
                        @Override
                        public void run() {
                            txtDevice.setText(value[0] + "");
                        }
                    });
                }

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

                @Override
                public void onMtuChanged(BluetoothDevice device, int mtu) {
                    super.onMtuChanged(device, mtu);
                }

                @Override
                public void onDescriptorReadRequest(BluetoothDevice device,
                                                    int requestId, int offset,
                                                    BluetoothGattDescriptor descriptor) {
                    super.onDescriptorReadRequest(device, requestId,
                            offset, descriptor);
                    gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characterNotify.getValue());
                    Log.d("Chris", "onDescriptorReadRequest");
                }

                @Override
                public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
                                                     BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded,
                                                     int offset, byte[] value) {
                    super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded,
                            offset, value);
                    gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
//                        characterNotify.setValue("HIHHHHH");
//                        gattServer.notifyCharacteristicChanged(bluetoothDevice, characterNotify, false);
                    Log.d("Chris", "onDescriptorWriteRequest");
                }

                @Override
                public void onExecuteWrite(BluetoothDevice device,
                                           int requestId, boolean execute) {
                    super.onExecuteWrite(device, requestId, execute);
                    Log.d("Chris", "onExecuteWrite");
                }
            });
    gattServer.addService(gattService);
}

/**
  *广播的一些基本设置
  **/
public AdvertiseSettings createAdvSettings(boolean connectAble, int timeoutMillis) {
    AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
    builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
    builder.setConnectable(connectAble);
    builder.setTimeout(timeoutMillis);
    builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
    AdvertiseSettings mAdvertiseSettings = builder.build();
    if (mAdvertiseSettings == null) {
        Toast.makeText(this, "mAdvertiseSettings == null", Toast.LENGTH_LONG).show();
        Log.e(TAG, "mAdvertiseSettings == null");
    }
    return mAdvertiseSettings;
}


@Override
public void onClick(View v) {
    if (v == btnNotify) {
        characterNotify.setValue("HIHHHHH");
        gattServer.notifyCharacteristicChanged(bluetoothDevice, characterNotify, false);
    } else if (v == btnStart) {
        mBluetoothLeAdvertiser.startAdvertising(createAdvSettings(true, 0), createAdvertiseData(), mAdvertiseCallback);
    } else if (v == btnStop) {
        stopAdvertise();
    }
}


private void stopAdvertise() {
    if (mBluetoothLeAdvertiser != null) {
        mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
    }
}


//广播数据
public AdvertiseData createAdvertiseData() {
    AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
    mDataBuilder.setIncludeDeviceName(true); //广播名称也需要字节长度
    mDataBuilder.setIncludeTxPowerLevel(true);
    mDataBuilder.addServiceData(ParcelUuid.fromString("0000fff0-0000-1000-8000-00805f9b34fb"),new byte[]{1,2});
    AdvertiseData mAdvertiseData = mDataBuilder.build();
    if (mAdvertiseData == null) {
        Toast.makeText(Main4Activity.this, "mAdvertiseSettings == null", Toast.LENGTH_LONG).show();
        Log.e(TAG, "mAdvertiseSettings == null");
    }
    return mAdvertiseData;
}


private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
    @Override
    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        super.onStartSuccess(settingsInEffect);
        if (settingsInEffect != null) {
            Log.d(TAG, "onStartSuccess TxPowerLv=" + settingsInEffect.getTxPowerLevel() + " mode=" + settingsInEffect.getMode()
                    + " timeout=" + settingsInEffect.getTimeout());
        } else {
            Log.e(TAG, "onStartSuccess, settingInEffect is null");
        }
        Log.e(TAG, "onStartSuccess settingsInEffect" + settingsInEffect);

    }

    @Override
    public void onStartFailure(int errorCode) {
        super.onStartFailure(errorCode);
        Log.e(TAG, "onStartFailure errorCode" + errorCode);

        if (errorCode == ADVERTISE_FAILED_DATA_TOO_LARGE) {
            Toast.makeText(Main4Activity.this, "R.string.advertise_failed_data_too_large", Toast.LENGTH_LONG).show();
            Log.e(TAG, "Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.");
        } else if (errorCode == ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
            Toast.makeText(Main4Activity.this, "R.string.advertise_failed_too_many_advertises", Toast.LENGTH_LONG).show();
            Log.e(TAG, "Failed to start advertising because no advertising instance is available.");
        } else if (errorCode == ADVERTISE_FAILED_ALREADY_STARTED) {
            Toast.makeText(Main4Activity.this, "R.string.advertise_failed_already_started", Toast.LENGTH_LONG).show();
            Log.e(TAG, "Failed to start advertising as the advertising is already started");
        } else if (errorCode == ADVERTISE_FAILED_INTERNAL_ERROR) {
            Toast.makeText(Main4Activity.this, "R.string.advertise_failed_internal_error", Toast.LENGTH_LONG).show();
            Log.e(TAG, "Operation failed due to an internal error");
        } else if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
            Toast.makeText(Main4Activity.this, "R.string.advertise_failed_feature_unsupported", Toast.LENGTH_LONG).show();
            Log.e(TAG, "This feature is not supported on this platform");
        }
    }
};
}