This guide walks you through adding DittoChat to an iOS or Android app from scratch. By the end you'll have a working peer-to-peer chat experience that syncs over Bluetooth, Wi-Fi, and the cloud.
Before you begin, make sure you have the following:
- A Ditto account — Sign up free at the Ditto Portal.
- An App ID and Online Playground Token — Create a new app in the portal and copy these credentials. You'll need them to initialize the SDK.
Open an existing iOS project or create a new one in Xcode (File → New → Project → App). Select SwiftUI as the interface and Swift as the language.
-
In Xcode, go to File → Add Package Dependencies…
-
In the search bar, paste the DittoChat repository URL:
https://github.com/getditto/DittoChat.git -
Under Dependency Rule, choose Up to Next Major Version and set it to the latest release (check the Releases page for the current version).
-
Click Add Package.
-
When prompted, select the DittoChat library product and add it to your app target.
Ditto uses Bluetooth LE and local networking for peer-to-peer sync. You need to declare usage descriptions so iOS can prompt the user for permission.
Add the following keys to your project's Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Uses Bluetooth to connect and sync with nearby devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Uses Bluetooth to connect and sync with nearby devices</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Uses WiFi to connect and sync with nearby devices</string>
<key>NSBonjourServices</key>
<array>
<string>_http-alt._tcp.</string>
</array>To keep chat syncing when your app is in the background:
- Select your project in the navigator, then your app target.
- Go to Signing & Capabilities → + Capability → Background Modes.
- Enable the following:
- Uses Bluetooth LE accessories
- Acts as a Bluetooth LE accessory
In your SwiftUI app entry point (e.g. App.swift or a root view), initialize a Ditto instance with your portal credentials and present the DittoChat view:
import SwiftUI
import DittoSwift
import DittoChat
@main
struct MyChatApp: App {
@StateObject private var dittoInstance = DittoManager()
var body: some Scene {
WindowGroup {
// Replace with the DittoChat view provided by the SDK.
// See the example app in the `apps/` directory for
// a complete working implementation.
ContentView()
.environmentObject(dittoInstance)
}
}
}
/// A simple singleton that owns the Ditto instance.
class DittoManager: ObservableObject {
let ditto: Ditto
init() {
ditto = Ditto(
identity: .onlinePlayground(
appID: "YOUR_APP_ID",
token: "YOUR_PLAYGROUND_TOKEN"
)
)
// Start syncing with nearby peers
do {
try ditto.startSync()
} catch {
print("Failed to start Ditto sync: \(error)")
}
}
}Important: Replace
YOUR_APP_IDandYOUR_PLAYGROUND_TOKENwith the credentials from your Ditto Portal app. Never commit these values to source control — use environment variables or a configuration file excluded from Git.
- Connect a physical iOS device (Bluetooth is not available in the Simulator).
- Select your device as the run destination and press ⌘R.
- Grant Bluetooth and local network permissions when prompted.
- Run the app on a second device to see peer-to-peer chat in action.
Note: The DittoChat Android SDK is under active development. The steps below show how to integrate the Ditto SDK in a Kotlin Android project and prepare for the DittoChat library. Check the Releases page and the
sdks/kotlin/directory for the latest availability.
Open an existing project or create a new one in Android Studio (File → New → New Project → Empty Activity). Choose Kotlin as the language and set the minimum SDK to API 23 (Android 6.0) or higher.
-
In your project-level
build.gradle(orsettings.gradle.kts), make sure Maven Central is included:// build.gradle (project-level) allprojects { repositories { mavenCentral() } } -
In your app-level
build.gradle, add the Ditto SDK:// build.gradle (app-level) dependencies { implementation "live.ditto:ditto:4.14.1" // Check docs.ditto.live for the latest version }
-
Sync your project: File → Sync Project with Gradle Files.
Once the DittoChat Android library is published, you will add it alongside the core Ditto SDK. Watch this repo for release announcements.
The Ditto SDK's AndroidManifest.xml automatically merges the required Bluetooth and network permissions into your app. However, you should be aware of what's being added:
<!-- These are automatically merged by the Ditto SDK -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"
tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"
tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />Android requires that certain permissions (like Bluetooth and location) be requested from the user at runtime. Use the DittoSyncPermissions helper provided by the SDK:
import live.ditto.transports.DittoSyncPermissions
// In your Activity's onCreate or a Composable's LaunchedEffect:
fun requestPermissions() {
val permissions = DittoSyncPermissions(this)
val missing = permissions.missingPermissions()
if (missing.isNotEmpty()) {
this.requestPermissions(missing, 0)
}
}Call this early in your app's lifecycle — before starting Ditto sync — so the user sees the permission prompts right away.
Create a singleton Application class (or use your existing one) to initialize Ditto at app startup:
import android.app.Application
import android.util.Log
import live.ditto.*
import live.ditto.android.DefaultAndroidDittoDependencies
class MyChatApplication : Application() {
lateinit var ditto: Ditto
override fun onCreate() {
super.onCreate()
try {
DittoLogger.minimumLogLevel = DittoLogLevel.DEBUG
val androidDependencies = DefaultAndroidDittoDependencies(applicationContext)
val identity = DittoIdentity.OnlinePlayground(
androidDependencies,
appId = "YOUR_APP_ID",
token = "YOUR_PLAYGROUND_TOKEN"
)
ditto = Ditto(androidDependencies, identity)
ditto.startSync()
} catch (e: DittoError) {
Log.e("DittoChat", "Failed to start Ditto: ${e.message}")
}
}
}Register the application class in your AndroidManifest.xml:
<application
android:name=".MyChatApplication"
... >Important: Replace
YOUR_APP_IDandYOUR_PLAYGROUND_TOKENwith your portal credentials. Store secrets securely — useBuildConfigfields or alocal.propertiesfile that is excluded from version control.
- Connect a physical Android device (Bluetooth is unavailable in the emulator).
- Run the app and grant all requested permissions.
- Deploy to a second device on the same network (or within Bluetooth range) to test peer-to-peer sync.
Once you have the app running on two or more devices:
- Make sure both devices have Bluetooth and Wi-Fi enabled.
- Both apps must be configured with the same App ID from the Ditto Portal.
- Send a message on one device — it should appear on the other within seconds.
- To test offline sync, enable Airplane Mode on both devices (but keep Bluetooth on). Messages will still sync directly over Bluetooth LE.
| Symptom | Possible Cause | Fix |
|---|---|---|
| Devices don't discover each other | Missing permissions | Verify all Bluetooth and network permissions are granted in device settings |
| Sync works on Wi-Fi but not Bluetooth | Background Modes not enabled (iOS) | Enable BLE Background Modes in Xcode capabilities |
DittoError on startup |
Invalid App ID or token | Double-check your credentials in the Ditto Portal |
| Messages appear only on one device | Different App IDs | Ensure both devices use the same App ID |
| Permissions prompt doesn't appear (Android) | requestPermissions not called |
Call DittoSyncPermissions.missingPermissions() before startSync() |
| Build fails after adding package (iOS) | Xcode version too old | DittoChat requires Xcode 15.6+; update Xcode |
- Explore the example apps in the
apps/directory for complete, runnable implementations. - Web integration? See the Web (React/TypeScript) section in the main README.
- Customize the UI — DittoChat components are designed to be themed and extended. Check the platform-specific SDK READMEs in
sdks/for API details. - Go to production — Replace
OnlinePlaygroundauthentication withOnlineWithAuthenticationfor production apps. See the Ditto Cloud Authentication docs for a full walkthrough. - Learn more about Ditto — Visit docs.ditto.live for comprehensive platform documentation.
If you run into issues:
- GitHub Issues: github.com/getditto/DittoChat/issues
- Ditto Support: support@ditto.live
- Documentation: docs.ditto.live