S K
12/23/2024, 3:56 PMloke
12/23/2024, 5:11 PMS K
12/24/2024, 4:28 AMclass BluetoothServiceIOSNew : BluetoothService {
    // Central and Peripheral Managers
    private val centralManager: CBCentralManager = CBCentralManager()
    private var peripheralManager: CBPeripheralManager? = null
    private var connectedPeripheral: CBPeripheral? = null
    private var peripheral: CBPeripheral? = null
    // Define properties for the callbacks
    private var connectSuccessCallback: (() -> Unit)? = null
    private var connectFailureCallback: ((Throwable) -> Unit)? = null
    private var disconnectCallback: (() -> Unit)? = null
    private var disconnectFailureCallback: ((Throwable) -> Unit)? = null
    init {
        println("Kotlin::: init execution")
        centralManager.delegate = object : NSObject(), CBCentralManagerDelegateProtocol {
            // Called when Bluetooth state changes (powered on/off)
            //This method is called whenever the Bluetooth state of the CBCentralManager changes (e.g., powered on, powered off, unsupported, etc.).
            override fun centralManagerDidUpdateState(manager: CBCentralManager) {
                println("Kotlin::: centralManagerDidUpdateState")
                when (manager.state) {
                    CBCentralManagerStatePoweredOn -> {
                        println("Kotlin::: Bluetooth is powered on.")
                    }
                    CBCentralManagerStatePoweredOff -> {
                        println("Kotlin::: Bluetooth is powered off.")
                    }
                    else -> {
                        println("Kotlin::: Bluetooth is unavailable or turned off.")
                    }
                }
            }
            // Called when a peripheral is discovered during scanning
            //This method is called when a peripheral device is discovered during a scan. You can use it to filter peripherals and initiate a connection.
            override fun centralManager(central: CBCentralManager, didDiscoverPeripheral: CBPeripheral, advertisementData: Map<Any?, *>, RSSI: NSNumber) {
                println("Kotlin:: Discovered peripheral: ${didDiscoverPeripheral.name}")
//                if (didDiscoverPeripheral.name == "TargetDeviceName") {
                    centralManager.connectPeripheral(didDiscoverPeripheral, options = null)
                    connectedPeripheral = didDiscoverPeripheral
                    println("Kotlin:: Connecting to peripheral: ${didDiscoverPeripheral.name}")
//                }
            }
            // Called when a peripheral has been successfully connected
            //This method is called when a peripheral is successfully connected. You can use this to trigger actions upon a successful connection.
            override fun centralManager(manager: CBCentralManager, didConnectPeripheral: CBPeripheral) {
                println("Kotlin:: Successfully connected to peripheral: ${didConnectPeripheral.name}")
                connectedPeripheral = didConnectPeripheral
                connectSuccessCallback?.invoke()  // Invoke the success callback
            }
            // Called when a connection to a peripheral fails
            //This method is called when a connection attempt to a peripheral fails. It provides an error so you can handle the failure.
            @ObjCSignatureOverride
            override fun centralManager(manager: CBCentralManager, didFailToConnectPeripheral: CBPeripheral, error: NSError?) {
                println("Kotlin:: Failed to connect to peripheral: ${didFailToConnectPeripheral.name}")
                connectFailureCallback?.invoke((error ?: Exception("Unknown connection failure")) as Throwable) // Invoke failure callback
            }
            // Called when a peripheral is disconnected
            //This method is called when a peripheral is disconnected, either intentionally or due to an error.
            @ObjCSignatureOverride
            override fun centralManager(manager: CBCentralManager, didDisconnectPeripheral: CBPeripheral, error: NSError?) {
                println("Kotlin:: Disconnected from peripheral: ${didDisconnectPeripheral.name}")
                connectedPeripheral = null
                if (error != null) {
                    disconnectFailureCallback?.invoke(error.toThrowable())  // If there's an error on disconnect, invoke failure callback
                } else {
                    disconnectCallback?.invoke()  // Otherwise, invoke success callback
                }
            }
        }
    }
    fun NSError.toThrowable(): Throwable {
        return Throwable("Kotlin::: NSError code: $code, description: ${localizedDescription}")
    }
    override fun isBluetoothPoweredOn(): Boolean {
        return when (centralManager.state) {
            CBCentralManagerStatePoweredOn -> true
            else -> false
        }
    }
    override suspend fun startAdvertising(name: String, serviceUUID: String) {
        println("Kotlin::: Starting advertising with name: $name and service UUID: $serviceUUID")
        if (peripheralManager == null) {
            println("Kotlin::: Null execution")
            // Initialize the peripheral manager with the correct delegate
            peripheralManager = CBPeripheralManager()
            // Set the delegate after initialization
            peripheralManager?.delegate = BluetoothPeripheralManagerDelegateNew(
                onAdvertisingStarted = {
                    println("Kotlin::: Advertising started successfully!")
                },
                onAdvertisingFailed = { error ->
                    println("Kotlin::: Advertising failed with error: ${error.localizedDescription}")
                }
            )
        }
        // Wait until the peripheral manager is powered on
        while (peripheralManager?.state != CBPeripheralManagerStatePoweredOn) {
            delay(500) // Check every 500ms
        }
        val advertisementData: Map<Any?, Any?> = mapOf(
            CBAdvertisementDataLocalNameKey to name,
            CBAdvertisementDataServiceUUIDsKey to listOf(CBUUID.UUIDWithString(serviceUUID))
        )
//        peripheralManager?.startAdvertising(advertisementData)
        peripheralManager?.startAdvertising(null)
        println("Kotlin::: Started advertising with name: $name and service UUID: $serviceUUID")
    }
    override suspend fun stopAdvertising() {
        peripheralManager?.stopAdvertising()
        println("Kotlin:: Stopped advertising.")
    }
    override suspend fun startDiscovery(serviceUUID: String) {
        println("Kotlin:: Starting scan for peripherals offering service UUID: $serviceUUID")
        withContext(Dispatchers.Main) {
            val serviceUUIDs = listOf(CBUUID.UUIDWithString(serviceUUID))
            centralManager.scanForPeripheralsWithServices(serviceUUIDs, options = null)
            println("Kotlin:: Started scanning for peripherals offering service UUID: $serviceUUID")
        }
    }
    override suspend fun stopDiscovery() {
        withContext(Dispatchers.Main) {
            centralManager.stopScan()
            println("Kotlin:: Stopped scanning for peripherals.")
        }
    }
    @Throws(Exception::class)
    override suspend fun connect(deviceId: String, onSuccess: () -> Unit, onFailure: (Throwable) -> Unit) {
        println("Kotlin:: connect-1")
        if (deviceId.isNullOrEmpty()) {
            onFailure(IllegalArgumentException("Device ID cannot be null or empty"))
            return
        }
        println("Kotlin:: connect-2")
        val nsUUID = NSUUID(deviceId)
        println("Kotlin:: connect Created NSUUID: $nsUUID")
        // Retrieve peripheral by UUID
        val peripheralToConnect = centralManager.retrievePeripheralsWithIdentifiers(listOf(nsUUID))
        if (!peripheralToConnect.isNullOrEmpty()) {
            peripheral = peripheralToConnect.firstOrNull() as? CBPeripheral
            println("Kotlin:: connect-5 :: $peripheral")
            if (peripheral != null) {
                centralManager.connectPeripheral(peripheral!!, options = null)
                println("Kotlin:: Attempting to connect to peripheral: $deviceId")
                // Store the callback functions for success and failure
                connectSuccessCallback = onSuccess
                connectFailureCallback = onFailure
            } else {
                onFailure(IllegalArgumentException("Peripheral not valid"))
            }
        } else {
            onFailure(IllegalArgumentException("Peripheral not found"))
        }
    }
    // Implement disconnect with success and failure callbacks
    override suspend fun disconnect(onSuccess: () -> Unit, onFailure: (Throwable) -> Unit) {
        println("Kotlin:: disconnect-1")
        if (connectedPeripheral != null) {
            centralManager.cancelPeripheralConnection(connectedPeripheral!!)
            println("Kotlin:: Disconnecting from peripheral: ${connectedPeripheral?.name}")
            // Store the callback for disconnection success
            disconnectCallback = onSuccess
            disconnectFailureCallback = onFailure
        } else {
            println("Kotlin:: No peripheral is connected.")
            onFailure(IllegalStateException("No peripheral is connected"))
        }
    }
}
// Bluetooth Peripheral Manager Delegate
class BluetoothPeripheralManagerDelegateNew(
    private val onAdvertisingStarted: () -> Unit,
    private val onAdvertisingFailed: (NSError) -> Unit
) : NSObject(), CBPeripheralManagerDelegateProtocol {
    // This callback will be triggered when advertising starts
    override fun peripheralManagerDidStartAdvertising(peripheral: CBPeripheralManager, error: NSError?) {
        if (error == null) {
            println("Kotlin::: oAdvertising-Started")
            onAdvertisingStarted()
        } else {
            println("Kotlin::: oAdvertising-Failed")
            onAdvertisingFailed(error)
        }
    }
    // This callback is triggered when the peripheral manager's state changes (e.g., powered on/off)
    override fun peripheralManagerDidUpdateState(peripheral: CBPeripheralManager) {
        when (peripheral.state) {
            CBPeripheralManagerStatePoweredOn -> {
                println("Kotlin::: Peripheral Manager powered on.")
            }
            else -> {
                println("Kotlin::: Peripheral Manager not ready or powered off.")
            }
        }
    }
}S K
12/24/2024, 4:28 AMinterface BluetoothService {
    fun isBluetoothPoweredOn(): Boolean
    suspend fun startAdvertising(name: String, serviceUUID: String)
    suspend fun stopAdvertising()
    suspend fun startDiscovery(serviceUUID: String)
    suspend fun stopDiscovery()
 /*   @Throws(Exception::class)
    suspend fun connect(deviceId: String)
    suspend fun disconnect()*/
    @Throws(Exception::class)
    suspend fun connect(deviceId: String, onSuccess: () -> Unit, onFailure: (Throwable) -> Unit)
    suspend fun disconnect(onSuccess: () -> Unit, onFailure: (Throwable) -> Unit)
}Adrijan Rogan
12/24/2024, 7:22 AMS K
12/24/2024, 9:52 AMAdrijan Rogan
12/24/2024, 10:09 AMS K
12/24/2024, 10:18 AMAdrijan Rogan
12/24/2024, 10:31 AMS K
12/24/2024, 11:40 AM