Android 以格式发送 BLE 数据

Android send BLE data in format

我想以下面给出的图像格式发送 BLE 数据。Advertising Data packet。 我只是以字节格式发送测试数据 1,但如图所示,我必须在 0x11 处发送第一种广告数据类型的 0x22 长度数据,我已发送第二种数据类型的长度,依此类推。那么我应该如何根据图像设置它。

 public class MainActivity extends AppCompatActivity {
    private Button mAdvertiseButton,stopAdvertiseButton;
    private static final String TAG = "BLEApp";
    private BluetoothAdapter mBluetoothAdapter;
    public static final int REQUEST_ENABLE_BT = 1;
    private String Device_Name="Abc";
    private String Device_Id ="0x34Abc";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mAdvertiseButton=(Button) findViewById(R.id.adv);
        stopAdvertiseButton=(Button) findViewById(R.id.stopadv);

        mAdvertiseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (savedInstanceState == null)
                    mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE))
                            .getAdapter();
                // Is Bluetooth supported on this device?
                if (mBluetoothAdapter != null) {

                    // Is Bluetooth turned on?
                    if (mBluetoothAdapter.isEnabled()) {

                        // Are Bluetooth Advertisements supported on this device?
                        if (mBluetoothAdapter.isMultipleAdvertisementSupported()) {

                            // Everything is supported and enabled, load the method
                            advertise();

                        } else {

                            // Bluetooth Advertisements are not supported.
                            showErrorText(R.string.bt_ads_not_supported);
                        }
                    } else {

                        // Prompt user to turn on Bluetooth (logic continues in onActivityResult()).
                        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
                    }
                } else {

                    // Bluetooth is not supported.
                    showErrorText(R.string.bt_not_supported);
                }
            }
        });
        stopAdvertiseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                stopAdv();
            }
        });




    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void stopAdv() {
        AdvertiseCallback callback= null;
        BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
            advertiser.stopAdvertising(null);
        }







    private void advertise() {
        BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
        AdvertisingSetParameters parameters = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            parameters = (new AdvertisingSetParameters.Builder())
                    .setLegacyMode(true) // True by default, but set here as a reminder.
                    .setConnectable(false)
                    .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
                    .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
                    .build();
        }

        byte[] manufacturerData = new byte[] {
//                0x12, 0x34,
//                0x56, 0x66,
                0x41,0x4d,0x4f,0x4c


        };

        String testData = "abcdefghij";
        byte[] testData1=testData.getBytes();


        ParcelUuid pUuid = new ParcelUuid( UUID.fromString("CDB7950D-73F1-4D4D-8E47-C090502DBD63"));

        AdvertiseData data = (new AdvertiseData.Builder())
                .addManufacturerData(1, testData1)
                .setIncludeDeviceName(true)
               
                .build();
        //.addServiceData( pUuid, "Data".getBytes(Charset.forName("UTF-8") ) )

       AdvertisingSetCallback callback= null;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            callback = new AdvertisingSetCallback() {
                @Override
                public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
                    super.onAdvertisingSetStarted(advertisingSet, txPower, status);

                    Log.d(TAG, "onAdvertisingSetStarted(): txPower:" + txPower + " , status: "
                            + status);
                    AdvertisingSet currentAdvertisingSet = advertisingSet;

                    // After onAdvertisingSetStarted callback is called, you can modify the
                    // advertising data and scan response data:
                    currentAdvertisingSet.setAdvertisingData(new AdvertiseData.Builder().
                            addManufacturerData(67, testData1)
                           .setIncludeDeviceName(true)
                            .setIncludeTxPowerLevel(true).build());
                    // Wait for onAdvertisingDataSet callback...

                  ParcelUuid pUuid = new ParcelUuid(UUID.randomUUID());

                   currentAdvertisingSet.setScanResponseData(new
                            AdvertiseData.Builder().addServiceUuid(pUuid).build());
                         Log.d(TAG,"UUID"+pUuid);
//
                    // Wait for onScanResponseDataSet callback...
                    Log.d(TAG, data.toString() + status);

//                    currentAdvertisingSet.setScanResponseData(new AdvertiseData.Builder());
                }

                @Override
                public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
                    super.onAdvertisingSetStopped(advertisingSet);
                    Log.d(TAG, "onAdvertisingSetStopped():");
                }

                @Override
                public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status) {
                    super.onAdvertisingEnabled(advertisingSet, enable, status);
                }

                @Override
                public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
                    super.onAdvertisingDataSet(advertisingSet, status);
                    Log.d(TAG, "onAdvertisingDataSet() :status:" + status);
                }

                @Override
                public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
                    super.onScanResponseDataSet(advertisingSet, status);
                    Log.d(TAG, "onScanResponseDataSet(): status:" + status);
                }
            };
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            advertiser.startAdvertisingSet(parameters, data, null, null, null, callback);
            Toast.makeText(MainActivity.this, "Data"+data, Toast.LENGTH_LONG).show();
        }

        // When done with the advertising:
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//            advertiser.stopAdvertisingSet(callback);
//       }

        //


    }

Android 提供用于构建 BLE 广告消息负载的高级 API,因此您只需添加每个 handles 的值(句柄是长度的三元组-dataType-data) 图像中的消息。 例如,要添加 service(消息的第二个句柄),您不必设置 length (0x11) 和 data type (0x07) but only use addServiceUuid of the AdvertiseData.Builder,SDK会设置length and 为你输入。这对最后一个句柄(制造商数据)也有效,您必须使用 addManufacturerData.

对于第一个句柄(标志),您无法使用 AdvertiseData.Builder 设置,但 AdvertisingSetParameters.Builder()here. But according this answer 不再支持 limited discoverable 模式