Интеграция SDK чата Stream Chat в мобильное приложение
Stream Chat отличается от SendBird архитектурно: API построен на основе событийной модели (WebSocket + event-driven state), SDK предоставляет готовые SwiftUI/Compose-компоненты с возможностью глубокой кастомизации через subclassing и view factories. Размер бинарника меньше, чем у SendBird, — iOS около 8 МБ, Android AAR ~6 МБ. Разберём интеграцию с нуля без «Hello World» из документации.
Инициализация и токены
Stream работает на JWT. Клиент никогда не генерирует токен самостоятельно — только ваш бэкенд:
POST /api/stream/token
{ "user_id": "user_123" }
→ { "token": "eyJ..." }
На бэкенде токен создаётся через stream_chat.create_token(user_id) (Python/Node SDK). На клиенте:
// iOS
let client = ChatClient(config: ChatClientConfig(apiKeyString: "YOUR_KEY"))
let token = try Token(rawValue: "eyJ...")
client.connectUser(userInfo: .init(id: userId), token: token) { error in ... }
// Android
val client = ChatClient.Builder("YOUR_KEY", context).build()
client.connectUser(User(id = userId), token).enqueue { result -> ... }
Token refresh: Stream SDK вызывает TokenProvider когда токен истекает. Реализуйте TokenProvider (iOS: closure-based, Android: TokenProvider interface) — там делайте запрос к своему API и возвращайте новый токен. Без этого пользователь вылетит из чата через TTL токена.
Каналы: создание и подписка
Stream использует комбинацию type:id для идентификации канала. Типы — messaging, livestream, team, commerce, gaming — влияют на дефолтные permissions.
// Получить или создать канал 1-на-1
let channelId = ChannelId(type: .messaging, id: "user1_user2")
let controller = client.channelController(
createChannelWithId: channelId,
members: [userId, targetId],
isCurrentUserMember: true
)
controller.synchronize { error in ... }
synchronize() — ключевой вызов. Он подтягивает историю, подписывается на realtime-события и синхронизирует локальный state. Без него канал создаётся, но события не приходят.
На Android:
val channelClient = client.channel(channelType = "messaging", channelId = "user1_user2")
channelClient.create(memberIds = listOf(userId, targetId)).enqueue { result -> ... }
SwiftUI UIComponents vs кастомный UI
Stream предоставляет ChatChannelView, MessageListView, MessageComposerView из пакета StreamChatSwiftUI. Кастомизация — через ViewFactory:
class CustomViewFactory: DefaultViewFactory {
func makeMessageAvatarView(for userInfo: UserAvatarData) -> some View {
// Ваш кастомный аватар
CustomAvatarView(imageUrl: userInfo.imageURL)
}
}
// Инжектируем:
Utils.shared.viewFactory = CustomViewFactory()
Это чище, чем полностью свой UI — 80% поведения (свайп, реакции, тред) достаётся бесплатно, кастомизируем только внешний вид. Полный кастомный UI имеет смысл только если дизайн несовместим с моделью компонентов Stream.
Для Android аналогично: MessageListView и MessageComposerView в XML или Compose, кастомизация через AttachmentFactoryManager и MessageListViewModelFactory.
Реакции и треды
Stream поддерживает реакции нативно через message.reactionScores и addReaction / deleteReaction endpoint. Треды (ответы на сообщение) — через controller.createNewReply. В готовых компонентах это работает из коробки; при кастомном UI нужно реализовать ThreadController.
Push-уведомления
Stream использует собственный провайдер уведомлений поверх APNs/FCM. Регистрация:
// iOS — после получения APNs токена
chatClient.currentUserController().addDevice(.apns(token: deviceToken))
// Android
FirebaseMessaging.getInstance().token.addOnSuccessListener { token ->
client.addDevice(Device(token = token, pushProvider = PushProvider.FIREBASE)).enqueue()
}
Stream самостоятельно отправляет уведомления при новых сообщениях в каналах, где пользователь — участник. В dashboard настраиваем шаблоны уведомлений. Deeplink — через обработку CKNNotificationInfo (iOS) или RemoteMessage.data (Android).
Офлайн-кэш
iOS SDK использует CoreData под капотом, Android — Room. Включается автоматически при isLocalStorageEnabled = true в конфигурации (по умолчанию — true). При восстановлении сети SDK автоматически синхронизирует пропущенные события через механизм health check WebSocket.
Этапы работы
Регистрация Stream-приложения и настройка ключей → реализация token endpoint на бэкенде → интеграция SDK → выбор между компонентами и кастомным UI → push-уведомления → тестирование reconnect/offline-сценариев.
Сроки
С готовыми компонентами StreamChatSwiftUI / StreamChatUI — 3-4 дня. Полностью кастомный UI на Core SDK — 6-8 дней. Стоимость рассчитывается индивидуально.







