Flutter
O pacote kavchat_flutter adiciona ao seu app Flutter o chat de atendimento baseado em roteiro: botões, reconhecimento de texto livre, formulário que abre um chamado, uma cópia do bot que funciona mesmo sem internet e exibição da direita para a esquerda em hebraico e árabe.
Instalação
dependencies:
kavchat_flutter: ^0.0.11O pacote inclui http, shared_preferences (cache da versão e conversa salva) e url_launcher (links nos roteiros). Para abrir links tel: no Android 11 ou superior, adicione ao AndroidManifest.xml uma entrada <queries> para o esquema tel e outra para https, para links de sites (consulte o README do url_launcher). No iOS, LSApplicationQueriesSchemes só é necessário se você chamar canLaunchUrl diretamente.
Uso
final kavchat = KavchatController(
publicKey: 'pk_live_...',
// apiBase: 'https://api.kavchat.com', // default
// locale: 'he', // default: device language if translated, else the bot language
onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
Scaffold(
floatingActionButton: KavchatLauncher(controller: kavchat), // hidden while the bot is off
);
// or open it yourself
showKavchat(context, kavchat);
// or embed the screen in your own route
KavchatChat(controller: kavchat, onClose: () => Navigator.pop(context));Crie o controlador uma única vez (por exemplo, em um State ou provider) e chame dispose() quando o componente que o mantém for descartado.
KavchatLauncher é um FloatingActionButton. Posicione-o com Scaffold.floatingActionButtonLocation. A configuração kavchat.settings?.position (start ou end) indica o lado escolhido no painel.
Quando uma mensagem ao lado do botão do chat é configurada no painel de administração (um balão de fala, texto curvado acima do botão, o próprio botão que se expande em uma cápsula e fala, ou uma linha que sobe do botão e mostra as primeiras opções do bot), KavchatLauncher a exibe após o intervalo definido, no máximo uma vez por dia. Tocar em uma opção da linha abre o chat com essa opção selecionada, como se ela tivesse sido escolhida dentro do chat. Fechar a mensagem ou abrir o chat oculta a mensagem até o dia seguinte. A mensagem não aparece enquanto o chat está aberto. Se a redução de movimento estiver ativada no dispositivo, a mensagem aparece sem movimento. Quando a opção "Não mostrar em celulares" está ativada, a mensagem aparece apenas em tablets (quando o lado mais curto da tela tem 600 pontos ou mais). No celular, a linha mostra até duas opções. KavchatLauncher(controller: kavchat, attention: false) desativa a exibição da mensagem.
Quando o ícone do botão no tema é um rosto, ele pisca de vez em quando enquanto o botão está em repouso. O rosto não pisca quando o chat está aberto, quando o app está em segundo plano ou quando a redução de movimento está ativada.
O bot não é exibido (o botão flutuante não aparece e KavchatChat mostra "Indisponível") quando a versão está com enabled: false: o bot está desativado, está disponível apenas para usuários de teste e o usuário não é um deles, ou a cota acabou (reason: 'quota').
Token de identidade
Para usuários conectados, assine um JWT curto no seu servidor com a chave secreta (nunca no app, consulte Identificação de usuários) e passe o token:
KavchatController(publicKey: 'pk_live_...', userToken: jwt, userName: 'Dana');
await kavchat.setUser(token: newJwt, name: 'Dana'); // after login
await kavchat.setUser(token: null); // after logoutO token é enviado no cabeçalho Authorization: Bearer <token> em cada chamada. Com um token, o formulário de contato não exige e-mail nem telefone, e o público de usuários de teste reconhece o usuário. setUser recarrega a versão, e um usuário diferente inicia uma nova conversa. Assim, uma conversa salva no dispositivo nunca passa para outra conta.
Links, telas e formulário de contato
- Botões do tipo
linkabrem comurl_launcher, apenas para endereçoshttps:etel:. Links dentro das mensagens do bot: apenashttps:. - Botões do tipo
screenchamamonScreen(screen, targetId). Sem essa função, eles não fazem nada. - O botão "Falar com a equipe" abre o formulário integrado (nome, e-mail, telefone, assunto e mensagem, com a conversa anexada) e, após o envio, mostra o número do chamado.
Lista de telas no editor
Declare uma única vez as telas que o app pode abrir em KavchatController(screens: ...). O SDK envia a lista ao Kavchat automaticamente, e o editor de roteiros oferece essas telas em uma lista suspensa com seus nomes, em vez de um campo de texto livre. O editor também solicita um identificador de item quando a tela precisa dele e avisa quando um botão leva a uma tela não declarada. Ninguém precisa digitar a lista de telas manualmente no painel.
final kavchat = KavchatController(
publicKey: 'pk_live_...',
screens: const [
KavchatScreen(id: 'orders', label: 'My orders'),
KavchatScreen(id: 'product', label: 'Product page', needsTarget: true), // the button carries a targetId
],
onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
// later, to replace the list: await kavchat.registerScreens([...]);idé o valor recebido poronScreen: letras latinas, números,_,.e-, até 40 caracteres.labelé o nome exibido ao administrador, até 60 caracteres. Até 100 telas. Entradas inválidas e identificadores duplicados são descartados.needsTarget: o botão também carrega um identificador de item (por exemplo, o identificador de um produto), recebido poronScreencomotargetId.- A lista é enviada em segundo plano depois que a versão é carregada, apenas quando há alterações ou uma vez por semana. Uma falha não é exibida, e o envio é tentado novamente na próxima inicialização. O usuário não vê nada.
- As telas registradas aparecem no painel em Bot, Configurações, "Telas do app", com as plataformas que informaram cada tela. Uma tela removida do app pode ser excluída ali.
RTL
O chat define sua própria Directionality de acordo com o idioma da interface: he e ar da direita para a esquerda; os demais, da esquerda para a direita. Isso não altera a direção do seu app. Cada balão também escolhe sua direção pela primeira letra com direção forte, para que conteúdos mistos sejam lidos corretamente. O idioma da interface e o do roteiro são independentes: um bot em inglês pode exibir botões em árabe, como "Voltar", quando locale: 'ar'.
Cores e identidade visual
As cores vêm da configuração primaryColor do bot. O texto sobre essa cor fica preto ou branco conforme o contraste WCAG, e uma cor clara demais é substituída por uma escura onde é usada como texto. Para alterar as cores:
KavchatLauncher(controller: kavchat, theme: KavchatThemeData.fromColor(const Color(0xFF0F766E)));
KavchatChat(controller: kavchat, theme: KavchatThemeData.fromHex('#0f766e').copyWith(background: Colors.white));O selo "Desenvolvido com Kavchat by maxsave" aparece em todos os planos, com um link para kavchat.com. No Premium, você pode ocultá-lo nas configurações do bot.
Chat com atendente
Não é preciso configurar nada para começar. Ao ativar o chat com atendentes no painel de administração, a opção aparece no chat do app exatamente como no widget do site.
- A opção: "Falar com um atendente" aparece antes de "Falar com a equipe", somente depois que o servidor confirma que há um atendente disponível. A disponibilidade é verificada novamente ao tocar no botão. Fora do horário de atendimento, ou quando todos os atendentes estão ocupados, aparece apenas o formulário de contato, com uma breve explicação e o horário de retorno da equipe, se for conhecido. Quando a cota mensal acaba, o formulário aparece sem explicação.
- A solicitação: visitantes deixam um e-mail ou telefone caso nenhum atendente fique disponível a tempo. Também podem adicionar um nome e uma mensagem inicial. Quando há mais de um departamento aberto, é preciso escolher um deles. Usuários identificados (
userToken) não precisam preencher dados de contato. Se nenhum atendente puder aceitar a conversa, o formulário de contato é aberto com os dados já informados. - A espera: aparece "Aguardando atendente" com uma contagem regressiva até o fim do tempo de espera que você definiu, ao lado dos botões "Deixar uma mensagem" e "Encerrar conversa". Já é possível escrever durante a espera. Quando o tempo acaba, a conversa vira um chamado automaticamente. São exibidos o número do chamado e uma explicação de que nenhum atendente ficou disponível a tempo.
- A conversa: nome do atendente, mensagens, indicador de digitação, transferência para outro atendente e encerramento da conversa. Tudo o que vem do servidor é exibido como texto simples, sem links.
- Em tempo real: conexão Server-Sent Events por uma resposta
httpem streaming. Se a conexão cair, o chat se reconecta com intervalos cada vez maiores e recupera tudo o que foi perdido. Assim, nenhuma mensagem se perde nem aparece duas vezes. Em redes que bloqueiam essa conexão e no Flutter Web, o chat usa consultas repetidas (long-poll). Cada mensagem tem um identificador, então uma nova tentativa não cria duplicatas. Uma mensagem que não foi enviada fica marcada e pode ser reenviada com um toque. - Segundo plano e reinicialização: quando o app vai para segundo plano (
paused,hidden), a conexão é encerrada. Quando ele volta (resumed), o chat recupera o que foi perdido. A credencial de acesso à conversa vale por até 12 horas ou até a conversa terminar e fica salva no armazenamento que você escolher. Assim, após reiniciar o app, uma conversa em andamento volta à tela. A credencial não é salva na URL nem registrada em log. - Sem notificações push nesta versão: as mensagens do atendente chegam apenas enquanto o app está aberto.
É recomendável guardar a credencial de acesso em armazenamento seguro (Keychain no iOS, Keystore no Android), por exemplo com flutter_secure_storage. Se secureStorage não for configurado, a credencial fica no mesmo armazenamento da conversa. Um botão próprio para falar com um atendente abre o formulário de solicitação quando há um atendente disponível. Se não houver, abre o formulário de contato com a explicação:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureKavchatStorage implements KavchatStorage {
final _s = const FlutterSecureStorage();
@override
Future<String?> read(String key) => _s.read(key: key);
@override
Future<void> write(String key, String value) => _s.write(key: key, value: value);
@override
Future<void> remove(String key) => _s.delete(key: key);
}
final kavchat = KavchatController(
publicKey: 'pk_live_...',
secureStorage: SecureKavchatStorage(),
livePage: 'checkout',
onLivePhase: (phase) => debugPrint('live chat: $phase'),
);
// your own button
FilledButton(onPressed: kavchat.openLive, child: const Text('Chat with us'));A mesma lógica, sem Flutter, está em kavchat_engine (KavchatClient, LiveSession e a máquina de estados compartilhada liveApplyEvent, liveLines e liveStatus, que passa pelos mesmos vetores de teste do widget do site).
Perguntas, condições e leads
Não é preciso configurar nada no app. Um roteiro pode pedir dados (nome, telefone, e-mail, número ou texto), decidir como continuar com base em condições (Premium) e enviar um lead. Tudo roda no dispositivo.
- Teclado adequado: quando o bot espera uma resposta, o campo de texto exibe um teclado de telefone, e-mail ou números, com preenchimento automático. Se a resposta for inválida, o bot explica o que falta e o campo fica destacado. Perguntas opcionais mostram um botão "Pular".
- Lead: quando há um texto de consentimento, aparecem os botões "Enviar" e "Não, obrigado". Se não houver conexão com a internet, o lead fica salvo no dispositivo e é enviado quando a conexão volta, sem duplicatas.
- Preenchimento prévio: as respostas que o usuário já deu preenchem o formulário de contato e o formulário de solicitação de atendimento e são anexadas ao chamado e à conversa com o atendente. Nome, e-mail e telefone do token de identidade contam como respostas conhecidas, e o bot não pergunta esses dados novamente.
- Tela atual:
livePagetambém indica a tela que as condições verificam e que é enviada com os leads. Quando o usuário muda de tela, chamesetPage('checkout').
Respostas de IA (Premium)
Não há nada para configurar no app. Quando as respostas de IA são ativadas no painel de administração (com sua própria chave de um provedor de IA), uma pergunta que nenhum roteiro responde é enviada ao Kavchat. Durante a espera, de até 20 segundos, o chat mostra que o bot está digitando. A resposta aparece como texto simples com uma pequena indicação "Resposta de IA" no idioma da interface. Abaixo dela aparecem um botão para um assunto relacionado, se houver, e o botão "Falar com a equipe".
Se não houver resposta, ou se a solicitação falhar, demorar demais ou ultrapassar o limite (10 respostas por conversa a cada 15 minutos), o chat exibe a mensagem habitual "Não encontrei uma resposta". A pergunta continua aparecendo no relatório de perguntas sem resposta, e as respostas de IA ficam na conversa salva como qualquer outra mensagem.
Uso offline e cache
A versão fica em cache com seu ETag (If-None-Match, 304). Quando não há internet ou ocorre um erro no servidor, a cópia salva é usada e uma mensagem informa isso. A conversa é salva por bot e restaurada por 24 horas, desde que a versão não tenha mudado. O percurso da conversa é informado ao servidor 2 segundos após a última ação e também quando o app vai para segundo plano.