Swift SDK for building chat-enabled, AI-ready, super-app style iOS applications using the Ethora platform.
The SDK provides a ready-made communication layer based on XMPP messaging, WebSockets, and Ethora APIs β along with UI components for chat screens, message bubbles, avatars, and typical in-app messaging behaviors.
- βοΈ XMPP messaging
- βοΈ WebSockets for presence + typing indicators
- βοΈ Message send/receive
- βοΈ User presence + "now typing"
- βοΈ Basic message attachments (in progress)
- βοΈ Authentication & session management
- βοΈ API client for Ethora backend
- βοΈ User profiles, avatars, chat room logic
- βοΈ Standard chat UI screen
- βοΈ Message bubbles
- βοΈ User avatars
- βοΈ Typing indicator
The SDK is actively evolving. Current beta limitations:
- β³ Logout mechanism
- β³ PDF preview (currently blank pages)
- iOS 15.0+ or macOS 12.0+
- Swift 5.9+
- Xcode 14.0+
-
Open your Xcode project
-
Add Package Dependency:
- Go to File β Add Package Dependencies...
- Enter the repository URL:
https://github.com/dappros/ethora-sdk-swift - Click Add Package
-
Select Package Products:
- β Check XMPPChatCore (required)
- β Check XMPPChatUI (required for UI components)
- Make sure they're added to your app target
- Click Add Package
If you're using a Swift Package Manager project, add the dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/dappros/ethora-sdk-swift", branch: "main")
]Then add the products to your target:
.target(
name: "YourTarget",
dependencies: [
.product(name: "XMPPChatCore", package: "ethora-sdk-swift"),
.product(name: "XMPPChatUI", package: "ethora-sdk-swift")
]
)In your Swift files, import the modules you need:
import XMPPChatCore // Core functionality (XMPP, API, models)
import XMPPChatUI // UI components (chat views, room list)First, configure your XMPP connection settings. You can use the default settings or customize them:
import XMPPChatCore
// Option 1: Use default settings (recommended for development)
let settings = AppConfig.defaultXMPPSettings
// Option 2: Customize XMPP settings
let customSettings = XMPPSettings(
devServer: "wss://xmpp.ethoradev.com:5443/ws",
host: "xmpp.ethoradev.com",
conference: "conference.xmpp.ethoradev.com",
xmppPingOnSendEnabled: true
)Authenticate with the Ethora API using email and password:
import XMPPChatCore
Task {
do {
// Login with email and password
let loginResponse = try await AuthAPI.loginWithEmail(
email: "yukiraze9@gmail.com",
password: "Qwerty123"
)
// Save user data to UserStore (this also caches the session)
await UserStore.shared.setUser(from: loginResponse)
print("β
Login successful!")
print("User ID: \(loginResponse.user.id)")
print("Token saved: \(UserStore.shared.token != nil)")
} catch {
print("β Login failed: \(error)")
}
}After successful authentication, initialize the XMPP client:
import XMPPChatCore
// Get user from UserStore
guard let user = UserStore.shared.currentUser else {
print("β No user found. Please login first.")
return
}
// Extract XMPP credentials
let xmppUsername = user.xmppUsername ?? user.email ?? ""
let xmppPassword = user.xmppPassword ?? ""
guard !xmppUsername.isEmpty, !xmppPassword.isEmpty else {
print("β Missing XMPP credentials")
return
}
// Create XMPP client
let settings = AppConfig.defaultXMPPSettings
let xmppClient = XMPPClient(
username: xmppUsername,
password: xmppPassword,
settings: settings
)
// Set delegate to receive connection events and messages
xmppClient.delegate = self
// The client will automatically connect when initializedImplement the delegate to handle connection events and incoming messages:
import XMPPChatCore
extension YourViewController: XMPPClientDelegate {
func xmppClientDidConnect(_ client: XMPPClient) {
print("β
XMPP Client connected")
// Update UI, load rooms, etc.
}
func xmppClientDidDisconnect(_ client: XMPPClient) {
print("β XMPP Client disconnected")
// Handle disconnection
}
func xmppClient(_ client: XMPPClient, didReceiveMessage message: Message) {
print("π¨ Received message: \(message.body)")
// Update UI with new message
}
func xmppClient(_ client: XMPPClient, didChangeStatus status: ConnectionStatus) {
print("π Connection status: \(status.rawValue)")
// Update connection status in UI
}
func xmppClient(_ client: XMPPClient, didReceiveStanza stanza: XMPPStanza) {
// Handle other XMPP stanzas if needed
}
}The SDK provides ready-to-use SwiftUI components:
import SwiftUI
import XMPPChatCore
import XMPPChatUI
struct ChatView: View {
let xmppClient: XMPPClient
var body: some View {
// Room List View - shows all chat rooms
RoomListView(
viewModel: RoomListViewModel(
client: xmppClient,
currentUserId: UserStore.shared.currentUser?.id ?? ""
)
)
}
}
// Or use ChatRoomView for a specific room
struct SingleChatView: View {
let roomId: String
let xmppClient: XMPPClient
var body: some View {
ChatRoomView(
viewModel: ChatRoomViewModel(
roomId: roomId,
client: xmppClient
)
)
}
}import SwiftUI
import XMPPChatCore
import XMPPChatUI
@main
struct MyApp: App {
@StateObject private var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(appState)
}
}
}
@MainActor
class AppState: ObservableObject {
@Published var xmppClient: XMPPClient?
@Published var isAuthenticated: Bool = false
func login(email: String, password: String) async {
do {
// Step 1: Authenticate
let loginResponse = try await AuthAPI.loginWithEmail(
email: email,
password: password
)
// Step 2: Save user
await UserStore.shared.setUser(from: loginResponse)
// Step 3: Initialize XMPP
guard let user = UserStore.shared.currentUser else { return }
let xmppClient = XMPPClient(
username: user.xmppUsername ?? user.email ?? "",
password: user.xmppPassword ?? "",
settings: AppConfig.defaultXMPPSettings
)
xmppClient.delegate = self
self.xmppClient = xmppClient
self.isAuthenticated = true
} catch {
print("Login failed: \(error)")
}
}
}
extension AppState: XMPPClientDelegate {
func xmppClientDidConnect(_ client: XMPPClient) {
print("β
Connected")
}
func xmppClient(_ client: XMPPClient, didReceiveMessage message: Message) {
print("π¨ \(message.body)")
}
// ... other delegate methods
}For a complete working example, see the Examples/ChatAppExample folder in this repository.
The SDK is organized into two main modules:
Core functionality including:
- Networking:
AuthAPI,RoomsAPIfor REST API calls - XMPP Client:
XMPPClientfor real-time messaging - Models:
User,Message,Room,XMPPSettings - Persistence:
UserStore,MessageCachefor local storage - Configuration:
AppConfigfor default settings
SwiftUI components including:
- RoomListView: List of all chat rooms
- ChatRoomView: Individual chat room interface
- BannerSettingsView: Settings management
UserStore: Manages user authentication state and caching
// Check if user is authenticated
if UserStore.shared.isAuthenticated {
// User is logged in
}
// Get current user
let user = UserStore.shared.currentUser
// Get auth token
let token = UserStore.shared.tokenXMPPClient: Handles XMPP connection and messaging
let client = XMPPClient(
username: "user@example.com",
password: "password",
settings: XMPPSettings(...)
)
client.delegate = selfAppConfig: Provides default configuration
// Default XMPP settings
let settings = AppConfig.defaultXMPPSettings
// Default API base URL
let baseURL = AppConfig.defaultBaseURL
// App token (can be overridden via ETHORA_APP_TOKEN env var)
let token = AppConfig.appTokenYou can override default configuration using environment variables:
ETHORA_APP_TOKEN: Override the default app tokenETHORA_DEV_USER_TOKEN: Override the default dev user token
let settings = XMPPSettings(
devServer: "wss://your-xmpp-server.com:5443/ws",
host: "your-xmpp-server.com",
conference: "conference.your-xmpp-server.com",
xmppPingOnSendEnabled: true // Optional: enable ping on send
)The SDK uses AppConfig.defaultBaseURL by default (https://api.ethoradev.com/v1). To use a different API endpoint, you'll need to modify the API classes or use dependency injection.
- See
Examples/ChatAppExamplefor a complete working example - Check
INSTALLATION.mdfor detailed installation steps - Review source code in
Sources/XMPPChatCoreandSources/XMPPChatUI
We welcome:
- PRs
- Issues
- Feature requests
- Bug reports
MIT License.
"No user found" error:
- Make sure you've called
UserStore.shared.setUser(from: loginResponse)after successful login - Verify the login response contains all required user data
XMPP connection fails:
- Check your XMPP credentials (
xmppUsernameandxmppPassword) - Verify XMPP server settings are correct
- Ensure network connectivity
401 Authentication errors:
- Verify your app token is correct
- Check that the user token is being sent in API requests
- Ensure
UserStore.shared.tokenis set after login
Messages not appearing:
- Verify XMPP client is connected (
xmppClientDidConnectwas called) - Check that you're listening to the correct room JID
- Ensure delegate methods are properly implemented
Contact: https://ethora.com/contact/