问题
I am trying to implement a mobile app (on iPhone) that just scans for beacons and displays a notification for each one. I am a noob with beacons/bluetooth.
I implemented it using the universal beacon library (https://github.com/andijakl/universal-beacon) and i've attached my ios bluetooth implementation.
my problem is that i receive about 12 beacon added events even though i only have two (I assume it is picking up all my other bluetooth devices). I also only receive the local name in the advertisement_received event.
My questions are:
- how do I distinguish that it is a beacon being added?
- how do i get the unique id an url from the beacon? (they are kontakt beacons)
Thanks for any help.
My beacon service:
public BeaconService()
{
// get the platform-specific provider
var provider = RootWorkItem.Services.Get<IBluetoothPacketProvider>();
if (null != provider)
{
// create a beacon manager, giving it an invoker to marshal collection changes to the UI thread
_manager = new BeaconManager(provider, Device.BeginInvokeOnMainThread);
_manager.Start();
_manager.BeaconAdded += _manager_BeaconAdded;
provider.AdvertisementPacketReceived += Provider_AdvertisementPacketReceived;
}
}
My ios bluetooth implementation:
public class iOSBluetoothPacketProvider : CocoaBluetoothPacketProvider { }
public class CocoaBluetoothPacketProvider : NSObject, IBluetoothPacketProvider
{
public event EventHandler<BLEAdvertisementPacketArgs> AdvertisementPacketReceived;
public event EventHandler<BTError> WatcherStopped;
private readonly CocoaBluetoothCentralDelegate centralDelegate;
private readonly CBCentralManager central;
public CocoaBluetoothPacketProvider()
{
Debug.WriteLine("BluetoothPacketProvider()");
centralDelegate = new CocoaBluetoothCentralDelegate();
central = new CBCentralManager(centralDelegate, null);
}
private void ScanCallback_OnAdvertisementPacketReceived(object sender, BLEAdvertisementPacketArgs e)
{
AdvertisementPacketReceived?.Invoke(this, e);
}
public void Start()
{
Debug.WriteLine("BluetoothPacketProvider:Start()");
centralDelegate.OnAdvertisementPacketReceived += ScanCallback_OnAdvertisementPacketReceived;
// Wait for the PoweredOn state
//if(CBCentralManagerState.PoweredOn == central.State) {
// central.ScanForPeripherals(peripheralUuids: new CBUUID[] { },
// options: new PeripheralScanningOptions { AllowDuplicatesKey = false });
//}
}
public void Stop()
{
Debug.WriteLine("BluetoothPacketProvider:Stop()");
centralDelegate.OnAdvertisementPacketReceived -= ScanCallback_OnAdvertisementPacketReceived;
central.StopScan();
WatcherStopped?.Invoke(sender: this, e: new BTError(BTError.BluetoothError.Success));
}
}
internal class CocoaBluetoothCentralDelegate : CBCentralManagerDelegate
{
public event EventHandler<BLEAdvertisementPacketArgs> OnAdvertisementPacketReceived;
#region CBCentralManagerDelegate
public override void ConnectedPeripheral(CBCentralManager central, CBPeripheral peripheral)
{
Debug.WriteLine($"ConnectedPeripheral(CBCentralManager central, CBPeripheral {peripheral})");
}
public override void DisconnectedPeripheral(CBCentralManager central, CBPeripheral peripheral, NSError error)
{
Debug.WriteLine($"DisconnectedPeripheral(CBCentralManager central, CBPeripheral {peripheral}, NSError {error})");
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
Debug.WriteLine($"Cocoa peripheral {peripheral}");
Debug.WriteLine($"Cocoa advertisementData {advertisementData}");
Debug.WriteLine($"Cocoa RSSI {RSSI}");
var bLEAdvertisementPacket = new BLEAdvertisementPacket()
{
Advertisement = new BLEAdvertisement()
{
LocalName = peripheral.Name,
ServiceUuids = new List<Guid>(),
DataSections = new List<BLEAdvertisementDataSection>(),
ManufacturerData = new List<BLEManufacturerData>()
},
AdvertisementType = BLEAdvertisementType.ScanResponse,
BluetoothAddress = (ulong)peripheral.Identifier.GetHashCode(),
RawSignalStrengthInDBm = RSSI.Int16Value,
Timestamp = DateTimeOffset.Now
};
//https://developer.apple.com/documentation/corebluetooth/cbadvertisementdataserviceuuidskey
//if (advertisementData.ContainsKey(CBAdvertisement.DataServiceUUIDsKey))
//{
// bLEAdvertisementPacket.Advertisement.ServiceUuids.Add(
// item: new BLEManufacturerData(packetType: BLEPacketType.UUID16List,
// data: (advertisementData[CBAdvertisement.DataServiceUUIDsKey])));
//}
//https://developer.apple.com/documentation/corebluetooth/cbadvertisementdataservicedatakey
//if (advertisementData.ContainsKey(CBAdvertisement.DataServiceDataKey))
//{
// bLEAdvertisementPacket.Advertisement.DataSections.Add(
// item: new BLEManufacturerData(packetType: BLEPacketType.ServiceData,
// data: advertisementData[CBAdvertisement.DataServiceDataKey]));
//}
//https://developer.apple.com/documentation/corebluetooth/cbadvertisementdatamanufacturerdatakey
if (advertisementData.ContainsKey(CBAdvertisement.DataManufacturerDataKey))
{
bLEAdvertisementPacket.Advertisement.ManufacturerData.Add(
item: new BLEManufacturerData(packetType: BLEPacketType.ManufacturerData,
data: (advertisementData[CBAdvertisement.DataManufacturerDataKey]
as NSData).ToArray()));
}
// Missing CBAdvertisement.DataTxPowerLevelKey
var bLEAdvertisementPacketArgs = new BLEAdvertisementPacketArgs(data: bLEAdvertisementPacket);
OnAdvertisementPacketReceived?.Invoke(this, bLEAdvertisementPacketArgs);
}
public override void FailedToConnectPeripheral(CBCentralManager central, CBPeripheral peripheral, NSError error)
{
Debug.WriteLine($"FailedToConnectPeripheral(CBCentralManager central, CBPeripheral {peripheral}, NSError {error})");
}
public override void UpdatedState(CBCentralManager central)
{
switch (central.State)
{
case CBCentralManagerState.Unknown:
Debug.WriteLine("CBCentralManagerState.Unknown");
break;
case CBCentralManagerState.Resetting:
Debug.WriteLine("CBCentralManagerState.Resetting");
break;
case CBCentralManagerState.Unsupported:
Debug.WriteLine("CBCentralManagerState.Unsupported");
break;
case CBCentralManagerState.Unauthorized:
Debug.WriteLine("CBCentralManagerState.Unauthorized");
break;
case CBCentralManagerState.PoweredOff:
Debug.WriteLine("CBCentralManagerState.PoweredOff");
break;
case CBCentralManagerState.PoweredOn:
Debug.WriteLine("CBCentralManagerState.PoweredOn");
central.ScanForPeripherals(peripheralUuids: new CBUUID[] { },
options: new PeripheralScanningOptions { AllowDuplicatesKey = true });
break;
default:
throw new NotImplementedException();
}
}
public override void WillRestoreState(CBCentralManager central, NSDictionary dict)
{
Debug.WriteLine($"WillRestoreState(CBCentralManager central, NSDictionary {dict})");
}
#endregion CBCentralManagerDelegate
}
回答1:
So in case anyone is looking for this. The universal beacon library does not have an ios implementation that converts the ios packets to the universal packets. This need to be implemented.
- how do I distinguish that it is a beacon being added?
I look for the Eddystone packets and if found I add to the observable list.
- how do i get the unique id an url from the beacon? (they are kontakt beacons)
You need to loop through the advertisementData sent with the advertisement and create a BLEAdvertisementDataSection. copy the frame data as NSData.
来源:https://stackoverflow.com/questions/53990097/scanning-for-beacons-using-universal-beacon-library