FastComments.com

Add Comments to Your iOS App


Esta es la biblioteca oficial de iOS para FastComments.

Incruste widgets de comentarios en vivo, chat y reseñas en su aplicación iOS.

Repositorio

Ver en GitHub


Características Internal Link

  • Árboles de comentarios con hilos anidados y paginación
  • Feed social con creación de publicaciones, reacciones y adjuntos multimedia
  • Modo de chat en vivo con desplazamiento automático y separadores por fecha
  • Actualizaciones en tiempo real vía WebSocket (nuevos comentarios, votos, presencia)
  • Inicio de sesión único (SSO simple para pruebas, SSO seguro para producción)
  • Edición de texto enriquecido con negrita, cursiva, código y @menciones
  • Votación con estilos configurables (flechas arriba/abajo o corazones)
  • Acciones de moderación: marcar, fijar, cerrar, bloquear
  • Tematización integral con ajustes predefinidos y personalización total
  • Botones personalizados de la barra de herramientas para comentarios y creación de publicaciones en el feed
  • Subidas de imágenes
  • Soporte para la región de la UE
  • Presencia de usuario (indicadores conectado/desconectado)
  • Filtrado del feed por etiquetas
  • Soporte de localización

Requisitos Internal Link


  • iOS 16+ o macOS 14+
  • Swift 5.9+
  • SwiftUI

Instalación Internal Link

Añade FastCommentsUI a tu proyecto usando Swift Package Manager.

En Xcode: Archivo > Añadir dependencias de paquetes, luego introduce la URL del repositorio.

O añádelo a tu Package.swift:

dependencies: [
    .package(url: "https://github.com/fastcomments/fastcomments-ios.git", from: "1.0.0")
]

Luego añade el producto a tu target:

.target(
    name: "YourApp",
    dependencies: [
        .product(name: "FastCommentsUI", package: "fastcomments-ios")
    ]
)

Importa ambos módulos donde sea necesario:

import FastCommentsUI
import FastCommentsSwift

Inicio rápido Internal Link


La configuración mínima para mostrar un widget de comentarios:

import SwiftUI
import FastCommentsUI

struct ContentView: View {
    @StateObject private var sdk = FastCommentsSDK(
        config: FastCommentsWidgetConfig(
            tenantId: "demo",
            urlId: "my-page-1",
            url: "https://example.com/page-1",
            pageTitle: "My Page"
        )
    )

    var body: some View {
        FastCommentsView(sdk: sdk)
            .task {
                try? await sdk.load()
            }
    }
}

Reemplaza "demo" por tu ID de tenant de FastComments. El urlId identifica la página o hilo donde se almacenan los comentarios.



Autenticación (SSO) Internal Link

FastComments admite tres modos de autenticación:

  1. Anonymous -- sin token SSO; los usuarios obtienen identidades basadas en sesión
  2. Simple SSO -- token del lado del cliente para demos y pruebas (no seguro)
  3. Secure SSO -- token firmado por el servidor para producción

Simple SSO

Útil para demos y pruebas locales. Cualquiera puede suplantar a cualquier usuario con Simple SSO, por lo que no lo uses en producción.

import FastCommentsSwift

let userData = SimpleSSOUserData(
    username: "Jane Doe",
    email: "jane@example.com",
    avatar: "https://example.com/avatar.jpg"
)
let sso = FastCommentsSSO.createSimple(simpleSSOUserData: userData)
let token = try? sso.prepareToSend()

let config = FastCommentsWidgetConfig(
    tenantId: "YOUR_TENANT_ID",
    urlId: "my-page-1",
    sso: token
)
let sdk = FastCommentsSDK(config: config)

SimpleSSOUserData also supports optional fields:

  • id -- ID de usuario (por defecto email si no se establece)
  • displayName -- nombre para mostrar separado
  • displayLabel -- etiqueta personalizada mostrada junto al nombre (por ejemplo "VIP")
  • websiteUrl -- enlace en el nombre del usuario
  • locale -- código de localización
  • isProfileActivityPrivate -- ocultar la actividad del perfil (por defecto true)

Secure SSO

En producción, tu backend genera un token SSO firmado usando tu secreto de API. La app iOS obtiene este token desde tu servidor y lo pasa a la configuración.

On your backend (using the FastComments Swift SDK or any language):

