NearDrop
NearDrop copied to clipboard
Advertising BLE service data from macOS
I'm fairly sure you should be able to do this on macOS (not iOS perhaps?). Here's an example. Specifically, CBAdvertisementDataServiceDataKey should be what you need.
I modified my test app to pass a Data for that key (the docs say that its value is a [CBUUID:Data] dictionary so that's what I was trying), it's still complaining that it's not an allowed key.
The service as seen by Android doesn't have any service data either:
Ah, I see. It looks like the nearby library actually recognizes this limitation too with a workaround:
/**
* Starts advertising service data in a way that is supported by CoreBluetooth.
*
* Since CoreBluetooth doesn't support setting the @c CBAdvertisementDataServiceDataKey key, the
* service list is advertised using @c CBAdvertisementDataServiceUUIDsKey and the associated data is
* advertised using @c CBAdvertisementDataLocalNameKey. Since @c CBAdvertisementDataLocalNameKey
* does not support binary data, the value is base64 encoded and truncated if the resulting value is
* longer than 22 bytes. This also means we can only support advertising a single service.
*
* @param serviceData A dictionary that contains service-specific advertisement data.
* @param completionHandler Called on a private queue with @c nil if successfully started
* advertising or an error if one has occured.
*/
- (void)startAdvertisingData:(NSDictionary<CBUUID *, NSData *> *)serviceData
completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler;
// Apple devices don't support advertising service data, so Apple devices advertise a base64
// encoded local name, while other devices advertise service data. Here we attempt to reconstruct
// service data by decoding the local name. If successful, this is possibly a Nearby advertisement
// on an Apple device.
NSString *localName = advertisementData[CBAdvertisementDataLocalNameKey];
// ...
// A Nearby Apple advertisement should only have a single service, so simply grab the first one if
// it exists.
NSArray<CBUUID *> *serviceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey];
// Maps service UUIDs to their service data.
//
// For each platform should follow to set the service UUID(key) and service
// data(value):
//
// iOS : 16 bit service UUID (type=0x03) + LocalName data (type=0x08)
// Windows: Service data (type=0x16)
// Android: 16 bit service UUID (type=0x03) + Service data (type=0x16)
absl::flat_hash_map<Uuid, nearby::ByteArray> service_data;
Can you see if this method works instead?
I tried this:
Didn't trigger neither the notification nor the MDNS service.
It looks like iOS/macOS BLE advertisement was only added to the google/nearby project last month by @bourdakos1 actually, so perhaps the Android/Play services system library isn't ready for it yet. Of note, it looks like migration of the Nearby Share code to the public project only started 2 weeks ago as well.
Okay then. Maybe they're preparing to ship their (inevitably worse lol) Nearby Share app for macOS.
Another thing to keep in mind is that google/nearby is their universal cross-platform implementation in C++ that is maybe used by projects like Chromium, but Play Services uses another, closed-source (as far as I can tell) pure-Java implementation.
I decompiled the latest (as of now) version of Play Services and found this:
So this fallback is implemented, but it's behind what looks like a server flag, that defaults to false:
(I renamed things here and there to make the code easier to understand)
In case someone wants to look at it themselves, the bulk of code dealing with the reception of these BLE advertisements is in com.google.android.gms.nearby.sharing.discovery.FastInitiation
Would using private apis be off the menu? The BluetoothHCILESetAdvertisingParameters https://github.com/seemoo-lab/internalblue/blob/master/macos/IOBluetoothExtended/IOBluetoothExtended/IOBluetoothHostController.h#L126C8-L126C40
eg https://github.com/RadiusNetworks/scanbeacon-gem/blob/f3f9ff9123593ff821b3dba7f253d9735e10082f/ext/core_bluetooth/core_bluetooth.m#L213-L222 ?
I'm totally fine with using private APIs, I'll test this one, although I don't have my hopes up
Oh these APIs are the ones I've already tested and they didn't work on modern macOS versions https://github.com/grishka/NearDrop/issues/4#issuecomment-1714705145