Mobile Development 9 min read

Swift–Kotlin Interoperability in Compose for iOS

This article demonstrates how to bridge Swift and Kotlin in a Compose‑Multiplatform iOS app by using Swift view modifiers to detect orientation changes and call Kotlin functions, while exposing Kotlin callbacks that Swift registers to change device orientation, enabling seamless two‑way platform‑specific logic integration.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Swift–Kotlin Interoperability in Compose for iOS

Preface

Similar to Android's Compose, iOS Compose also supports nesting Compose UI with SwiftUI or UIKit. However, unlike Android which uses Kotlin, iOS development uses Swift or Objective‑C. Some platform‑specific logic must be implemented in native iOS code and called from Kotlin.

This article demonstrates, with a real project, how to achieve business‑logic interoperation between Swift and Kotlin in Compose for iOS.

Swift Calls Kotlin

In the github.com/equationl/calculator-Compose-MultiPlatform project we need to listen for screen‑rotation events and switch the keyboard type accordingly. Because rotation listening is iOS‑specific, it must be implemented in Swift and then invoke Kotlin code.

First, add a view modifier in ContentView.swift that subscribes to UIDevice.orientationDidChangeNotification :

struct DetectOrientation: ViewModifier { 
    func body(content: Content) -> some View { 
        content 
            .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in 
                // trigger screen orientation change event 
            } 
    } 
} 

extension View { 
    func detectOrientation() -> some View { 
        modifier(DetectOrientation()) 
    } 
}

Apply the modifier to the Compose view:

struct ContentView: View { 
    var body: some View { 
        VStack { 
            ComposeView() 
                .ignoresSafeArea(.keyboard) // Compose has its own keyboard handler 
        }.detectOrientation() 
    } 
}

When the device orientation changes, the Swift code calls the Kotlin function Main_iosKt.onScreenChange(orientation: Int) :

struct DetectOrientation: ViewModifier { 
    func body(content: Content) -> some View { 
        content 
            .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in 
                if UIDevice.current.orientation.isLandscape { 
                    Main_iosKt.onScreenChange(orientation: 1) 
                } else { 
                    Main_iosKt.onScreenChange(orientation: 0) 
                } 
            } 
    } 
}

The corresponding Kotlin function resides in shared/iosMain/main.ios.kt :

/** 
 * @param orientation 0 portrait, 1 landscape 
 */ 
fun onScreenChange(orientation: Int) { 
    if (orientation == 0) { 
        homeChannel?.trySend( 
            HomeAction.OnScreenOrientationChange(changeToType = KeyboardTypeStandard) 
        ) 
    } else { 
        homeChannel?.trySend( 
            HomeAction.OnScreenOrientationChange(changeToType = KeyboardTypeProgrammer) 
        ) 
    } 
}

Kotlin Calls Swift

Most business logic can be written in Kotlin, but some platform‑specific APIs (e.g., Bluetooth, screen rotation) require Swift. Kotlin Multiplatform already wraps many iOS APIs, such as CoreBluetooth:

import platform.CoreBluetooth.CBCentralManager 
import platform.CoreBluetooth.CBManagerAuthorizationAllowedAlways 
import platform.CoreBluetooth.CBManagerAuthorizationDenied 
import platform.CoreBluetooth.CBManagerAuthorizationNotDetermined 
import platform.CoreBluetooth.CBManagerAuthorizationRestricted 

internal class BluetoothPermissionDelegate : PermissionDelegate { 
    override fun getPermissionState(): PermissionState { 
        return when (CBCentralManager.authorization) { 
            CBManagerAuthorizationNotDetermined -> { /* not granted */ } 
            CBManagerAuthorizationAllowedAlways, CBManagerAuthorizationRestricted -> { /* granted */ } 
            CBManagerAuthorizationDenied -> { /* denied */ } 
            else -> { /* other */ } 
        } 
    } 
    
    override suspend fun providePermission() { 
        CBCentralManager().authorization() 
    } 
    
    override fun openSettingPage() { 
        // open settings 
    } 
}

For functionality not wrapped (e.g., forcing screen orientation), we implement a Swift helper:

func changeOrientation(to orientation: UIInterfaceOrientation) { 
    if #available(iOS 16.0, *) { 
        let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene 
        if orientation.isPortrait { 
            windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait)) 
        } else { 
            windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .landscape)) 
        } 
    } else { 
        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation") 
    } 
}

To let Kotlin invoke this Swift function, we expose a callback from Kotlin that Swift can set:

var changeScreenOrientationFunc: ((to: Int) -> Unit)? = null 

fun changeScreenOrientation(callBack: (to: Int) -> Unit) { 
    changeScreenOrientationFunc = callBack 
}

Swift registers the callback during initialization:

Main_iosKt.changeScreenOrientation { kotlinInt -> 
    if (kotlinInt == 0) { 
        changeOrientation(to: UIInterfaceOrientation.portrait) 
    } else { 
        changeOrientation(to: UIInterfaceOrientation.landscapeLeft) 
    } 
}

Summary

The article shows how to bridge Swift and Kotlin in a Compose‑Multiplatform iOS project: Swift listens to device rotation, forwards the event to Kotlin, Kotlin updates the UI state, and Kotlin can also request Swift to change the device orientation via a callback mechanism. Full source code is available at github.com/equationl/calculator-Compose-MultiPlatform .

iOSKotlinSwiftinteroperabilityCompose Multiplatform
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.