let userData = SecureSSOUserData(
    id: "user-123",
    email: "user@example.com",
    username: "Display Name",
    avatar: "https://example.com/avatar.jpg"
)
let sso = try FastCommentsSSO.createSecure(apiKey: "YOUR_API_KEY", secureSSOUserData: userData)
let token = try sso.prepareToSend()
// Devuelve este token a tu app iOS mediante tu API

In your iOS app:

struct MyView: View {
    @StateObject private var sdk = FastCommentsSDK(
        config: FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "my-page-1"
        )
    )
    @State private var isLoadingToken = true

    var body: some View {
        Group {
            if isLoadingToken {
                ProgressView("Loading...")
            } else {
                FastCommentsView(sdk: sdk)
            }
        }
        .task {
            // Obtén el token de tu backend
            let token = try? await fetchSSOTokenFromYourBackend()
            // Crea una nueva configuración con el token, o establécelo antes de cargar
            isLoadingToken = false
            try? await sdk.load()
        }
    }
}

SecureSSOUserData supports additional fields:

  • optedInNotifications -- suscripción a notificaciones por correo electrónico
  • displayLabel -- etiqueta personalizada
  • displayName -- nombre para mostrar
  • websiteUrl -- URL del sitio web
  • groupIds -- pertenencia a grupos
  • isAdmin -- privilegios de administrador
  • isModerator -- privilegios de moderador
  • isProfileActivityPrivate -- privacidad del perfil


Comentarios anidados Internal Link

Uso básico

struct CommentsPage: View {
    @StateObject private var sdk = FastCommentsSDK(
        config: FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "article-42",
            url: "https://example.com/article/42",
            pageTitle: "Article Title"
        )
    )

    var body: some View {
        FastCommentsView(sdk: sdk)
            .task {
                try? await sdk.load()
            }
    }
}

Estilos de voto

El estilo de voto por defecto muestra flechas arriba/abajo. Usa ._1 para votos estilo corazón:

FastCommentsView(sdk: sdk, voteStyle: ._1)
Estilo Apariencia
._0 Botones de flecha arriba/abajo con recuento neto
._1 Botón único de corazón con contador

Callbacks de eventos

Usa callbacks estilo modificador para manejar las interacciones del usuario:

FastCommentsView(sdk: sdk)
    .onCommentPosted { comment in
        print("New comment: \(comment.commentHTML)")
    }
    .onReplyClick { renderableComment in
        print("Replying to: \(renderableComment.comment.id)")
    }
    .onUserClick { context, userInfo, source in
        // source es .name o .avatar
        print("Tapped \(userInfo.displayName)")
    }

Aplicar un tema

Pasa un tema a través del entorno de SwiftUI:

FastCommentsView(sdk: sdk)
    .fastCommentsTheme(myTheme)
    .task { try? await sdk.load() }

O configúralo directamente en el SDK:

sdk.theme = FastCommentsTheme.modern

Dirección de orden

sdk.defaultSortDirection = .nf  // Más recientes primero (predeterminado)
sdk.defaultSortDirection = .of  // Más antiguos primero
sdk.defaultSortDirection = .mr  // Más relevantes


Chat en vivo Internal Link

LiveChatView ofrece una experiencia de chat en tiempo real con desplazamiento automático, separadores de fecha y un diseño compacto. Configura automáticamente el SDK para ordenación de más antiguos primero y visualización en vivo inmediata.

struct ChatView: View {
    @StateObject private var sdk: FastCommentsSDK = {
        let config = FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "chat-room-1",
            sso: ssoToken  // Se recomienda SSO para que los usuarios tengan nombres
        )
        return FastCommentsSDK(config: config)
    }()

    var body: some View {
        LiveChatView(sdk: sdk)
            .onCommentPosted { comment in
                print("Sent: \(comment.commentHTML)")
            }
            .task {
                try? await sdk.load()
            }
    }
}

LiveChatView supports these callbacks:

  • .onCommentPosted -- se activa cuando el usuario envía un mensaje
  • .onCommentDeleted -- se activa cuando se elimina un mensaje
  • .onUserClick -- se activa cuando se pulsa el nombre o el avatar de un usuario


Feed social Internal Link

El sistema de feed es un SDK separado (FastCommentsFeedSDK) con su propia vista.

Carga y visualización del feed

