How to Use an SDK Built for UIKit in Your SwiftUI App

Matheus C.
Matheus C.
Published November 11, 2020 Updated March 15, 2022

SwiftUI becomes more popular as it gets more capable with each iOS release. However, it may take some time until it's a better option than UIKit to build complex user experiences such as chat and video calls. That doesn't mean you need to stick with UIKit until all the SDKs you use support SwiftUI. In this tutorial, you'll learn how easy it is to use SDKs built for UIKit in your SwiftUI app.

Note: This article's content is outdated.
In the meantime, check out our SwiftUI SDK, or get started with our new SwiftUI chat app tutorial.

Image shows a chat screen running inside a SwiftUI app

In this tutorial, I'll use Stream Chat's iOS SDK inside a SwiftUI app. It provides a fully-featured chat user interface in the form of a UIViewController subclass. If you're using a different SDK, the process may be similar if it provides the UI components in the form of UIKit views or view controllers.

Configuring the SDK

Typically, in UIKit, we would put any SDK initialization code inside the AppDelegate's method applicationDidFinishLaunching(_:).

If you chose to go full SwiftUI and used the SwiftUI App lifecycle, which doesn't contain an AppDelegate, the best place to configure the SDK is inside the App struct's initializer:

import SwiftUI
import StreamChatClient

@main
struct SwiftUIChatApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
    
    init() {
        Client.configureShared(.init(apiKey: "[api_key]", logOptions: .info))
        
        let user = User(id: "[user_id]")
        Client.shared.set(user: user, token: .development)
    }
}

Wrapping a UIViewController in SwiftUI

To display the ChatViewController provided by the Stream Chat SDK, we need to wrap it in a SwiftUI view struct. To do this, create a struct that conforms to the protocol UIViewControllerRepresentable and inside the makeUIViewController function, instantiate and configure the view controller as you would in a UIKit app. Additionally, you can add properties to the SwiftUI view, as I did below with channelType and channelId.

import SwiftUI
import StreamChat
import StreamChatCore
import StreamChatClient

struct ChatView: UIViewControllerRepresentable {
    let channelType: ChannelType
    let channelId: String
    
    typealias UIViewControllerType = ChatViewController
    
    func makeUIViewController(context: Context) -> ChatViewController {
        let chatViewController = ChatViewController()
        
        let channel = Client.shared.channel(type: channelType, id: channelId)
        let presenter = ChannelPresenter(channel: channel)
        
        chatViewController.presenter = presenter
        
        return chatViewController
    }
    
    func updateUIViewController(_ uiViewController: ChatViewController, context: Context) { }
}

Displaying the UIViewController

Now, you can use the SwiftUI view you created as you would any other SwiftUI view. In this case, I added it as the root view in my app's ContentView. If you added any properties to your wrapper, you need to pass them now.

import SwiftUI

struct ContentView: View {
    var body: some View {
        ChatView(channelType: .messaging, channelId: "general")
            .ignoresSafeArea()
    }
}

Wrapping a UIView in SwiftUI

In some cases, you may want to use a single UIView. The process is similar to wrapping a UIViewController. To do it, create a struct that conforms to UIViewRepresentable and inside the makeUIView function, instantiate and configure the view as you would in a UIKit app. In this case, I'm wrapping Stream Chat's AvatarView. I also added the name property to make it customize it inside the SwiftUI view hierarchy.

import SwiftUI
import StreamChat

struct AvatarView: UIViewRepresentable {
    @Binding var name: String

    func makeUIView(context: Context) -> StreamChat.AvatarView {
        let avatarView = StreamChat.AvatarView(style: .init())
        
        avatarView.update(withName: name)
        
        return avatarView
    }

    func updateUIView(_ uiView: StreamChat.AvatarView, context: Context) {
        uiView.update(withName: name)
    }
}

Displaying the UIView

Displaying the wrapped UIView is also similar to displaying the wrapped UIViewController. Just reference it as you would any other SwiftUI view. If you also added properties, make sure to fill them out.

import SwiftUI

struct ContentView: View {
    var body: some View {
        AvatarView(name: "Alice")
    }
}

Next Steps with UIKit on SwiftUI

Congratulations! You now have the entire library of SDKs built for UIKit at your SwiftUI app's disposal. If you want to check out two great examples of SDKs built for UIKit that you can use in your SwiftUI apps, see Stream Chat's iOS SDK and Stream Video & Audio. Additionally, read more about the iOS chat SDK.

Integrating Video With Your App?
We've built a Video and Audio solution just for you. Check out our APIs and SDKs.
Learn more ->