iOS SDK
UIKit integration
Host AppNorth's SwiftUI views in UIHostingController. Keep your existing app delegate, navigation, and dependency injection; configure and retain the client once per session.
Present community
The community view already supplies a navigation stack. Present its hosting controller directly rather than adding another navigation container.
import UIKit
import SwiftUI
import AppNorth
@MainActor
func presentCommunity(from presenter: UIViewController, client: AppNorthClient) {
let controller = UIHostingController(rootView: AppNorthView(client: client))
controller.modalPresentationStyle = .pageSheet
presenter.present(controller, animated: true)
}The default sheet can be dismissed by swiping. If your app requires an explicit close button or a full-screen presentation, add a host-owned SwiftUI wrapper with a dismissal control.
Present support with a close button
The chat view is conversation content, so you can put it inside your UIKit navigation controller:
import UIKit
import SwiftUI
import AppNorth
@MainActor
final class SupportViewController: UIHostingController<AppNorthChatView> {
init(client: AppNorthClient) {
super.init(rootView: AppNorthChatView(client: client))
}
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError("Use init(client:)") }
override func viewDidLoad() {
super.viewDidLoad()
title = "Support"
navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .done,
target: self,
action: #selector(closeSupport)
)
}
@objc private func closeSupport() {
dismiss(animated: true)
}
}
@MainActor
func presentSupport(from presenter: UIViewController, client: AppNorthClient) {
let navigation = UINavigationController(
rootViewController: SupportViewController(client: client)
)
presenter.present(navigation, animated: true)
}The built-in chat view manages visible/foreground polling. If you use AppNorthChatModel directly, you own its start/stop lifecycle. For an embedded hosting controller, use UIKit's normal addChild, view constraints, and didMove(toParent:) containment lifecycle.
Keep identity and appearance aligned
Install the signed credential before presenting identified screens. Dismiss them before logout or account changes, clear the credential and account state, and create new controllers for the next session.
Pass copy, theme, and paywalls to the underlying SwiftUI view when needed. In a multiwindow app, supply the active window's presenter to the RevenueCat helper so a card opens above the correct chat.
Verify
Present and dismiss both screens from the existing UIKit app.
Open the keyboard, rotate the device, and test large text without clipping the composer.
Background and foreground support, then dismiss it; verify polling stops when hidden.
Switch accounts and confirm the newly presented controller has no previous account content.