struct FeedPage: View {
    @StateObject private var sdk: FastCommentsFeedSDK = {
        let config = FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "my-feed",
            sso: ssoToken
        )
        return FastCommentsFeedSDK(config: config)
    }()

    @State private var commentsPost: FeedPost?

    var body: some View {
        FastCommentsFeedView(sdk: sdk)
            .onPostSelected { post in
                commentsPost = post
            }
            .onCommentsRequested { post in
                commentsPost = post
            }
            .onSharePost { post in
                // Presentar hoja de compartir
            }
            .onUserClick { context, userInfo, source in
                // Navegar al perfil de usuario
            }
            .onMediaClick { mediaItem, index in
                // Presentar visor de imágenes a pantalla completa
            }
            .task {
                try? await sdk.load()
            }
    }
}

La vista de feed incluye arrastrar para actualizar (pull-to-refresh) y desplazamiento infinito automáticamente.

Crear publicaciones

Usa FeedPostCreateView para presentar un formulario de creación de publicaciones:

@State private var showCreatePost = false

// En el cuerpo de tu vista:
.sheet(isPresented: $showCreatePost) {
    FeedPostCreateView(
        sdk: sdk,
        onPostCreated: { post in
            showCreatePost = false
            Task { try? await sdk.refresh() }
        },
        onCancelled: {
            showCreatePost = false
        }
    )
}

Reaccionar a publicaciones

El SDK gestiona las reacciones con actualizaciones optimistas:

try await sdk.reactPost(postId: post.id, reactionType: "l")

// Comprobar estado de reacción
let hasLiked = sdk.hasUserReacted(postId: post.id, reactType: "l")
let likeCount = sdk.getLikeCount(postId: post.id)

Abrir comentarios de una publicación

Usa CommentsSheet para mostrar los comentarios de una publicación del feed. Crea una instancia de FastCommentsSDK internamente usando la configuración del feed SDK:

.sheet(item: $commentsPost) { post in
    CommentsSheet(post: post, feedSDK: sdk, onUserClick: { context, userInfo, source in
        // Manejar clic en el usuario
    })
}

Nota: FeedPost debe ajustarse a Identifiable para .sheet(item:). Añade esta extensión:

extension FeedPost: @retroactive Identifiable {}

Filtrado del feed por etiquetas

Implementa el protocolo TagSupplier para filtrar las publicaciones del feed por etiquetas:

struct TeamTagSupplier: TagSupplier {
    func getTags(currentUser: UserSessionInfo?) -> [String]? {
        guard let user = currentUser else { return nil }
        return ["team:\(user.id ?? "")", "public"]
    }
}

sdk.tagSupplier = TeamTagSupplier()

Devuelve nil para un feed global sin filtrar.

Guardar y restaurar el estado del feed

Preserva el estado de paginación a través de eventos del ciclo de vida de la vista:

let state = sdk.savePaginationState()
// Más tarde...
sdk.restorePaginationState(state)

Eliminar publicaciones

sdk.onPostDeleted = { postId in
    print("Post \(postId) was deleted")
}


Personalización de temas Internal Link

Preajustes de tema

Cuatro preajustes integrados están disponibles:

// Valores predeterminados del sistema
sdk.theme = FastCommentsTheme.default

// Tarjetas con sombras y esquinas grandes redondeadas
sdk.theme = FastCommentsTheme.modern

// Plano, sin sombras, radio de esquina pequeño, sin líneas de hilo
sdk.theme = FastCommentsTheme.minimal

// Establecer todos los colores de acción a un único color de marca
sdk.theme = FastCommentsTheme.allPrimary(.indigo)

Estilos de visualización de comentarios

var theme = FastCommentsTheme()
theme.commentStyle = .flat    // Lista plana con divisores (predeterminado)
theme.commentStyle = .card    // Tarjetas redondeadas con sombras
theme.commentStyle = .bubble  // Estilo de burbuja de chat

Colores

Todas las propiedades de color son opcionales. Los valores no establecidos vuelven a los valores predeterminados sensatos del sistema.

var theme = FastCommentsTheme()

// Colores de marca
theme.primaryColor = .indigo
theme.primaryLightColor = .indigo.opacity(0.6)
theme.primaryDarkColor = Color(red: 0.2, green: 0.1, blue: 0.5)

