From 7a69d5a76995f5574aabc4fe4e3eadbf07e86402 Mon Sep 17 00:00:00 2001 From: Travis Wyatt Date: Wed, 18 Sep 2024 13:23:12 -0700 Subject: [PATCH] Make `isSupported` always `true` on Apple --- .../appleMain/kotlin/bluetooth/IsSupported.kt | 52 +------------------ kable-core/src/commonMain/kotlin/Bluetooth.kt | 8 ++- 2 files changed, 7 insertions(+), 53 deletions(-) diff --git a/kable-core/src/appleMain/kotlin/bluetooth/IsSupported.kt b/kable-core/src/appleMain/kotlin/bluetooth/IsSupported.kt index 650104f06..0d1ce3cab 100644 --- a/kable-core/src/appleMain/kotlin/bluetooth/IsSupported.kt +++ b/kable-core/src/appleMain/kotlin/bluetooth/IsSupported.kt @@ -1,53 +1,3 @@ package com.juul.kable.bluetooth -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.onFailure -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import platform.CoreBluetooth.CBCentralManager -import platform.CoreBluetooth.CBCentralManagerDelegateProtocol -import platform.CoreBluetooth.CBCentralManagerOptionShowPowerAlertKey -import platform.CoreBluetooth.CBManagerState -import platform.CoreBluetooth.CBManagerStateResetting -import platform.CoreBluetooth.CBManagerStateUnknown -import platform.CoreBluetooth.CBManagerStateUnsupported -import platform.darwin.NSObject - -// Prevent triggering bluetooth dialog (note that permission dialog will still appear). -// https://chrismaddern.com/determine-whether-bluetooth-is-enabled-on-ios-passively/ -// https://stackoverflow.com/a/58600900 -private val options = mapOf(CBCentralManagerOptionShowPowerAlertKey to false) - -private var cachedState: CBManagerState? = null -private val mutex = Mutex() - -internal actual suspend fun isSupported() = mutex.withLock { - cachedState ?: awaitState().also { cachedState = it } -} != CBManagerStateUnsupported - -// Need to hold strong-reference to CBCentralManager and its delegate while in use. -private var managerRef: NSObject? = null -private var delegateRef: NSObject? = null - -private suspend fun awaitState() = callbackFlow { - val delegate = object : NSObject(), CBCentralManagerDelegateProtocol { - override fun centralManagerDidUpdateState(central: CBCentralManager) { - trySend(central.state).onFailure { - // Silently ignore. - } - } - } - - delegateRef = delegate - managerRef = CBCentralManager(delegate, null, options) - - awaitClose { - managerRef = null - delegateRef = null - } -}.first { it.isDetermined } - -private val CBManagerState.isDetermined: Boolean - get() = this != CBManagerStateUnknown && this != CBManagerStateResetting +internal actual suspend fun isSupported() = true diff --git a/kable-core/src/commonMain/kotlin/Bluetooth.kt b/kable-core/src/commonMain/kotlin/Bluetooth.kt index e13946842..af7c5afe7 100644 --- a/kable-core/src/commonMain/kotlin/Bluetooth.kt +++ b/kable-core/src/commonMain/kotlin/Bluetooth.kt @@ -35,16 +35,20 @@ public object Bluetooth { public data class Unavailable(val reason: Reason?) : Availability() } + public val availability: Flow = bluetoothAvailability + /** * Checks if Bluetooth Low Energy is supported on the system. Being supported (a return of * `true`) does not necessarily mean that bluetooth operations will work. The radio could be off * or permissions may be denied. * + * Due to Core Bluetooth limitations (unavoidable dialog upon checking if supported), this + * function **always** returns `true` on Apple (even if Bluetooth is not supported). + * * This function is idempotent. */ + @ExperimentalApi // Due to the inability to query Bluetooth support w/o showing a dialog on Apple, this function may be removed. public suspend fun isSupported(): Boolean = isBluetoothSupported() - - public val availability: Flow = bluetoothAvailability } internal expect val bluetoothAvailability: Flow