これは広告主です(通知はタイプdata
として渡されますAdvertiseData
)
private void advertise() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothLeAdvertiser advertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.setConnectable(false)
.build();
ParcelUuid pUuid = new ParcelUuid(UUID.fromString("cf2c82b6-6a06-403d-b7e6-13934e602664"));
AdvertiseData data = new AdvertiseData.Builder()
//.setIncludeDeviceName(true)
.addServiceUuid(pUuid)
.addServiceData(pUuid, "123456".getBytes(Charset.forName("UTF-8")))
.build();
AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.i(tag, "Advertising onStartSuccess");
super.onStartSuccess(settingsInEffect);
}
@Override
public void onStartFailure(int errorCode) {
Log.e(tag, "Advertising onStartFailure: " + errorCode);
super.onStartFailure(errorCode);
}
};
advertiser.startAdvertising(settings, data, advertiseCallback);
}
正常に起動しました。
これはスキャナーです
private void discover() {
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.build();
mBluetoothLeScanner.startScan(null, settings, mScanCallback);
}
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i(tag, "Discovery onScanResult");
if (result == null) {
Log.i(tag, "no result");
return;
}
ScanRecord scanRecord = result.getScanRecord();
List<ParcelUuid> list = scanRecord != null ? scanRecord.getServiceUuids() : null;
if (list != null) {
Log.i(tag, scanRecord.toString());
for (ParcelUuid uuid : list) {
byte[] data = scanRecord.getServiceData(uuid);
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.i(tag, "Discovery onBatchScanResults");
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.e(tag, "Discovery onScanFailed: " + errorCode);
}
};
コールバックでは、この出力を生成するonScarnResult
スキャンレコードを記録しますtoString()
ScanRecord [mAdvertiseFlags=2,
mServiceUuids=[cf2c82b6-6a06-403d-b7e6-13934e602664],
mManufacturerSpecificData={},
mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]},
mTxPowerLevel=-2147483648, mDeviceName=null]
uuidは一致しましたが、残念ながら結果は
byte[] data = scanRecord.getServiceData(uuid)
出力には、宣伝されているデータ文字「123456」のASCIIコード、つまり49、50、51、52、53、54が含まれているnull
ことに気付きました。toString
mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]}
正しい広告データを受け取りたいのですが、何か間違っているのでしょうか?
編集: マニフェストには、Bluetooth、BT管理、位置情報の権限があります。3番目は、Android 6で実行時にリクエストを開始します。
編集: スキャンレコード全体を印刷すると、この出力が得られます
スキャン記録 [mAdvertiseFlags=-1、mServiceUuids=[cf2c82b6-6a06-403d-b7e6-13934e602664]、mManufacturerSpecificData={}、mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49、50、51、52、53、54]}、mTxPowerLevel=-2147483648、mDeviceName=null]
基本的に、mServiceUuids 配列にある広告主が決定した uuid は使用できません。mServiceData に関連付けられたキーは別のキーであるためです。そのため、データ マップをナビゲートして値を取得するために、コードを次のように変更しました (2 つの if ブロックを参照してください)。
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
for (ScanResult result : results) {
ScanRecord scanRecord = result.getScanRecord();
List<ParcelUuid> uuids = scanRecord.getServiceUuids();
Map<ParcelUuid, byte[]> map = scanRecord.getServiceData();
if (uuids != null) {
for (ParcelUuid uuid : uuids) {
byte[] data = scanRecord.getServiceData(uuid);
Log.i(tag, uuid + " -> " + data + " contain " + map.containsKey(uuid));
}
}
if (map != null) {
Set<Map.Entry<ParcelUuid, byte[]>> set = map.entrySet();
Iterator<Map.Entry<ParcelUuid, byte[]>> iterator = set.iterator();
while (iterator.hasNext()) {
Log.i(tag, new String(iterator.next().getValue()));
}
}
}
}
実際、
map.containsKey(uuid)
広告主の UUID がデータ マップで使用されていないため、false を返します。
値 (2 番目の if ブロック) を見つけるためにマップを移動する必要がありましたが、それが興味のある値であるかどうかを知る手段がありません。いずれにしても、システムが、受信側アプリでスキャナーのコードを実行しているときに、私が知ることができない別のキーを配置した場合、値を取得できません。
受信側でこの問題をどのように処理すればよいでしょうか? データ フィールドを使用したいのですが、それを取得するための文字列キーは事前にわかっておらず、システムによって決定されます。
ベストアンサー1
古いスレッドであることは承知していますが、私も同じ問題を抱えていて解決策を見つけたので...
.addServiceUuid()
アドバタイザーで使用される UUIDとアドバタイザー内で使用される UUID.addServiceData()
は異なるオブジェクトです。最初の UUID はサービスを識別し、128 ビットの UUID です。2 番目の UUID は、そのサービス内の serviceData を識別し、16 ビットの UUID であることが期待されます。
これがスキャナーが受信する理由です
0000**82b6**-0000-1000-8000-00805f9b34fb
16 ビットは0x82b6
.addServiceData に渡される UUID と共通であることに注意してください。
cf2c**82b6**-6a06-403d-b7e6-13934e602664
16 ビットの UUID は、96 ビットを左シフトし、Bluetooth 定数 UUID を追加することで 128 ビットに変換されます。
解決策は、この形式の UUID [ 0000xxxx-0000-1000-8000-00805f9b34fb
] を使用して、広告主とスキャナーの両方でサービスデータを識別することです。元の 128 ビット UUID を保持してサービスを識別することができます。