// Fondos
theme.commentBackgroundColor = Color(.secondarySystemGroupedBackground)
theme.containerBackgroundColor = Color(.systemGroupedBackground)

// Botones de acción
theme.actionButtonColor = .indigo
theme.replyButtonColor = .indigo
theme.toggleRepliesButtonColor = .indigo.opacity(0.8)
theme.loadMoreButtonTextColor = .indigo

// Votos
theme.voteActiveColor = .red
theme.voteCountColor = .primary
theme.voteCountZeroColor = .secondary
theme.voteDividerColor = Color(.separator)

// Enlaces
theme.linkColor = .indigo
theme.linkColorPressed = .indigo.opacity(0.5)

// Diálogos
theme.dialogHeaderBackgroundColor = .indigo
theme.dialogHeaderTextColor = .white

// Barra de entrada
theme.inputBarBackgroundColor = Color(.systemBackground)
theme.inputBarBorderColor = Color(.separator)

// Otros
theme.onlineIndicatorColor = .green
theme.separatorColor = Color(.separator)
theme.badgeBackgroundColor = .gray.opacity(0.2)
theme.threadLineColor = .indigo.opacity(0.15)

Tipografía

theme.commenterNameFont = .subheadline.weight(.bold)
theme.bodyFont = .body
theme.captionFont = .caption
theme.actionFont = .caption.weight(.medium)

Diseño y espaciado

theme.cornerRadius = .large       // .none, .small, .medium, .large
theme.commentSpacing = 4          // Puntos entre filas de comentarios
theme.nestingIndent = 20          // Puntos de sangría por nivel de anidamiento
theme.avatarSize = 36             // Diámetro del avatar para comentarios raíz
theme.replyAvatarSize = 28        // Diámetro del avatar para respuestas anidadas

Efectos visuales

theme.showShadows = true          // Sombras sutiles en las tarjetas
theme.showThreadLine = true       // Línea vertical que conecta respuestas anidadas
theme.animateVotes = true         // Animación tipo resorte en cambios de votación

Aplicación de temas

Dos enfoques:

// A través del entorno SwiftUI (recomendado para la jerarquía de vistas)
FastCommentsView(sdk: sdk)
    .fastCommentsTheme(theme)

// Directamente en el SDK
sdk.theme = theme


Botones personalizados de la barra de herramientas Internal Link

Botones de la barra de herramientas de comentarios

Implemente el protocolo CustomToolbarButton para agregar botones a la barra de herramientas del campo de entrada de comentarios:

struct EmojiButton: CustomToolbarButton {
    let id = "emoji"
    let iconSystemName = "face.smiling"       // Nombre del SF Symbol
    let contentDescription = "Add Emoji"
    let badgeText: String? = nil              // Conteo de insignia opcional

    func onClick(text: Binding<String>) {
        text.wrappedValue += "\u{1F44D}"
    }

    // Sobrescrituras opcionales (predeterminado true)
    func isEnabled() -> Bool { true }
    func isVisible() -> Bool { true }
}

Pase los botones personalizados al crear la vista:

FastCommentsView(
    sdk: sdk,
    customToolbarButtons: [EmojiButton(), CodeBlockButton()]
)

O agréguelos globalmente al SDK (se aplica a todas las instancias):

sdk.addGlobalCustomToolbarButton(EmojiButton())
sdk.removeGlobalCustomToolbarButton(id: "emoji")
sdk.clearGlobalCustomToolbarButtons()

Botones de la barra de herramientas del feed

Implemente FeedCustomToolbarButton para el formulario de creación de publicaciones:

struct HashtagButton: FeedCustomToolbarButton {
    let id = "hashtag"
    let iconSystemName = "number"
    let contentDescription = "Add Hashtag"

    func onClick(content: Binding<String>) {
        content.wrappedValue += "#"
    }
}

Páselos a la vista de creación:

FeedPostCreateView(
    sdk: sdk,
    customToolbarButtons: [HashtagButton()],
    onPostCreated: { _ in },
    onCancelled: { }
)

O configúrelos globalmente en el SDK del feed:

sdk.globalFeedToolbarButtons = [HashtagButton()]


Moderación Internal Link

Acciones disponibles para todos los usuarios

  • Marcar/Desmarcar -- reportar un comentario para revisión
