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

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

Плагин clomni_flutter работает поверх нативных SDK для Android и iOS, экраны нативные.

Шаги

  1. 1

    Требования

    • Flutter 3.16 или новее.
    • iOS 15, Android API 24.
    • App ID и оба ключа API (android_…, ios_…).
    • Голосовым сообщениям (с SDK 1.0.2) нужно RECORD_AUDIO в манифесте Android-приложения, иначе кнопка микрофона не показывается. Камере разрешение не нужно.
  2. 2

    Установка

    flutter pub add clomni_flutter

    SDK для iOS является Swift package:

    • Со Swift Package Manager плагин берёт SDK сам. В текущем Flutter он включён по умолчанию. Во Flutter 3.24 и новее, если он выключен, включите его командой flutter config --enable-swift-package-manager.
    • С CocoaPods добавьте эту строку в ios/Podfile внутри target 'Runner' и выполните pod install. Без строки pod install останавливается с «clomni_flutter: the iOS SDK is not on CocoaPods trunk».
    pod 'ClomniMessenger', :git => 'https://github.com/clomni/clomni-mobile-sdk.git', :tag => '1.0.4'

    Добавьте тексты разрешений для фото (NSPhotoLibraryUsageDescription, NSCameraUsageDescription, а с SDK 1.0.2 и NSMicrophoneUsageDescription) в ios/Runner/Info.plist.

    На Android MainActivity должна наследовать FlutterFragmentActivity, а не FlutterActivity. Иначе приложение падает при открытии Messenger, а плавающая кнопка не видна:

    // android/app/src/main/kotlin/com/example/app/MainActivity.kt
    package com.example.app
    
    import io.flutter.embedding.android.FlutterFragmentActivity
    
    class MainActivity : FlutterFragmentActivity()
  3. 3

    Запустите SDK

    import 'dart:io' show Platform;
    
    import 'package:clomni_flutter/clomni_flutter.dart';
    import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';
    
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Clomni.initialize('app_…', Platform.isIOS ? 'ios_…' : 'android_…');
      if (kDebugMode) await Clomni.setLogLevel(ClomniLogLevel.debug);
      runApp(const App());
    }
  4. 4

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

    await Clomni.loginUser(
      const ClomniUser(userId: '12345', email: '[email protected]', name: 'Aysel'),
      userHash: hashFromYourServer,
    );
    await Clomni.updateUser(language: 'az', customAttributes: {'plan': 'premium'});
    
    // Together with your app's own logout:
    await Clomni.logout();
    class SupportTile extends StatelessWidget {
      const SupportTile({super.key});
    
      @override
      Widget build(BuildContext context) {
        return StreamBuilder<int>(
          stream: Clomni.unreadCountStream, // the current count at once, then every change
          builder: (context, snapshot) {
            final unread = snapshot.data ?? 0;
            return ListTile(
              title: const Text('Support'),
              trailing: unread > 0 ? Badge(label: Text('$unread')) : null,
              onTap: () => Clomni.present(source: 'profile_support'),
            );
          },
        );
      }
    }

    Другие вызовы: presentNewConversation(source: …), presentConversation(id), dismiss(), setLauncherVisible(true), setBottomPadding(72). События приходят как Stream: onMessengerOpened, onMessengerClosed, onConversationStarted, onFlowCompleted.

    Шрифты из pubspec.yaml не доходят до нативных экранов. Передайте в setTypeface на iOS имя семейства шрифта из UIAppFonts, на Android имя ресурса res/font: await Clomni.setTypeface(Platform.isIOS ? 'Montserrat' : 'montserrat');.

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

  5. 5

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

    Запуск flow из приложения и подписка на события Messenger:

    await Clomni.startFlow('ride_problem', data: {'ride_id': 'R-1923'}, openMessenger: true, source: 'ride_screen');
    
    final subscriptions = [
      Clomni.onMessengerOpened.listen((source) => debugPrint('opened from $source')),
      Clomni.onMessengerClosed.listen((_) => debugPrint('closed')),
      Clomni.onConversationStarted.listen((id) => debugPrint('conversation $id')),
      Clomni.onFlowCompleted.listen((flowId) => debugPrint('flow $flowId')),
    ];
    // later: for (final s in subscriptions) { s.cancel(); }

    Flow должен быть создан в панели с триггером «Событие приложения» с тем же именем и опубликован. Данные должны быть JSON.

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

    import 'package:url_launcher/url_launcher.dart';
    
    await Clomni.onLink((url) => launchUrl(Uri.parse(url)));   // or your own router; null: the system opens links
    await Clomni.setLanguage('en');                             // 'az', 'en', 'ru'; null follows the phone
    await Clomni.setSoundsEnabled(false);
    await Clomni.setTheme(primaryColor: '#0A66C2', typeface: 'Montserrat', mode: ClomniThemeMode.dark);

    Язык Messenger меняет setLanguage; updateUser(language: …) записывает язык в профиль пользователя. Выбранный язык должен быть включён в панели, иначе используется язык телефона, а если и он выключен, основной язык панели. Цвет указывается в формате #RRGGBB. Значения из панели действуют, только если приложение не задало свои.

  6. 6

    Push: Android

    Сначала загрузите ключи в панель (статья «Ключи push для мобильного SDK»). Настройте Firebase через FlutterFire (flutterfire configure) и объявите <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> в android/app/src/main/AndroidManifest.xml.

    import 'dart:io' show Platform;
    
    import 'package:clomni_flutter/clomni_flutter.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:firebase_messaging/firebase_messaging.dart';
    import 'package:flutter/material.dart';
    
    // Clomni data messages while the app is in the background or closed: the SDK shows the notification.
    @pragma('vm:entry-point')
    Future<void> onBackgroundMessage(RemoteMessage message) async {
      await Clomni.handlePush(message.data);
    }
    
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      FirebaseMessaging.onBackgroundMessage(onBackgroundMessage);
      await Clomni.initialize('app_…', Platform.isIOS ? 'ios_…' : 'android_…');
      runApp(const App());
    }
    
    Future<void> setUpAndroidPush() async {
      final messaging = FirebaseMessaging.instance;
      await messaging.requestPermission(); // Android 13+: the system permission dialog
      final token = await messaging.getToken();
      if (token != null) await Clomni.setDeviceToken(token);
      messaging.onTokenRefresh.listen(Clomni.setDeviceToken);
      // Messages while the app is open.
      FirebaseMessaging.onMessage.listen((message) async {
        if (!await Clomni.handlePush(message.data)) {
          // your app's own push
        }
      });
      await Clomni.setNotificationIcon('ic_notification'); // android/app/src/main/res/drawable/ic_notification.png
    }

    Вызывайте setUpAndroidPush() на Android в подходящий момент, например после входа.

  7. 7

    Push: iOS

    Clomni отправляет push на iOS в APNs, не через Firebase. firebase_messaging не видит нажатия на уведомление Clomni, поэтому ловите нажатие в нативном коде Runner:

    1. В Xcode (ios/Runner.xcworkspace): Runner › Signing & Capabilities › + Capability › Push Notifications.
    2. Код Runner импортирует ClomniMessenger. С CocoaPods достаточно строки Podfile выше. Со Swift Package Manager добавьте пакет и в цель Runner: File › Add Package Dependencies, https://github.com/clomni/clomni-mobile-sdk.git, продукт ClomniMessenger, цель Runner.
    3. Добавьте этот файл в Runner:
    // ios/Runner/ClomniNotifications.swift
    import ClomniMessenger
    import UserNotifications
    
    /// Clomni pushes: hidden while the Messenger is open, and a tap opens the conversation.
    final class ClomniNotifications: NSObject, UNUserNotificationCenterDelegate {
        static let shared = ClomniNotifications()
    
        func userNotificationCenter(
            _ center: UNUserNotificationCenter,
            willPresent notification: UNNotification,
            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
        ) {
            let show = Clomni.shouldShowForeground(notification.request.content.userInfo)
            completionHandler(show ? [.banner, .list, .sound] : [])
        }
    
        func userNotificationCenter(
            _ center: UNUserNotificationCenter,
            didReceive response: UNNotificationResponse,
            withCompletionHandler completionHandler: @escaping () -> Void
        ) {
            _ = Clomni.handlePush(response.notification.request.content.userInfo)
            completionHandler()
        }
    }
    1. Сделайте его делегатом в AppDelegate.swift, до `super.application(...)`:
    // ios/Runner/AppDelegate.swift
    import Flutter
    import UIKit
    import UserNotifications
    
    @main
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        UNUserNotificationCenter.current().delegate = ClomniNotifications.shared
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
    1. Передайте токен APNs из Dart:
    if (Platform.isIOS) {
      await FirebaseMessaging.instance.requestPermission();
      final apnsToken = await FirebaseMessaging.instance.getAPNSToken(); // hex
      if (apnsToken != null) await Clomni.setDeviceToken(apnsToken);
    }

    Если на iOS нет Firebase, переопределите в AppDelegate didRegisterForRemoteNotificationsWithDeviceToken: Clomni.setDeviceToken(deviceToken), затем super.

  8. 8

    Проблемы

    • pod install останавливается и печатает строку pod 'ClomniMessenger': впишите строку внутрь target 'Runner' или включите Swift Package Manager.
    • Android: приложение падает при открытии Messenger или плавающая кнопка не видна: MainActivity должна наследовать FlutterFragmentActivity.
    • На Android уведомления не приходят, когда приложение закрыто: зарегистрируйте onBackgroundMessage до runApp, функцией верхнего уровня.
    • iOS: No such module 'ClomniMessenger': добавьте пакет или pod в цель Runner (шаг 2).
    • На iOS нажатие только открывает приложение: делегата нет или он назначен после super.application(...).

    Ошибки Dart начинаются с [Clomni] в логе Flutter, нативные логи в logcat (Clomni) и в консоли Xcode.

  9. 9

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

Документ