I'm trying to get the ASK Sample to discover and connect to a device using a 16-bit uuid. In my case, I have a few fitness sensors laying around like heart rate monitors and cycling sensors.
Specifically, I've configured the following descriptor to be shown in the picker:
private static let heartRateMonitor: ASPickerDisplayItem = {
let descriptor = ASDiscoveryDescriptor()
descriptor.bluetoothServiceUUID = CBUUID(string: "180D")
return ASPickerDisplayItem(name: "Heart Rate Monitor", productImage: UIImage(named: "PolarH10")!, descriptor: descriptor)
}()
100% another app on the device using an unfiltered scan can find this device, so I know the phone can see it. Also, the settings app Bluetooth screen sees it too.
When the picker is active for this descriptor, in console I see the device is being discovered and it is matching the underlying filter. However the picker doesn't show the device.
Received 'start active Unspecified scan' request , without duplicates, duration:unlimited, UUIDs [ E56A082E-C49B-47CA-A2AB-389127B8ABE3 E56A082E-C49B-47CA-A2AB-389127B8ABE4 0x180D ] on 1M PHY from session "com.apple.deviceaccessd-central-727-198"
Matched UUID 0x180D for device "D3030A85-BBB9-6C0D-53C4-6697898B2E4B"
This is an apparent bug:
FB14078940 - AccessorySetupKit: ASDiscoveryDescriptor does not appear to identify 16-bit UUIDs like the Heart Rate Service/Profile UUID
After more tinkering, I did discover that if I connect the device in the settings app, and keep it connected, the picker will find the device immediately. I assume it is under the hood it is calling this function or the internal implementation: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/retrieveconnectedperipherals(withservices:)
This is still not expected, a developer should be able to discover and connect an accessory directly in their app.
Noteworthy, I also found that ALL apps in the Settings app list the accessory once paired, which is totally not expected:
FB14170263 - Settings: Viewing accessories in settings app for all apps show the accessory paired with another application
P.S. forum moderators, there is no tag for 'AccessorySetupKit' which is the technology I'd like to tag this with.
Last tested with iOS 18 developer beta 2.
Core Bluetooth
RSS for tagCommunicate with Bluetooth 4.0 low energy devices using Core Bluetooth.
Posts under Core Bluetooth tag
177 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I am converting some old objective-C code deployed on ios 12 to swift in a WKWebView app. Im also developing the app for Mac via MacCatalyst. the issue im experiencing relates to a programmable learning bot that is programmed via block coding and the app facilitates the read and writes back and forth. the audio works via a A2DP connection the user sets manually in their settings, while the actual movement of the robot is controlled via a BLE connection. Currently the code works as intended on MacCatalyst, while on iPhone, the audio being sent back to the robot is very choppy and sometimes doesn't play at all. I apologize for the length of this, but there is a bit to unpack here.
First, I know there has been a few threads posted about this issue, this one that seems similar but went unsolved https://forums.developer.apple.com/forums/thread/740354
as well as this one where apple says it is "log noise"
https://forums.developer.apple.com/forums/thread/742739
However I just find it hard to believe that this issue seems to be log noise in this case. Mac Catalyst uses a legacy header file for WebKit, and im wondering if that could be part of the issue here.I have enable everything relating to bluetooth in my info plist file as the developer documents say. In my app sandbox for mac catalyst I have the permissions set for bluetooth as well there. Here are snippets of my read and write function
func readFunction(session: String){
// Wait if we are still waiting to hear from the robot
if self.serialRxBuf == ""{
self.emptyReadCount += 1
}
if (!self.serialRxWaiting){
return
}
// Make sure we are waiting for the correct session
if (Int(session) != self.serialRxSession){
return
}
self.serialRxWaiting = false
self.serialRxSession += 1
let buf = self.serialRxBuf
self.serialRxBuf = ""
print("sending Read: \(buf)")
self.MainWebView.evaluateJavaScript("""
if (serialPort.onRead) {
serialPort.onRead("\(buf)");
}
serialPort.onRead = null;
"""
,completionHandler: nil)
}
// ----- Write function for javascript bluetooth interface -----
func writeFunction(buf: String) -> Bool {
emptyReadCount = 0
if((self.blePeripheral == nil) || (self.bleCharacteristic == nil) || self.blePeripheral?.state != .connected){
print("write result: bad state, peripheral, or connection ")
// in case we recieve an error that will freeze react side, safely navigate and clear bluetooth information.
if MainWebView.canGoBack{
MainWebView.reload()
showDisconnectedAlert()
self.centralManager = nil // we will just start over next time
self.blePeripheral = nil
self.bleCharacteristic = nil
self.connectACD2Failed()
return false
}
return false
}
var data = Data()
var byteStr = ""
for i in stride(from: 0, to: buf.count, by: 2) {
let startIndex = buf.index(buf.startIndex, offsetBy: i)
let endIndex = buf.index(startIndex, offsetBy: 2)
byteStr = String(buf[startIndex..<endIndex])
let byte = UInt8(byteStr, radix: 16)!
data.append(byte)
}
guard let connectedCharacteristic = self.bleCharacteristic else {
print("write result: Failure to assign bleCharacteristic")
return false
}
print("sending bleWrite: \(String(describing: data))")
self.blePeripheral.writeValue(data, for: connectedCharacteristic, type: .withoutResponse)
print("write result: True")
return true
}
Here is what the log looks like when running on mac catalyst, which works just fine
sending bleWrite: 20 bytes
write result: True
sending Read:
sending Read: 55AA55AA0B0040469EE6000000000000000000ED
sending bleWrite: 20 bytes
write result: True
sending Read:
sending Read:
sending Read: 55AA55AA0B0040469EE6000000000000000000ED
sending bleWrite: 20 bytes
write result: True
sending Read: 55AA55AA0B0040469EE6000000000000000000ED
sending bleWrite: 20 bytes
write result: True
sending Read: 55AA55AA0B0040EDCB09000000000000000000ED
sending bleWrite: 20 bytes
write result: True
sending Read:
sending Read: 55AA55AA0B00407A7B96000000000000000000ED
sending bleWrite: 20 bytes
write result: True
Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement com.apple.multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement com.apple.multitasking.systemappassertions)}>
0x12c0380e0 - ProcessAssertion::acquireSync Failed to acquire RBS assertion 'WebKit Media Playback' for process with PID=36540, error: Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement com.apple.multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement com.apple.multitasking.systemappassertions)}
and here is the log from when we are running the code on iPhone (trying to save space here)
I apologize for the length of this post, however submitting a test project to apple developer support just isn't possible with the device thats in use. Any help at all is appreciated. i've looked at every permission, entitlement, background processing, and tried every solution that I could find to no avail.
I am looking to do the OOB (Out of band) pairing using QR code with a device from iOS app. I referred the documentation but could not find if this is feasible or not. Few forum says it is not feasible, few says it is. May I know the latest state from Apple development support team?
Hello, as the title says, I am trying to access Bluetooth in a system daemon. I am running on MacOS Sonoma 14.5.
When initializing Bluetooth, my daemon received Unauthorized state.
I have tried to add my daemon in the system settings (System Preferences > Security & Privacy > Privacy > Bluetooth) "Allow applications to access Bluetooth" by adding the program executable path defined by the entry Program of my system daemon as suggested here: https://developer.apple.com/forums/thread/662459.
But I am still having the issue.
Writing a system daemon with Bluetooth is not my final goal. The bigger picture is the smartcard reader driver with Bluetooth access which as the same issue and the solution is probably related.
I do not remember how but my smartcard reader driver use to work with Bluetooth but it does now with the same Unauthorized error.
As far as I can see daemon and smartcard drivers does not have support for entitlement.
Here are the logs for my sample system daemon:
my_daemon [0x6000011b0000] activating connection: mach=true listener=false peer=false name=com.apple.server.bluetooth.le.att.xpc
bluetoothd [0x7f804828e8a0] activating connection: mach=false listener=false peer=true name=com.apple.server.bluetooth.le.att.xpc.peer[76672].0x7f804828e8a0
bluetoothd Received XPC message "CBMsgIdCheckIn" from session ""
bluetoothd Received XPC check-in from session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" fAccessLevel 0 fProgrammaticPairing 0 fLimitedForMediaAccess 0
bluetoothd Access level is less than kXPCAccessLevelSystem for session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67". Restricted state operation not allowed
bluetoothd Sending 'session attached' event for session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67"
bluetoothd Attached session for "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" with session: 0x7f804802d1b0, session handle: 0xef8d0000
bluetoothd Registering peripheral session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" with backgrounding: off, persistence: off (CBSR) restoreID: (null)
bluetoothd Error getting Application State for <private>: <private>, 3
bluetoothd Error getting Application State for <private>: <private>, 3
bluetoothd Session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" tccRequired : 1
bluetoothd ReadyForTCC. TCC required:1 fLimitedForMediaAccess:0 fDeviceAccessForMediaExtension:0
bluetoothd Session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67" : needsRestrictedStateOperation = 0, overrideRestrictedState = 0 , denylistMode = 0, receivesControllerBTClockEvents=0
my_daemon Received CBMsgIdReadyForTCC
my_daemon Running performTccCheck CBManager tccAvail 1, tccRequired 1
my_daemon TCC required
my_daemon [0x6000011b8000] activating connection: mach=true listener=false peer=false name=com.apple.tccd
my_daemon [0x6000011b8000] failed to do a bootstrap look-up: xpc_error=[3: No such process]
my_daemon [0x6000011b8000] invalidated after a failed init
my_daemon send_message_with_reply(): user tccd unavailable, sending 0x600000ab4000 to system tccd
my_daemon [0x6000011b4000] activating connection: mach=true listener=false peer=false name=com.apple.tccd.system
tccd [0x7fd4d1f7ed80] activating connection: mach=false listener=false peer=true name=com.apple.tccd.system.peer[76672].0x7fd4d1f7ed80
tccd REQUEST: tccd_uid=0, sender_pid=76672, sender_uid=0, sender_auid=-1, function=TCCAccessRequest, msgID=76672.1
tccd AUTHREQ_CTX: msgID=76672.1, function=<private>, service=kTCCServiceBluetoothAlways, preflight=no, query=1, client_dict=(null), daemon_dict=<private>
tccd AUTHREQ_ATTRIBUTION: msgID=76672.1, attribution={requesting={TCCDProcess: identifier=my_daemon-5555494498236e3b5e2e395b93c13af176769937, pid=76672, auid=0, euid=0, binary_path=/Users/olivier/daemon/my_daemon}, },
tccd AUTHREQ_SUBJECT: msgID=76672.1, subject=/Users/olivier/daemon/my_daemon,
tccd Refusing TCCAccessRequest for service kTCCServiceBluetoothAlways from client Sub:{/Users/olivier/daemon/my_daemon}Resp:{TCCDProcess: identifier=my_daemon-5555494498236e3b5e2e395b93c13af176769937, pid=76672, auid=0, euid=0, binary_path=/Users/olivier/daemon/my_daemon} in background session
tccd AUTHREQ_RESULT: msgID=76672.1, authValue=0, authReason=5, authVersion=1, error=(null),
tccd REPLY: (0) function=TCCAccessRequest, msgID=76672.1
my_daemon [0x6000011b4000] invalidated after the last release of the connection object
bluetoothd Received XPC message "CBMsgIdTCCDone" from session "my_daemon-5555494498236e3b5e2e395b93c13af176769937-peripheral-76672-67"
tccd [0x7fd4d1f7ed80] invalidated after getting a no-senders notification - client is gone
bluetoothd [0x7f80482820f0] activating connection: mach=true listener=false peer=false name=com.apple.tccd.system
tccd [0x7fd4d32585f0] activating connection: mach=false listener=false peer=true name=com.apple.tccd.system.peer[169].0x7fd4d32585f0
tccd REQUEST: tccd_uid=0, sender_pid=169, sender_uid=0, sender_auid=-1, function=TCCAccessRequest, msgID=169.48
tccd [0x7fd4d313d880] activating connection: mach=true listener=false peer=false name=com.apple.tccd
tccd [0x7fd4d313d880] failed to do a bootstrap look-up: xpc_error=[3: No such process]
bluetoothd [0x7f80482820f0] invalidated after the last release of the connection object
bluetoothd Bluetooth user permission alwaysAuth: denied
tccd [0x7fd4d313d880] invalidated after a failed init
tccd FORWARD: to=com.apple.tccd/0, request: {
require_purpose=<xpc_null>
service="kTCCServiceBluetoothAlways"
function="TCCAccessRequest"
preflight=true
target_token={pid:76672, auid:-1, euid:0}
TCCD_MSG_ID="169.48"
background_session=false
}
tccd REPLY: from=com.apple.tccd, reply: {
XPCErrorDescription="Connection invalid"
}
tccd forwardMessage error: Connection invalid.
tccd [0x7fd4d3152bf0] activating connection: mach=false listener=false peer=true name=com.apple.tccd.system.peer[169].0x7fd4d3152bf0
bluetoothd [0x7f80482820f0] activating connection: mach=true listener=false peer=false name=com.apple.tccd.system
tccd REQUEST: tccd_uid=0, sender_pid=169, sender_uid=0, sender_auid=-1, function=TCCAccessRequest, msgID=169.49
tccd [0x7fd4d32585f0] invalidated after getting a no-senders notification - client is gone
tccd [0x7fd4d1f4c810] activating connection: mach=true listener=false peer=false name=com.apple.tccd
tccd [0x7fd4d1f4c810] failed to do a bootstrap look-up: xpc_error=[3: No such process]
tccd [0x7fd4d1f4c810] invalidated after a failed init
tccd FORWARD: to=com.apple.tccd/0, request: {
require_purpose=<xpc_null>
service="kTCCServiceBluetoothAlways"
function="TCCAccessRequest"
preflight=true
target_token={pid:76672, auid:-1, euid:0}
TCCD_MSG_ID="169.49"
background_session=false
}
tccd REPLY: from=com.apple.tccd, reply: {
XPCErrorDescription="Connection invalid"
}
tccd forwardMessage error: Connection invalid.
Hello,
Our app is going to be used in an industrial setting where users will connect to many devices a day via Bluetooth to complete an installation process. They will only connect to one device at a time, so connection limit isn't an issue.
What we're wondering about is the limit on number of pairings (found in Settings > Bluetooth > MY DEVICES). This is important because pairings can't be removed programatically. I seem to remember reading somewhere the limit was ~30 devices, but I can't find that document anymore. Does anyone know if this limit is correct, or where I could find a document regarding this?
I set up my app very similar to the sample app, putting the Service UUID in the plist and descriptor, I am able to see the picker but when my device is advertising, it doesn't seem to be responding to it. I see it stuck on "Discovering" and then it times out saying "Make sure the accessory is nearby and ready to connect". I also noticed that when I remove the ASK code but leave in the ASK fields in the info plist, my CBManagerAuthroization state is always "not determined". Can anyone help me troubleshoot these 2 issues? Perhaps they are related?
I have created a demo iOS app to create BLE connection with surrounding headphone.
I am able to connect to headphone successfully through my demo iOS app. I can also see in iPhone Bluetooth Setting that headphone is connected but when i am playing music from Spotify/YouTube then music is not being played through headphone. It is still using iPhone speakers.
First i am scanning sarounding bluetooth Devices through CBCentralManager and then connecting one of the found device.
cBCenteralManager.scanForPeripherals(withServices: nil, options: nil)
For connecting:
cBCenteralManager.connect(peripheral, options: nil)
Do i need to make any code changes while connecting via BLE?
I am expecting when i am connecting to headphone via my Demo app. Same connection is visible in iPhone Bluetooth setting too then when i play music on spotify/youtube then sound should be played on headphone and not on iPhone speakers.
Hey Apple,
We (our customer support teams) have received feedback from our customers complaining their hearing devices (hearing aids) appear to be connected to MFi and OS controls are working, but audio stream isn't working, and the app is unable to resolve a connection to the device via the CBCentralManager.retrieveConnectedPeripherals(withServices:)
The issues appear to disappear once the user unpairs and re-pair the hearing devices in the Accessibility > Hearing Devices options (they might also need to uninstall and reinstall the app as it is getting stuck due to invalid state), but we are unable to replicate this issue on our environments given it is intermittent and once we have upgraded a device to iOS 17.5.1, we don't have a mechanism to revert to an earlier version of it.
So far, we have received about 30 reports for the past 2 weeks. Most of our customers complain about the app not connecting to the devices, but the fact the audio stream is not happening could hint to a deeper problem than our app.
Are you guys aware of a problem affecting MFi hearing devices restoring after the OS upgrade process?
We want to use AccessorySetupKit to pair our BLE accessories. However, currently all our products announce the same BLE service UUID. The manufacturer data is different for every product.
I try to pair our products with ASK and create the ASDiscoveryDescriptor with the expected manufacturer data:
let descriptorA = ASDiscoveryDescriptor()
descriptorA.bluetoothServiceUUID = CBUUID("CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2") // same
descriptorA.bluetoothManufacturerDataBlob = Data([0xd2, 0x0a, 0x00, /* A */ 0x2a, 0x00, 0x00, 0x00]) // different
descriptorA.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
let descriptorB = ASDiscoveryDescriptor()
descriptorB.bluetoothServiceUUID = CBUUID("CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2") // same
descriptorB.bluetoothManufacturerDataBlob = Data([0xd2, 0x0a, 0x00, /* B */ 0x2b, 0x00, 0x00, 0x00]) // different
descriptorB.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
However, it seems random which device is found, as if the service UUID is the primary key to handle things in ASK.
My questions are:
Is it possible to use only manufacturer data to distinguish between different products with the same service UUID?
How do I use bluetoothManufacturerDataMask properly? I assume that internally some filtering like this is done: DataBlob & DataMask == ReceivedManufacturerData & DataMask. Because of that I have set all bits of the mask to 1. Should this e done differently?
Hi,
I just watched session "10203" on "Meet AccessorySetupKit". In 09:13, it was mentioned that there is special UI for entering PIN codes / passphrases. How exactly is this UI triggered? And is there any UI for setting a pin during initial setup? I couldn't find any further information about any of this in the documentation.
Best,
Klemens
Hi,
Please let me know iOS 18 beta have deprecated/ stopped support for which of the following:
proximityUUID
CLBeaconRegion
(instancetype)initWithProximityUUID:(NSUUID *)proximityUUID identifier:(NSString *)identifier
(void)startRangingBeaconsInRegion:(CLBeaconRegion *)region
-startRangingBeaconsSatisfyingConstraint: , is this also deprecated in iOS 18 beta, since: CLBeaconIdentityConstraint is deprecated right?
CLBeaconIdentityCondition is not supported in XCode 15.3. What should I do for this? Should I install XCode 16 beta?
locationManager:didRangeBeacons:satisfyingConstraint: can we use it in iOS 18 beta, since, CLBeaconIdentityConstraint is deprecated? what is alternative
startMonitoring(for:) is also deprecated in iOS 18 beta right?
Also, can someone specify or create a documentation on how beaconing shall be monitored, ranged and locationManager delegate methods pertaining to beaconing to be used in iOS 18 beta?
We have a BLE app and we are trying to get it to work in Background Mode consistently.
Use case:
RFID BLE reader is attached to a printer
Person installs the iOS app on phone and enables Background Mode
Person walks to the printer with phone
iOS App connects to RFID BLE reader and authenticates to allow secure printing
Current status/Problem:
On several tests, we were able to connect to the BLE device, but with inconsistent results.
For example, for 5 - 2 min tests - (1) we see 8 successful scans, (2) 1 successful scan, (3) 20 successful scans, (4) 15 successful scans, and (5) 11 successful scans.
In the above tests, we were getting a scan every 3-4 secs and then it scanning stops.
The objective is to maintain continuous scanning until user closes app or disables background mode.
Why does scanning stop? How can we make scanning continuous?
Any guidance you can provide is appreciated.
I am learning about endpoint security and other system extensions, while I was handling ES_EVENT_TYPE_AUTH_IOKIT_OPEN event I realized that I cannot auth deny any bluetooth events. I tried to deny any open or execute events related to com.apple.bluetoothd but it did not work. I searched google and found out that I can use CoreBluetooth to control bluetooth. But when I get connected to bluetooth keyboard or mouse, didConnectPeripheral dose not get called or when I call [central cancelPeripheralConnection:peripheral] disconnection never happens.
Is there any recommendation for handling or controlling events related to bluetooth connection?
We have observed a significant increase in download time from the sensors to the mobile device after recent OS updates. We are connected to the external sensors via the BLE interface using the following connection
parameters(15,15,0,6000)
https://mbientlab.com/tutorials/MetaMotionRL.html:
example 1.For 1 Meter with duration of 28 Seconds the IOS 17.1 taking 44 secs where as IOS 17.5.1 taking 82 secs .
2..For 1 Meter with duration of 45 Seconds the IOS 17.1 taking 74 secs where as IOS 17.5.1 taking 143 secs .
Even with the same connection parameters, download times were considerably lower in iOS 15 and below devices.
We are currently using the connection parameters 15, 15, 0, 6000.
I have learned from some documents that the minimum connection interval was changed to 20, but when I tried it, the download time increased further. I am seeking assistance on how to achieve the same download times as the older versions.
https://mbientlab.com/community/discussion/comment/11852#Comment_11852
I am trying to code out a background refresh part of my app but there are two centralManager functions in the app.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if peripheral.identifier.uuidString == selected {
selectedPeripheral = peripheral
centralManager?.stopScan()
centralManager?.connect(selectedPeripheral!, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connected to peripheral: \(peripheral)")
// Subscribe to disconnection events
peripheral
.publisher(for: \.state)
.sink { [weak self] state in
if state == .connected {
self?.isConnected = true
} else if state == .disconnected {
// Peripheral is disconnected, send notification
if self?.isConnected == true {
self?.sendNotification()
self?.isConnected = false
}
}
}
.store(in: &cancellables)
}
and this is the refresh part
private func handleBluetoothMonitoring(task: BGAppRefreshTask, bluetoothMonitor: BluetoothMonitor) {
let queue = DispatchQueue(label: "com.yourcompany.bluetoothmonitor")
task.expirationHandler = {
// Handle expiration of the task if needed
}
queue.async {
// Perform Bluetooth monitoring tasks here
if let centralManagerInstance = bluetoothMonitor.centralManager {
DispatchQueue.main.async {
bluetoothMonitor.centralManagerDidUpdateState(centralManagerInstance)
}
} else {
print("Central manager is nil")
}
// End the task
task.setTaskCompleted(success: true)
}
}
Is there a way to solve this? Thanks!
Hello everyone,
I hope you’re all doing well. I have a question regarding the use of Apple's Find My network.
I’m in the early stages of developing an app that would track third-party Find My-compatible tags. Before proceeding further, I want to ensure that I am compliant with Apple’s guidelines and policies.
Can anyone provide insight into whether Apple allows developers to use the Find My crowd-sourced network for their own apps? Specifically, I'm interested in tracking third-party Find My tags through my app.
Any guidance or resources you can share would be greatly appreciated!
Thank you!
I'm trying to broadcast some customized data into the peripheral advertisingData package. Based on the WWDC 2019, and some posts Ios BLE extended Advertising example, seems like with iphone devices that support bluetooth 5.0, we can send up to 124 bytes.
However Apple didn't say how to send extensive advertisement data (which key or API to use). And I tested with the CBAdvertisementDataLocalNameKey, seems like I can still ONLY send within 31 bytes. My code:
@IBAction func switchChanged(_ sender: Any) {
// All we advertise is our service's UUID.
if advertisingSwitch.isOn {
peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [TransferService.serviceUUID], CBAdvertisementDataLocalNameKey: "1234567890asddsgsfhgfshfgshfsggdrfgdbfsbfgshgfshbfgb"])
} else {
peripheralManager.stopAdvertising()
}
}
And on the central side, my code:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
os_log("name:", String(name))
}
}
But I only got the first some bytes:
name String "1234567890asddsgsfhgfshfgs"
My question is, does apple really support Extended Advertising starting from iPhone 8? If so, how should I use it to send data up to 124 bytes?
I have encountered a strange behavior these past couple weeks while dealing with Bluetooth, mostly because my code hasn't changed in over 6 months (maybe it was not working before and now it's correct, who knows). Essentially, when i pair with a bluetooth device for the first time, the onchange has stopped firing. I can post more exact code of the view but I didn't think it was necessary but after you select the device you want to connect to (for the first time) you get asked by the OS to pair. After successful connection, we read information from the device (the Profiles). Once I get that information, i set dataGathered to true which triggers .onChange and I can navigate. However, with this initial connection/pairing the .onChange is never triggered, but i know i'm getting my dataGathered set to true because my print is being set. Subsequent connections do cause .onChange to be triggered with 0 profiles and with many profiles. This code hasn't changed in months so i'm not sure if there's SwiftUI bug that's sprung up or what, or if there's an inherint issue with what i was doing and it's only now being caught.
struct DeviceSearchView: View {
@StateObject var connectedManager: Manager = Manager()
@StateObject var bluetoothListener: Listener = BluetoothListener()
var body: some View {
body
.onChange(self.bluetoothListener.connectedDevice) { device in
device.getData()
}
.onChange(self.connectedManager.dataGathered) { dataGathered in
// determine navigation
}
}
}
Manager Object
final class Manager: ObservedObject, BTDelegate, Identifiable /*i've tried adding/switching with Equatable but no change*/ {
@Published var dataGathered: Bool = false
@Published var profileList: Profile = [Profile]()
@Published var index: Int = 0
func updatedProfile(list: NSArray, selectedIndex: Int) {
print("profiles are in fact here")
var newList = [Profile]()
for element in list {
if let profile = element as? B50Profile {
print("\(profile.name)")
if !newList.contains(profile){
newList.append(profile)
}
}
}
self.profileList = newList
self.index = selectedIndex
self.dataGathered = true
print("data gathered is \(self.dataGathered)"
}
}
We are developing an app which connects to a BLE peripheral in the background whenever it gets close to it. What we have used so far is that we monitor a circular region. When the phone enters the region the app will start scanning for peripherals and when it discovers the peripheral it connects to it.
This worked pretty well for the last few iOS versions, perhaps iOS 14-16. It wasn't perfect but for the most part it would feel like it connected rather quickly when you would approach the BLE peripheral. If you listen to music via BLE or talk to someone using your BLE headset then it could sometimes work noticeably worse. But, as said, for the most part it would work satisfactory.
Starting with iOS 17 and analyzing the functionality over the past 6 months or so we've noticed a clear worsening of it. It does generally connect to the peripheral but the user might often have to wait for quite some time. Rather frequently the user must even light up the screen of the phone before anything even happens. It appears that some sort of resource allocation, battery saving feature or similar has affected this functionality greatly. The time difference between entering a region and physically approaching the device is generally around 2-3 minutes.
We have tried to do it more in line with documentation and follow the guidelines that we find in:
https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
So in doing this we do not start scanning for peripherals when a region is entered, but instead we directly invoke connectPeripheral:options:. This way we offload to the system that we want to connect to that peripheral. However, when testing this we see no real improvement. Sometimes it connects satisfactorily. Sometimes it doesn't really connect at all. Many times it connects if the user lights up the screen. So just looking at what the user is experiencing our analysis is that doing it this way works even worse than what we previously did.
I understand that the system has many resources to consider and that some may have to wait while others perform things. But are there any documentation on what one could expect from initiating a connectPeripheral:options: from the background? In the link I posted it simply states the iOS device will reconnect when the user returns home. So not much detail in terms of performance which is crucial for our application.
If there aren't any further details on the performance, are there any other ways to improve this functionality? We are not looking at draining the battery whatsoever but we simply need our background running app to be as responsive as possible for a few minutes after it has been launched by the region monitoring. We understand that battery life is important but since this happens rarely and sparsely (not more than a few times per day) it seems reasonable that there should be a way to be able to make it function properly.
The crash logs for my app show an occasional crash that happens during the launch of the app. The highlighed line is "CoreBluetooth -[CBUUID initiWithData:]. The stack trace ends with "static AppDelegate.$main()".
My app does use Core Bluetooth, but there are no Bluetooth related functions in the App Delegate. Also, my app does not use [CBUUID initWithData:] explicitly anywhere.
With a stack trace that contains no reference to any of my code, it is extremely difficult to figure out what is going on. I cannot reproduce the crash on any of my own devices. One of my affected users says the app crashes on startup on his phone consistently, even if he deletes and reinstalls it.