try await sdk.flagComment(commentId: commentId)
try await sdk.unflagComment(commentId: commentId)
  • Bloquear/Desbloquear -- ocultar todos los comentarios de un usuario (por espectador)
try await sdk.blockUser(commentId: commentId)
try await sdk.unblockUser(commentId: commentId)

Acciones solo para administradores

  • Fijar/Desfijar -- fijar un comentario en la parte superior del hilo
try await sdk.pinComment(commentId: commentId)
try await sdk.unpinComment(commentId: commentId)
  • Bloquear/Desbloquear -- impedir nuevas respuestas en un comentario
try await sdk.lockComment(commentId: commentId)
try await sdk.unlockComment(commentId: commentId)

Todas las acciones de moderación también están disponibles a través del menú contextual del comentario en la interfaz de usuario. Las acciones de administrador solo aparecen cuando el usuario actual es administrador del sitio (configurado mediante la bandera SSO isAdmin o la configuración del panel).



Actualizaciones en tiempo real Internal Link

Después de llamar a sdk.load(), el SDK se suscribe automáticamente a los eventos de WebSocket para el urlId configurado. Se manejan los siguientes eventos:

  • Nuevos comentarios, ediciones y eliminaciones
  • Votos (nuevos y eliminados)
  • Cambios de estado de pin, lock, flag y block
  • Presencia de usuarios (entrada/salida)
  • Apertura/cierre de hilo
  • Otorgamiento de insignias
  • Actualizaciones de configuración del servidor

Controlar la visualización en vivo

Por defecto, los nuevos comentarios de otros usuarios aparecen inmediatamente:

sdk.showLiveRightAway = true   // Predeterminado: mostrarse inmediatamente

Establece esto en false para almacenar en búfer los nuevos comentarios detrás de un botón "N nuevos comentarios", permitiendo que el usuario elija cuándo revelarlos:

sdk.showLiveRightAway = false

Presencia de usuario

Los indicadores de en línea/sin conexión aparecen automáticamente en los avatares de usuario cuando el servidor habilita el seguimiento de presencia. No se necesita configuración adicional en el cliente.



Paginación Internal Link

Tamaño de página

// Comentarios: por defecto 30
sdk.pageSize = 50

// Feed: por defecto 10
feedSDK.pageSize = 20

Cargar más comentarios

La interfaz de usuario muestra controles de paginación automáticamente. También puedes activar la paginación programáticamente:

// Cargar la siguiente página
try await sdk.loadMore()

// Cargar todos los restantes (deshabilitado si >2000 comentarios por rendimiento)
try await sdk.loadAll()

// Comprobar estado
sdk.hasMore            // Si existen más páginas
sdk.shouldShowLoadAll()
sdk.getCountRemainingToShow()

Paginación de comentarios hijos

Las respuestas anidadas se cargan de forma diferida. Cuando un usuario expande un hilo, se cargan los primeros 5 hijos. Aparece un control "cargar más respuestas" si existen más. Esto lo gestiona automáticamente la interfaz de usuario.



Estado y observabilidad Internal Link

Ambas FastCommentsSDK y FastCommentsFeedSDK son clases ObservableObject con propiedades @Published. Puedes observarlas en tus vistas SwiftUI para actualizaciones reactivas de la interfaz.

Propiedades Publicadas de FastCommentsSDK

Propiedad Tipo Descripción
commentCountOnServer Int Recuento total de comentarios en el servidor
newRootCommentCount Int Comentarios nuevos en búfer (cuando showLiveRightAway es false)
currentUser UserSessionInfo? Usuario autenticado actual
isSiteAdmin Bool Si el usuario actual es administrador del sitio
isClosed Bool Si el hilo de comentarios está cerrado
hasBillingIssue Bool Si existe un problema de facturación
isLoading Bool Si hay una petición de red en curso
hasMore Bool Si existen más páginas de comentarios
blockingErrorMessage String? Error que impide que la interfaz funcione
warningMessage String? Mensaje de advertencia no bloqueante
isDemo Bool Si se está ejecutando en modo demo
commentsVisible Bool Control para la visibilidad de los comentarios
toolbarEnabled Bool Si se muestra la barra de herramientas de formato

Propiedades Publicadas de FastCommentsFeedSDK

