Как подключить мобильный SDK к приложению iOS

Обновлено: 9 октября 2026 · 10 мин чтения

SDK для iOS использует только системные фреймворки и поставляется с privacy manifest. Clomni отправляет push на iOS напрямую в APNs с Вашим ключом .p8: Firebase на iOS не нужен.

Шаги

  1. 1

    Требования

    • iOS 15 или новее, Xcode 15 или новее.
    • App ID и ключ API для iOS (ios_…) из раздела «Installation» в панели.
    • Для push: аккаунт Apple Developer и ключ APNs.
  2. 2

    Добавьте пакет

    Swift Package Manager: Xcode › File › Add Package Dependencies, введите https://github.com/clomni/clomni-mobile-sdk.git, выберите «Up to Next Major Version» от 1.0.4 и добавьте продукт ClomniMessenger в цель приложения. В Package.swift:

    dependencies: [
        .package(url: "https://github.com/clomni/clomni-mobile-sdk.git", from: "1.0.4"),
    ],
    targets: [
        .target(name: "App", dependencies: [
            .product(name: "ClomniMessenger", package: "clomni-mobile-sdk"),
        ]),
    ]

    CocoaPods: SDK нет в CocoaPods trunk, берите pod из тега репозитория. Со строкой pod 'ClomniMessenger', '1.0.4' CocoaPods пакет не найдёт.

    # Podfile, in your app's target
    pod 'ClomniMessenger', :git => 'https://github.com/clomni/clomni-mobile-sdk.git', :tag => '1.0.4'

    Пользователь может отправлять фото в диалоге. Добавьте тексты разрешений в Info.plist:

    <key>NSPhotoLibraryUsageDescription</key>
    <string>To send photos to support</string>
    <key>NSCameraUsageDescription</key>
    <string>To take a photo and send it to support</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>To send voice messages to support</string>

    Без NSCameraUsageDescription Messenger не предлагает камеру. Без NSMicrophoneUsageDescription кнопка микрофона не показывается (голосовые сообщения появятся в SDK 1.0.2).

  3. 3

    Запустите SDK

    Вызывайте initialize один раз при запуске. В приложении SwiftUI подключите AppDelegate через @UIApplicationDelegateAdaptor, для push он всё равно нужен.

    import SwiftUI
    
    @main
    struct ExampleApp: App {
        @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
    
        var body: some Scene {
            WindowGroup { ContentView() }
        }
    }

    Методы можно вызывать из любого треда, колбэки приходят в главном треде (main thread). Повторный initialize игнорируется. Полный AppDelegate приведён ниже в части о push.

  4. 4

    Пользователь и Messenger

    let user = ClomniUser(userId: "12345", email: "[email protected]", name: "Aysel")
    Clomni.loginUser(user, userHash: hashFromYourServer)   // the hash comes from your server
    Clomni.updateUser(language: "az", customAttributes: ["plan": "premium"])
    
    // Together with your app's own logout:
    Clomni.logout()
    // SwiftUI
    Button("Support") { Clomni.present(source: "profile_support") }
    
    // UIKit
    @objc private func supportTapped() {
        Clomni.present(source: "profile_support")
    }

    Messenger открывается поверх верхнего экрана. Вызывайте present после показа экрана, не в didFinishLaunching. Другие вызовы: presentNewConversation(source:), presentConversation(_:), dismiss(). Счётчик непрочитанных: let token = Clomni.addUnreadCountListener { count in ... }, затем Clomni.removeUnreadCountListener(token). Плавающая кнопка: Clomni.setLauncherVisible(true), Clomni.setBottomPadding(72) (в точках).

    Пока пользователь вошёл в приложение, вызывайте loginUser при каждом запуске, как будто он только что вошёл. Для того же пользователя SDK использует сохранённую сессию.

  5. 5

    События, ссылки, язык и внешний вид

    Чтобы слушать события Messenger:

    Clomni.onMessengerOpened = { source in print("opened from \(source ?? "-")") }
    Clomni.onMessengerClosed = { print("closed") }
    Clomni.onConversationStarted = { id in print("conversation \(id)") }
    Clomni.onFlowCompleted = { flowId in print("flow \(flowId) completed") }
    Clomni.onUnreadCountChanged = { count in print("unread \(count)") }

    У каждого события один слушатель, nil удаляет его.

    Кнопка новости может вести на веб-адрес или deep link приложения. Если задан onLink, каждая ссылка приходит в приложение, и открывает её приложение. Без него ссылки открывает система.

    Clomni.onLink = { url in
        if url.scheme == "example" {
            // route inside your app
        } else {
            UIApplication.shared.open(url)
        }
    }

    Язык, звуки и собственный цвет приложения:

    Clomni.setLanguage("en")          // az, en or ru; nil follows the phone
    Clomni.setSoundsEnabled(false)
    Clomni.setTheme(primaryColor: "#0A66C2", typeface: "Montserrat", mode: .dark)
    • setLanguage выбирает один из языков, включённых в панели (Appearance › «Languages»). Пустое значение или выключенный язык: используется язык телефона, а если его нет, основной язык панели.
    • Звуки: короткий звук отправленного и полученного сообщения, пока диалог открыт. Подчиняется беззвучному режиму телефона.
    • setTheme накладывает собственный цвет, шрифт и режим приложения поверх настроек панели. Цвет в формате #RRGGBB, остальные цвета бренда выводятся из него. Каждый вызов заменяет предыдущий, не переданное значение остаётся из панели. При неверном формате в логе будет setTheme: primaryColor "…" is not #RRGGBB.
    • Шрифт задаётся именем семейства шрифта из бандла приложения, указанного в Info.plist под UIAppFonts ("Montserrat" для Montserrat-Regular.ttf). Текст по-прежнему следует Dynamic Type. Только шрифт: Clomni.setTypeface("Montserrat"). Если шрифт не найден, в логе будет font family "…" is not in the app; the system font stays, и останется системный шрифт.
  6. 6

    Push: capability

    Xcode › Project navigator › проект › TARGETS › приложение › Signing & Capabilities › + Capability › Push Notifications. Конфигурация «All».

  7. 7

    Push: AppDelegate

    import ClomniMessenger
    import UIKit
    import UserNotifications
    
    final class AppDelegate: NSObject, UIApplicationDelegate, @preconcurrency UNUserNotificationCenterDelegate {
        func application(_ application: UIApplication,
                         didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            Clomni.initialize(appId: "app_…", apiKey: "ios_…")
            UNUserNotificationCenter.current().delegate = self
            Task {
                let center = UNUserNotificationCenter.current()
                let granted = try? await center.requestAuthorization(options: [.alert, .sound, .badge])
                if granted == true { UIApplication.shared.registerForRemoteNotifications() }
            }
            return true
        }
    
        func application(_ application: UIApplication,
                         didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
            Clomni.setDeviceToken(deviceToken)
        }
    
        // A push while the app is open. Clomni pushes stay hidden while the Messenger is open.
        @MainActor
        func userNotificationCenter(
            _ center: UNUserNotificationCenter,
            willPresent notification: UNNotification
        ) async -> UNNotificationPresentationOptions {
            Clomni.shouldShowForeground(notification.request.content.userInfo) ? [.banner, .list, .sound] : []
        }
    
        // A tap: a Clomni push opens its conversation.
        @MainActor
        func userNotificationCenter(_ center: UNUserNotificationCenter,
                                    didReceive response: UNNotificationResponse) async {
            if Clomni.handlePush(response.notification.request.content.userInfo) { return }
            // your app's own push
        }
    }
    • Оба метода делегата оставьте @MainActor, не nonisolated. Иначе нажатие на уведомление останавливает приложение с «Call must be made on main thread».
    • Запрашивайте разрешение на уведомления в удобный для пользователей момент. Пример для краткости запрашивает при запуске.
    • Clomni.isClomniPush(userInfo) говорит, принадлежит ли push Clomni.
  8. 8

    Sandbox и production

    SDK сам сообщает среду APNs каждого устройства: сборка, запущенная из Xcode, использует sandbox; TestFlight, App Store и Ad Hoc используют production. Один ключ .p8 обслуживает обе среды, если создан для Sandbox & Production. Ключ, ограниченный одной средой, в другой даёт BadEnvironmentKeyInToken. Список «Test push» показывает среду каждого устройства.

    Если хотите фото оператора в уведомлении, добавьте Notification Service Extension. Clomni отправляет каждый push с mutable-content: 1 и avatar_url. Готовый код расширения есть в разделе iOS полного руководства, Clomni SDK ему не нужен.

  9. 9

    Проверьте

    1. Запустите приложение на настоящем iPhone (симулятор не получает push APNs от Clomni), разрешите уведомления и один раз откройте Messenger.
    2. Панель › Ваш канал › колонка настроек › «Push» › «Test push» › выберите устройство › «Send».

    Логи в консоли Xcode и в Console.app: subsystem ai.clomni.messenger, category Clomni. Частые проблемы:

    • Строка лога, начинающаяся с api_key, о том, что ключ неверный или не для этой платформы (ошибка сервера invalid_api_key): используйте ключ ios_…. Так же бывает, если «iOS Bundle ID» в панели отличается от Bundle ID приложения.
    • no window to present the messenger from yet: вызывайте present после показа экрана.
    • «Test push» отвечает BadEnvironmentKeyInToken: создайте ключ Sandbox & Production. DeviceTokenNotForTopic: Bundle ID в разделе Push не совпадает с Bundle ID приложения.
  10. 10

    Полное руководство

Документ