Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 27, 2025

CBCentralManager.state initializes asynchronously as .unknown and takes ~500ms to update. The previous implementation checked the state immediately without waiting, causing isBluetoothEnabled() to always return false on first call.

Changes

Implement CBCentralManagerDelegate

  • Added CBCentralManagerDelegate protocol conformance
  • Set delegate when initializing CBCentralManager(delegate: self, queue: nil)
  • Cache state in centralManagerState property
  • Implement centralManagerDidUpdateState(_:) to update cached state and resolve pending promises

Update isBluetoothEnabled logic

  • Return immediately if state is already known (not .unknown)
  • Queue callback in stateUpdateCallbacks array if state is .unknown
  • Trigger lazy initialization to start async state update
  • Resolve with cached state on subsequent calls (no performance impact)

Memory management

  • Use weak self capture in callbacks to avoid retain cycles
  • Resolve with false if self is deallocated before state updates

Example

// Before: Always false on first call
RNBluetoothClassic.isBluetoothEnabled()
  .then(r => console.log(r))  // false (even if BT is on)

// After: Waits for actual state, subsequent calls instant
RNBluetoothClassic.isBluetoothEnabled()
  .then(r => console.log(r))  // true (accurate, waits ~100ms)
  .then(() => RNBluetoothClassic.isBluetoothEnabled())
  .then(r => console.log(r))  // true (instant, cached)
Original prompt

This section details on the original issue you should resolve

<issue_title>IsBluetoothEnabled always false on first call</issue_title>
<issue_description>Mobile Device Environment

  • Device: iPad Mini (5th gen)
  • OS: iPadOS 18.5

Application Environment
Provide information about your development environment:

  • React Native version: 0.76.9
  • RN Bluetooth Classic version: 1.73.0-rc.12

Describe the bug

  1. Calling RNBluetoothClass.isBluetoothEnabled() always returns false on the first call, regardless of the actual bluetooth state. Calling the function twice in a row, via isBluetoothEnabled.finally(() => isBluetoothEnabled()) also always returns false on the first call. The only way i am able to actually get the proper bluetooth state, is by putting a short delay (~500ms) in between the function invocations, and only taking the last result.

To Reproduce
Steps to reproduce the behavior:

  1. Create a basic app with the following code:
export const App = () => {
  useEffect(() => {
    RNBluetoothClassic.isBluetoothEnabled()
      .then((r) => console.log('bluetooth enabled: ', r))
      .then(() => new Promise((res) => setTimeout(res, 1000)))
      .then(() => RNBluetoothClassic.isBluetoothEnabled())
      .then((r) => console.log('bluetooth enabled now?: ', r))
  }, [])
  return <Text>My App</Text>
}
  1. observe the following logs in the developer console:
bluetooth enabled: false
bluetooth enabled now?: true

Expected behavior
isBluetoothEnabled returns the proper response regardless of invocation timing.

</issue_description>

<agent_instructions>Need to determine if there is any documentation surrounding the call to the Apple CBCentralManagerState that would take a few moments to get the correct value. Or could there be an issue with the bridge handling resolution of promises between React JS and Native module?</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@kenjdavidson This is really just a call through to ``` /** * Check the Core Bluetooth Central Manager for status */ private func checkBluetoothAdapter() -> Bool { var enabled = false
    if #available(iOS 10.0, *) {
        enabled = (cbCentral.state == CBManagerState.poweredOn)
    } else {
        enabled = (cbCentral.state.rawValue == CBCentralManagerState.poweredOn.rawValue)
    }
    
    return enabled
}

If something in the CBCentralManagerState takes a while to sort itself out.  Feel free to debug it and open a PR if you see what's up with it.

I'm pretty much hands off at this point, just accepting PRs and releasing, sometimes helping look through code and docs when time permits.</body></comment_new>
</comments>


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Fix isBluetoothEnabled always returning false on first call Fix isBluetoothEnabled returning false on first call due to CBCentralManager async initialization Oct 27, 2025
Copilot AI requested a review from kenjdavidson October 27, 2025 20:41
Copilot finished work on behalf of kenjdavidson October 27, 2025 20:41
@kenjdavidson kenjdavidson marked this pull request as ready for review October 28, 2025 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IsBluetoothEnabled always false on first call

2 participants