
Idioma 🇧🇷 Português (Brasil)
Documentação
Primeiros passos
Autenticação
Uso
Add Comments to Your iOS App
Esta é a biblioteca iOS oficial do FastComments.
Incorpore widgets de comentários ao vivo, chat e avaliação no seu app iOS.
Repositório
Recursos 
- Árvores de comentários encadeados com respostas aninhadas e paginação
- Feed social com criação de postagens, reações e anexos de mídia
- Modo de chat ao vivo com rolagem automática e separadores de data
- Atualizações em tempo real via WebSocket (novos comentários, votos, presença)
- Single Sign-On (SSO simples para testes, SSO seguro para produção)
- Edição de texto rico com negrito, itálico, código e menções @
- Votação com estilos configuráveis (setas para cima/baixo ou corações)
- Ações de moderação: sinalizar, fixar, trancar, bloquear
- Temas abrangentes com predefinições e personalização completa
- Botões de barra de ferramentas personalizados para criação de comentários e publicações no feed
- Upload de imagens
- Suporte à região da UE
- Presença do usuário (indicadores online/offline)
- Filtragem do feed baseada em tags
- Suporte à localização
Instalação 
Adicione FastCommentsUI ao seu projeto usando o Swift Package Manager.
No Xcode: Arquivo > Adicionar Dependências de Pacote, em seguida insira a URL do repositório.
Ou adicione-o ao seu Package.swift:
dependencies: [
.package(url: "https://github.com/fastcomments/fastcomments-ios.git", from: "1.0.0")
]
Em seguida, adicione o produto ao seu target:
.target(
name: "YourApp",
dependencies: [
.product(name: "FastCommentsUI", package: "fastcomments-ios")
]
)
Importe ambos os módulos onde necessário:
import FastCommentsUI
import FastCommentsSwift
Início Rápido 
A configuração mínima para exibir um widget de comentários:
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()
}
}
}
Replace "demo" with your FastComments tenant ID. The urlId identifies the page or thread where comments are stored.
Autenticação (SSO) 
FastComments suporta três modos de autenticação:
- Anônimo -- sem token SSO; os usuários recebem identidades baseadas em sessão
- Simple SSO -- token no cliente para demonstrações e testes (não seguro)
- Secure SSO -- token assinado pelo servidor para produção
Simple SSO
Útil para demonstrações e testes locais. Qualquer pessoa pode se passar por qualquer usuário com Simple SSO, portanto não o utilize em produção.
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 também suporta campos opcionais:
id-- ID do usuário (padrão é o email se não definido)displayName-- nome de exibição separadodisplayLabel-- etiqueta personalizada exibida ao lado do nome (por exemplo "VIP")websiteUrl-- link no nome do usuáriolocale-- código de localidadeisProfileActivityPrivate-- ocultar atividade do perfil (padrão é true)
Secure SSO
Em produção, seu backend gera um token SSO assinado usando seu segredo de API. O app iOS busca esse token no seu servidor e o passa para a config.
No seu backend (usando o SDK Swift do FastComments ou qualquer linguagem):
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()
// Retorne este token para seu app iOS via sua API
No seu app iOS:
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 {
// Busque o token no seu backend
let token = try? await fetchSSOTokenFromYourBackend()
// Crie uma nova config com o token, ou defina-o antes do carregamento
isLoadingToken = false
try? await sdk.load()
}
}
}
SecureSSOUserData suporta campos adicionais:
optedInNotifications-- opt-in para notificações por emaildisplayLabel-- etiqueta personalizadadisplayName-- nome de exibiçãowebsiteUrl-- URL do sitegroupIds-- associações a gruposisAdmin-- privilégios de administradorisModerator-- privilégios de moderadorisProfileActivityPrivate-- privacidade do perfil
Comentários encadeados 
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
O estilo de voto padrão mostra setas para cima/para baixo. Passe ._1 para votos em forma de coração:
FastCommentsView(sdk: sdk, voteStyle: ._1)
| Estilo | Aparência |
|---|---|
._0 |
Botões de seta para cima/baixo com contagem líquida |
._1 |
Único botão de coração com contagem |
Callbacks de Evento
Use callbacks no estilo de modificador para lidar com interações do usuário:
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 é .name ou .avatar
print("Tapped \(userInfo.displayName)")
}
Aplicando um Tema
Passe um tema através do ambiente SwiftUI:
FastCommentsView(sdk: sdk)
.fastCommentsTheme(myTheme)
.task { try? await sdk.load() }
Ou defina-o diretamente no SDK:
sdk.theme = FastCommentsTheme.modern
Direção de Ordenação
sdk.defaultSortDirection = .nf // Mais recentes primeiro (padrão)
sdk.defaultSortDirection = .of // Mais antigos primeiro
sdk.defaultSortDirection = .mr // Mais relevantes
Chat ao Vivo 
LiveChatView fornece uma experiência de chat em tempo real com rolagem automática, separadores de data e um layout compacto. Ele configura automaticamente o SDK para ordenação do mais antigo para o mais recente e exibição ao vivo imediata.
struct ChatView: View {
@StateObject private var sdk: FastCommentsSDK = {
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "chat-room-1",
sso: ssoToken // SSO recomendado para que os usuários tenham nomes
)
return FastCommentsSDK(config: config)
}()
var body: some View {
LiveChatView(sdk: sdk)
.onCommentPosted { comment in
print("Sent: \(comment.commentHTML)")
}
.task {
try? await sdk.load()
}
}
}
LiveChatView suporta estes callbacks:
.onCommentPosted-- disparado quando o usuário envia uma mensagem.onCommentDeleted-- disparado quando uma mensagem é excluída.onUserClick-- disparado quando o nome ou avatar de um usuário é tocado
Feed Social 
O sistema de feed é um SDK separado (FastCommentsFeedSDK) com sua própria view.
Carregando e Exibindo o 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
// Apresentar folha de compartilhamento
}
.onUserClick { context, userInfo, source in
// Navegar para o perfil do usuário
}
.onMediaClick { mediaItem, index in
// Apresentar visualizador de imagem em tela cheia
}
.task {
try? await sdk.load()
}
}
}
A visualização do feed inclui pull-to-refresh e rolagem infinita automaticamente.
Criando Posts
Use FeedPostCreateView para apresentar um formulário de criação de post:
@State private var showCreatePost = false
// In your view body:
.sheet(isPresented: $showCreatePost) {
FeedPostCreateView(
sdk: sdk,
onPostCreated: { post in
showCreatePost = false
Task { try? await sdk.refresh() }
},
onCancelled: {
showCreatePost = false
}
)
}
Reagindo a Posts
O SDK lida com reações com atualizações otimistas:
try await sdk.reactPost(postId: post.id, reactionType: "l")
// Check reaction state
let hasLiked = sdk.hasUserReacted(postId: post.id, reactType: "l")
let likeCount = sdk.getLikeCount(postId: post.id)
Abrindo Comentários em um Post
Use CommentsSheet para exibir comentários de um post do feed. Ele cria internamente uma instância de FastCommentsSDK usando a config do feed SDK:
.sheet(item: $commentsPost) { post in
CommentsSheet(post: post, feedSDK: sdk, onUserClick: { context, userInfo, source in
// Lidar com clique do usuário
})
}
Nota: FeedPost deve conformar ao Identifiable para .sheet(item:). Adicione esta extensão:
extension FeedPost: @retroactive Identifiable {}
Filtragem do Feed por Tags
Implemente o protocolo TagSupplier para filtrar posts do feed por tags:
struct TeamTagSupplier: TagSupplier {
func getTags(currentUser: UserSessionInfo?) -> [String]? {
guard let user = currentUser else { return nil }
return ["team:\(user.id ?? "")", "public"]
}
}
sdk.tagSupplier = TeamTagSupplier()
Retorne nil para um feed global sem filtro.
Salvando e Restaurando o Estado do Feed
Preserve o estado de paginação durante eventos do ciclo de vida da view:
let state = sdk.savePaginationState()
// Later...
sdk.restorePaginationState(state)
Excluindo Posts
sdk.onPostDeleted = { postId in
print("Post \(postId) was deleted")
}
Temas 
Predefinições de Tema
Quatro predefinições integradas estão disponíveis:
// Padrões do sistema
sdk.theme = FastCommentsTheme.default
// Cartões com sombras e cantos grandes arredondados
sdk.theme = FastCommentsTheme.modern
// Plano, sem sombras, raio de canto pequeno, sem linhas de encadeamento
sdk.theme = FastCommentsTheme.minimal
// Define todas as cores de ação para uma única cor da marca
sdk.theme = FastCommentsTheme.allPrimary(.indigo)
Estilos de Exibição de Comentários
var theme = FastCommentsTheme()
theme.commentStyle = .flat // Lista plana com divisores (padrão)
theme.commentStyle = .card // Cartões arredondados com sombras
theme.commentStyle = .bubble // Estilo de balão de conversa
Cores
Todas as propriedades de cor são opcionais. Valores não definidos usarão os padrões sensíveis do sistema.
var theme = FastCommentsTheme()
// Cores da marca
theme.primaryColor = .indigo
theme.primaryLightColor = .indigo.opacity(0.6)
theme.primaryDarkColor = Color(red: 0.2, green: 0.1, blue: 0.5)
// Fundos
theme.commentBackgroundColor = Color(.secondarySystemGroupedBackground)
theme.containerBackgroundColor = Color(.systemGroupedBackground)
// Botões de ação
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)
// Links
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)
// Outros
theme.onlineIndicatorColor = .green
theme.separatorColor = Color(.separator)
theme.badgeBackgroundColor = .gray.opacity(0.2)
theme.threadLineColor = .indigo.opacity(0.15)
Tipografia
theme.commenterNameFont = .subheadline.weight(.bold)
theme.bodyFont = .body
theme.captionFont = .caption
theme.actionFont = .caption.weight(.medium)
Layout e Espaçamento
theme.cornerRadius = .large // .none, .small, .medium, .large
theme.commentSpacing = 4 // Pontos entre linhas de comentário
theme.nestingIndent = 20 // Pontos de indentação por nível de aninhamento
theme.avatarSize = 36 // Diâmetro do avatar para comentários raiz
theme.replyAvatarSize = 28 // Diâmetro do avatar para respostas aninhadas
Efeitos Visuais
theme.showShadows = true // Sombras sutis nos cartões
theme.showThreadLine = true // Linha vertical conectando respostas aninhadas
theme.animateVotes = true // Animação com efeito de mola nas mudanças de voto
Aplicando Temas
Duas abordagens:
// Via SwiftUI environment (recommended for view hierarchy)
FastCommentsView(sdk: sdk)
.fastCommentsTheme(theme)
// Directly on the SDK
sdk.theme = theme
Botões personalizados da barra de ferramentas 
Botões da Barra de Ferramentas de Comentários
Implemente o protocolo CustomToolbarButton para adicionar botões à barra de ferramentas do campo de entrada de comentários:
struct EmojiButton: CustomToolbarButton {
let id = "emoji"
let iconSystemName = "face.smiling" // nome do SF Symbol
let contentDescription = "Add Emoji"
let badgeText: String? = nil // Contador de badge opcional
func onClick(text: Binding<String>) {
text.wrappedValue += "\u{1F44D}"
}
// Sobrescritas opcionais (padrão true)
func isEnabled() -> Bool { true }
func isVisible() -> Bool { true }
}
Passe botões customizados ao criar a view:
FastCommentsView(
sdk: sdk,
customToolbarButtons: [EmojiButton(), CodeBlockButton()]
)
Ou adicione-os globalmente no SDK (aplica-se a todas as instâncias):
sdk.addGlobalCustomToolbarButton(EmojiButton())
sdk.removeGlobalCustomToolbarButton(id: "emoji")
sdk.clearGlobalCustomToolbarButtons()
Botões da Barra de Ferramentas do Feed
Implemente FeedCustomToolbarButton para o formulário de criação de post:
struct HashtagButton: FeedCustomToolbarButton {
let id = "hashtag"
let iconSystemName = "number"
let contentDescription = "Add Hashtag"
func onClick(content: Binding<String>) {
content.wrappedValue += "#"
}
}
Passe-os para a view de criação:
FeedPostCreateView(
sdk: sdk,
customToolbarButtons: [HashtagButton()],
onPostCreated: { _ in },
onCancelled: { }
)
Ou defina-os globalmente no SDK do feed:
sdk.globalFeedToolbarButtons = [HashtagButton()]
Moderação 
Ações disponíveis para todos os usuários
- Denunciar/Remover denúncia -- denunciar um comentário para revisão
try await sdk.flagComment(commentId: commentId)
try await sdk.unflagComment(commentId: commentId)
- Bloquear/Desbloquear -- ocultar todos os comentários de um usuário (por visualizador)
try await sdk.blockUser(commentId: commentId)
try await sdk.unblockUser(commentId: commentId)
Ações apenas para administradores
- Fixar/Desfixar -- fixar um comentário no topo da thread
try await sdk.pinComment(commentId: commentId)
try await sdk.unpinComment(commentId: commentId)
- Bloquear/Desbloquear -- impedir novas respostas a um comentário
try await sdk.lockComment(commentId: commentId)
try await sdk.unlockComment(commentId: commentId)
Todas as ações de moderação também estão disponíveis através do menu de contexto do comentário na interface. As ações de administrador aparecem apenas quando o usuário atual é um administrador do site (definido via SSO isAdmin flag ou configuração do painel).
Atualizações em Tempo Real 
Após chamar sdk.load(), o SDK inscreve-se automaticamente em eventos WebSocket para o urlId configurado. Os seguintes eventos são tratados:
- Novos comentários, edições e exclusões
- Votos (novos e removidos)
- Alterações de estado de pin, lock, flag e block
- Presença do usuário (entrada/saída)
- Abertura/fechamento de thread
- Concessões de badges
- Atualizações de configuração do servidor
Controlando a exibição ao vivo
Por padrão, novos comentários de outros usuários aparecem imediatamente:
sdk.showLiveRightAway = true // Padrão: mostrar instantaneamente
Defina isso como false para armazenar novos comentários atrás de um botão 'N novos comentários', permitindo que o usuário escolha quando revelá-los:
sdk.showLiveRightAway = false
Presença do usuário
Indicadores online/offline aparecem automaticamente nos avatares dos usuários quando o servidor habilita o rastreamento de presença. Nenhuma configuração adicional é necessária no cliente.
Paginação 
Page Size
// Comentários: padrão 30
sdk.pageSize = 50
// Feed: padrão 10
feedSDK.pageSize = 20
Loading More Comments
A IU exibe controles de paginação automaticamente. Você também pode acionar a paginação programaticamente:
// Carregar próxima página
try await sdk.loadMore()
// Carregar todos os restantes (desativado se >2000 comentários por motivos de desempenho)
try await sdk.loadAll()
// Verificar estado
sdk.hasMore // Se há mais páginas
sdk.shouldShowLoadAll()
sdk.getCountRemainingToShow()
Child Comment Pagination
As respostas aninhadas são carregadas sob demanda. Quando um usuário expande um tópico, os primeiros 5 comentários filhos são carregados. Um controle "carregar mais respostas" aparece se houver mais. Isso é tratado automaticamente pela IU.
Estado e Observabilidade 
Tanto FastCommentsSDK quanto FastCommentsFeedSDK são classes ObservableObject com propriedades @Published. Você pode observar essas propriedades nas suas views SwiftUI para atualizações reativas da UI.
Propriedades Publicadas do FastCommentsSDK
| Propriedade | Tipo | Descrição |
|---|---|---|
commentCountOnServer |
Int |
Contagem total de comentários no servidor |
newRootCommentCount |
Int |
Comentários novos em buffer (quando showLiveRightAway é false) |
currentUser |
UserSessionInfo? |
Usuário autenticado atual |
isSiteAdmin |
Bool |
Se o usuário atual é administrador do site |
isClosed |
Bool |
Se o tópico de comentários está fechado |
hasBillingIssue |
Bool |
Se há um problema de cobrança |
isLoading |
Bool |
Se uma requisição de rede está em andamento |
hasMore |
Bool |
Se existem mais páginas de comentários |
blockingErrorMessage |
String? |
Erro que impede o funcionamento da UI |
warningMessage |
String? |
Mensagem de aviso não bloqueante |
isDemo |
Bool |
Se está em modo de demonstração |
commentsVisible |
Bool |
Alterna a visibilidade dos comentários |
toolbarEnabled |
Bool |
Se a barra de ferramentas de formatação está exibida |
Propriedades Publicadas do FastCommentsFeedSDK
| Propriedade | Tipo | Descrição |
|---|---|---|
feedPosts |
[FeedPost] |
Posts do feed carregados atualmente |
hasMore |
Bool |
Se existem mais páginas |
currentUser |
UserSessionInfo? |
Usuário autenticado atual |
blockingErrorMessage |
String? |
Mensagem de erro bloqueante |
isLoading |
Bool |
Se uma requisição de rede está em andamento |
newPostsCount |
Int |
Número de novos posts desde o último carregamento |
Árvore de Comentários
A árvore de comentários é acessível via sdk.commentsTree:
// Lista plana de nós visíveis para renderização
sdk.commentsTree.visibleNodes
// Localiza um comentário pelo ID
sdk.commentsTree.commentsById["comment-id"]
Região da UE 
Para usar o datacenter da UE, defina o campo region na sua configuração:
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page",
region: "eu"
)
Isso direciona todas as requisições de API e conexões WebSocket para eu.fastcomments.com.
Limpeza 
Quando você terminar com uma instância do SDK (por exemplo, quando a view estiver sendo dispensada), chame cleanup() para fechar a conexão WebSocket e cancelar tarefas em segundo plano:
sdk.cleanup()
Para views gerenciadas pelo @StateObject do SwiftUI, isso normalmente é chamado em .onDisappear ou quando a view é desalocada.
Envio de imagens 
Comentários
let imageUrl = try await sdk.uploadImage(imageData: jpegData, filename: "photo.jpg")
Retorna a string de URL da imagem enviada.
Publicações do Feed
let mediaItem = try await feedSDK.uploadImage(imageData: jpegData, filename: "photo.jpg")
// Fazer upload de várias imagens em paralelo
let mediaItems = try await feedSDK.uploadImages(images: [
(jpegData1, "photo1.jpg"),
(jpegData2, "photo2.jpg")
])
Menções a usuários 
Pesquisar usuários para dar suporte ao autocompletar de @mention:
let results = try await sdk.searchUsers(query: "jan")
// Retorna [UserSearchResult] com userId, username, avatar, etc.
O CommentInputBar integrado lida com o autocompletar de @mention automaticamente.
Edição e exclusão de comentários 
Editar
try await sdk.editComment(commentId: commentId, newText: "Updated text")
O servidor renderiza novamente o HTML. O comentário local é atualizado automaticamente.
Excluir
try await sdk.deleteComment(commentId: commentId)
Ao excluir um comentário, seus descendentes também são removidos da árvore local.
Ambas as ações estão disponíveis através do menu de contexto do comentário na interface quando o usuário atual for o autor do comentário (ou um administrador do site).
Tratamento de erros 
Os métodos do SDK lançam FastCommentsError, que está em conformidade com LocalizedError:
do {
try await sdk.load()
} catch let error as FastCommentsError {
print(error.translatedError ?? error.reason ?? "Unknown error")
} catch {
print(error.localizedDescription)
}
Propriedades de FastCommentsError:
code-- código de erro da APIreason-- descrição do erro em inglêstranslatedError-- mensagem de erro localizada fornecida pelo servidor
Erros de bloqueio também são exibidos automaticamente via sdk.blockingErrorMessage, que as visualizações integradas exibem para o usuário.
Localização 
Passe um código de localidade na configuração para localizar as strings fornecidas pelo servidor:
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page",
locale: "fr_fr"
)
As strings da interface do usuário do lado do cliente utilizam a localização baseada em bundles do iOS.
Aplicativo de exemplo 
O repositório inclui um aplicativo de exemplo completo em ExampleApp/ com demonstrações de:
- Comentários encadeados com SSO e temas personalizados
- Feed social com criação de postagens e filtragem por tags
- Bate-papo ao vivo
- Fluxos SSO simples e seguros
- Botões personalizados na barra de ferramentas (comentários e feed)
Precisa de ajuda?
Se você encontrar algum problema ou tiver dúvidas sobre a biblioteca iOS, por favor:
Contribuindo
Contribuições são bem-vindas! Por favor visite o repositório do GitHub para as diretrizes de contribuição.