Propiedad Tipo Descripción
feedPosts [FeedPost] Publicaciones del feed actualmente cargadas
hasMore Bool Si existen más páginas
currentUser UserSessionInfo? Usuario autenticado actual
blockingErrorMessage String? Mensaje de error bloqueante
isLoading Bool Si hay una petición de red en curso
newPostsCount Int Número de nuevas publicaciones desde la última carga

Árbol de comentarios

El árbol de comentarios es accesible a través de sdk.commentsTree:

// Lista plana de nodos visibles para renderizar
sdk.commentsTree.visibleNodes

// Buscar un comentario por ID
sdk.commentsTree.commentsById["comment-id"]


Región de la UE Internal Link


Para usar el centro de datos de la UE, establezca el campo region en su configuración:

let config = FastCommentsWidgetConfig(
    tenantId: "YOUR_TENANT_ID",
    urlId: "my-page",
    region: "eu"
)

Esto enruta todas las solicitudes de API y las conexiones WebSocket a eu.fastcomments.com.



Limpieza Internal Link


Cuando haya terminado con una instancia del SDK (por ejemplo, cuando se descarta la vista), llame a cleanup() para cerrar la conexión WebSocket y cancelar tareas en segundo plano:

sdk.cleanup()

Para vistas gestionadas por @StateObject de SwiftUI, esto normalmente se llama en .onDisappear o cuando la vista se libera.



Subida de imágenes Internal Link

Comentarios

let imageUrl = try await sdk.uploadImage(imageData: jpegData, filename: "photo.jpg")

Devuelve la cadena URL de la imagen subida.

Publicaciones del Feed

let mediaItem = try await feedSDK.uploadImage(imageData: jpegData, filename: "photo.jpg")

// Subir varias imágenes en paralelo
let mediaItems = try await feedSDK.uploadImages(images: [
    (jpegData1, "photo1.jpg"),
    (jpegData2, "photo2.jpg")
])


Menciones de usuarios Internal Link

Buscar usuarios para habilitar el autocompletado de @menciones:

let results = try await sdk.searchUsers(query: "jan")
// Devuelve [UserSearchResult] con userId, username, avatar, etc.

La CommentInputBar integrada gestiona el autocompletado de @menciones automáticamente.



Edición y eliminación de comentarios Internal Link

Editar

try await sdk.editComment(commentId: commentId, newText: "Updated text")

El servidor vuelve a renderizar el HTML. El comentario local se actualiza automáticamente.

Eliminar

try await sdk.deleteComment(commentId: commentId)

Eliminar un comentario también elimina sus descendientes del árbol local.

Ambas acciones están disponibles a través del menú contextual del comentario en la interfaz de usuario cuando el usuario actual es el autor del comentario (o un administrador del sitio).



Gestión de errores Internal Link

Los métodos del SDK lanzan FastCommentsError, que cumple con LocalizedError:

do {
    try await sdk.load()
} catch let error as FastCommentsError {
    print(error.translatedError ?? error.reason ?? "Unknown error")
} catch {
    print(error.localizedDescription)
}

Propiedades de FastCommentsError:

  • code -- código de error de la API
  • reason -- descripción del error en inglés
  • translatedError -- mensaje de error localizado proporcionado por el servidor

Los errores de bloqueo también se muestran automáticamente a través de sdk.blockingErrorMessage, que las vistas integradas muestran al usuario.



Localización Internal Link

Pasa un código de localización en la configuración para localizar las cadenas proporcionadas por el servidor:

let config = FastCommentsWidgetConfig(
    tenantId: "YOUR_TENANT_ID",
    urlId: "my-page",
    locale: "fr_fr"
)

Las cadenas de la interfaz de usuario del lado del cliente utilizan la localización basada en bundles de iOS.



Aplicación de ejemplo Internal Link

El repositorio incluye una aplicación de ejemplo completa en ExampleApp/ con demostraciones de:

  • Comentarios en hilos con SSO y temas personalizados
  • Feed social con creación de publicaciones y filtrado por etiquetas
  • Chat en vivo
  • Flujos SSO simples y seguros
  • Botones personalizados en la barra de herramientas (comentarios y feed)

¿Necesita ayuda?

Si encuentra algún problema o tiene preguntas sobre la biblioteca iOS, por favor:

Contribuciones

¡Se aceptan contribuciones! Visite el repositorio en GitHub para conocer las directrices de contribución.