O SDK Android do Hooky
A conversa do Hooky, nativa no seu app Android: escrita com Jetpack Compose (Material 3), sem WebView, com as cores do seu site. Ela funciona tanto em um app Compose quanto em um app com views XML, em Kotlin ou em Java.
Requisitos
- Android 6.0 ou mais recente (
minSdk 23). - O SDK é compilado com
compileSdk 36(Android 16): compile o seu app com a mesma versão ou uma mais recente. - Kotlin ou Java. O seu app não precisa usar Compose: o SDK o traz para a própria tela.
- Dependências: AndroidX (Activity, Core, Compose), as coroutines do Kotlin e o OkHttp. Nenhuma biblioteca de imagens, de JSON ou de análise.
- Uma conta Hooky e um site: a chave pública dele fica em Sites › Instalar, a mesma do
data-site-keydo balão na web.
Instalação
O SDK é servido a partir do repositório no GitHub, como repositório Maven (GitHub Pages). Adicione-o ao seu projeto, no settings.gradle.kts:
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://defdjamel.github.io/hooky-android")
}
}e depois a dependência ao módulo do seu app:
// app/build.gradle.kts
dependencies {
implementation("com.heyhooky:hooky-android:1.0.0")
}Em Groovy: maven { url 'https://defdjamel.github.io/hooky-android' } e implementation 'com.heyhooky:hooky-android:1.0.0'. As dependências do SDK (AndroidX, Compose, OkHttp, corrotinas) vêm do google() e do mavenCentral(). O código-fonte está sob licença MIT: github.com/Defdjamel/hooky-android.
Comece em 3 linhas
// 1. Uma vez, na inicialização (Application.onCreate é o melhor lugar)
Hooky.configure(context, "SUA_CHAVE_PUBLICA")
// 2. O balão pronto, em um canto da sua tela (Compose)
HookyBubble(Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(20.dp))
// 3. Ou a conversa a partir do seu próprio botão
Hooky.open(context)configure carrega o nome, a cor e a mensagem de boas-vindas do site, retoma a conversa salva e mantém a conexão ao vivo aberta enquanto o app está em primeiro plano.
class MeuApp : Application() {
override fun onCreate() {
super.onCreate()
Hooky.configure(this, "SUA_CHAVE_PUBLICA")
}
}
// AndroidManifest.xml: <application android:name=".MeuApp" …>Todas as chamadas são feitas na thread principal e nunca geram erro. configure também aceita translation = false, para remover a tradução das mensagens da equipe (veja Tradução das mensagens), e apiUrl, que só serve para testar com o seu próprio servidor.
O balão
Um botão com a cor do seu site (64 dp), o logo do Hooky e um contador para as respostas ainda não lidas. Um toque abre a conversa. Ele aparece assim que a aparência do site é carregada.
Jetpack Compose
Box(Modifier.fillMaxSize()) {
MinhaTela()
HookyBubble(Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(20.dp))
}
// Com a sua própria ação
HookyBubble(onClick = { mostrarAjuda = true })Views XML
<FrameLayout …>
<!-- a sua tela -->
<com.heyhooky.sdk.HookyBubbleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="20dp" />
</FrameLayout>A activity que o exibe precisa ser uma AppCompatActivity ou uma ComponentActivity.
Abrir e fechar a conversa
Hooky.open(context) // tela cheia (uma Activity), a partir de qualquer Context
Hooky.close() // fecha a conversaA tela de conversa, HookyActivity, é declarada pelo SDK: você não precisa adicionar nada ao seu manifesto.
Mensagens não lidas
O balão já mostra o próprio contador. Para os seus botões, o número de respostas da equipe ainda não vistas pode ser acompanhado ao vivo; ele volta a 0 quando a conversa é aberta.
// Compose: um StateFlow<Int>
val naoLidas by Hooky.unreadCount.collectAsState()
BadgedBox(badge = { if (naoLidas > 0) Badge { Text("$naoLidas") } }) { Icon(Icons.Default.Email, null) }
// Views ou Java: um listener (o valor atual, depois cada mudança)
val ouvinte: Closeable = Hooky.addUnreadCountListener { n -> badge.isVisible = n > 0 }
ouvinte.close() // para pararEm Java:
Hooky.configure(this, "SUA_CHAVE_PUBLICA");
Closeable ouvinte = Hooky.addUnreadCountListener(n -> badge.setText(String.valueOf(n)));As respostas chegam ao vivo enquanto o app está em primeiro plano; quando ele volta, o SDK recupera o que perdeu. A versão 1.0.0 não envia notificações push aos seus usuários. Hooky.isConfigured e Hooky.VERSION completam a API.
Identificar o usuário
O seu app sabe quem está logado: conte isso ao Hooky. Nos detalhes da conversa, a sua equipe vê o nome, o e-mail, o seu próprio identificador do usuário, o aparelho e os dados que você anexa. Com um e-mail, a conversa não pede mais nome nem e-mail.
// Depois do login
Hooky.identify(
name = "Lou",
email = "lou@example.com",
userId = "u_1042", // o seu próprio identificador
attributes = mapOf("plano" to "Pro", "carrinho" to 49.9, "beta" to true),
)
// Mais tarde: mesclados com os anteriores
Hooky.setAttributes(mapOf("carrinho" to 12, "ultima_tela" to "Pagamento"))
Hooky.setAttributes(mapOf("beta" to null)) // null apaga uma chave
// No logout
Hooky.reset()Em Java: Hooky.identify("Lou", "lou@example.com", "u_1042");, ou com um Map<String, Object> de dados como quarto parâmetro.
Como funciona
- Ainda sem conversa: tudo fica na memória (mesmo antes de
configure) e é enviado com a primeira mensagem. Depois, cada mudança é enviada na hora, agrupada (um único envio para tudo o que muda no mesmo segundo). Sem conexão, ela vai junto com a próxima mensagem ou quando o app voltar ao primeiro plano. nameeemailsubstituem os da conversa (nullos apaga no aparelho);userId = nullo deixa como está.- O
userIdé guardado com o token da conversa. UmuserIddiferente é outra conta no mesmo aparelho: a conversa é esquecida, como comreset(). O novo usuário não vê a conversa do anterior. Hooky.reset()fecha a conversa e esquece o histórico, a identidade e os dados. Chame no logout.
Regras dos dados
| Campo | Regra |
|---|---|
| Dados livres | Um Map sem aninhamento: 50 chaves no máximo, 8 KB no total. As chaves novas substituem as antigas, as outras ficam. |
| Chave | De 1 a 64 caracteres: letras, algarismos, espaços, _, . e -. Senão, é ignorada. |
| Valor | Um texto (cortado em 500 caracteres), um número ou um booleano. null apaga a chave. Listas e maps são ignorados, os outros objetos são enviados como texto. |
userId | 200 caracteres no máximo. |
name, email | O nome: 100 caracteres no máximo. O e-mail: um endereço válido, senão é ignorado. |
O Hooky limpa o que passar do limite, sem nunca recusar a mensagem do seu usuário.
Esses dados são declarativos: a chave do site é pública, então qualquer pessoa pode usá-la para enviar o nome, o e-mail ou o userId que quiser. Eles ajudam a sua equipe a situar a pessoa, não provam quem ela é. Nunca coloque um segredo neles (senha, token, número de cartão) e nunca use esses dados para liberar um acesso ou agir sobre uma conta: sempre confira do seu lado.
Estatísticas
Conte o que acontece no seu app, como com Hooky.track na web: os cards aparecem em Estatísticas, junto com os do site. Chame logo depois que a ação der certo.
Hooky.track("cadastro")
Hooky.track("pedido", 49.9, mapOf("plano" to "pro", "assentos" to 3, "teste" to false))- O segundo parâmetro,
value: um valor em dinheiro ou uma quantidade, somado no card. As propriedades não têm aninhamento (textos, números, booleanos). - Chame
configureprimeiro: antes disso,tracknão faz nada. As falhas são silenciosas; sem conexão, o evento se perde. - As mesmas regras da web (nome, 20 propriedades no máximo, limite): veja Estatísticas na página.
Nunca envie dados pessoais (e-mail, nome, telefone) em um evento. Conte ações, não pessoas.
O que a conversa faz
- A primeira mensagem, com nome e e-mail opcionais (ou os do
identify), depois uma conversa como a do balão na web: separadores de dias, nomes da equipe, links, emojis grandes, “Lida”, “… está digitando”, mensagens anteriores sob demanda. - Até 4 anexos por mensagem, 10 MB cada, com barra de progresso: fotos do seletor do sistema (nenhuma permissão a pedir), da câmera (pelo app de câmera do celular) e PDFs do app Arquivos.
- As fotos recebidas abrem em tela cheia (faça pinça ou toque duas vezes para dar zoom); os arquivos, no app que sabe abri-los, ou podem ser compartilhados.
- O rascunho sobrevive ao fechamento da tela e do app. O teclado nunca cobre o campo de texto.
- Erros claros: sem conexão, mensagens demais de uma vez, arquivo grande demais ou recusado.
O que o SDK adiciona ao seu app
- A permissão
INTERNET, e nenhuma outra. HookyActivitye umFileProvider(autoridade<seu.pacote>.hooky.fichiers, limitado à pastahooky/do cache do seu app) para as fotos da câmera e os arquivos recebidos.<queries>para os apps que tiram fotos ou abrem PDFs (Android 11 ou mais recente).
Se o seu app declarar ele mesmo a permissão CAMERA, o Android também a exige para abrir o app de câmera: nesse caso, o SDK a pede antes.
Tradução das mensagens
O seu usuário e a sua equipe escrevem cada um no seu idioma, como com o balão na web (veja Tradução das mensagens).
- Abaixo de uma mensagem da equipe escrita em outro idioma que o da conversa (o do aparelho), aparece um link discreto Traduzir. Traduzida, a mensagem aparece no idioma do usuário, com “Traduzido do inglês · Ver o original” para voltar ao texto original.
- O botão de tradução do cabeçalho oferece Traduzir sempre: as mensagens da equipe passam a chegar já traduzidas. A escolha fica salva no aparelho, para cada chave de site.
- Uma tradução que falha mostra um erro curto com Tentar de novo. As mensagens do usuário nunca são traduzidas do lado dele; a sua equipe tem o próprio botão Traduzir, no painel e no app Hooky.
- Só o texto é traduzido, não os anexos. A tradução vem ativada por padrão; para removê-la do seu app:
Hooky.configure(context, "SUA_CHAVE_PUBLICA", translation = false).
O que o SDK envia
O que o balão da web envia, e nada mais. Sem ID de publicidade, sem identificador do aparelho, sem biblioteca de análise. Para preencher a seção Segurança dos dados da sua página no Google Play:
| Dado | Quando | Segurança dos dados |
|---|---|---|
| Mensagens | Quando o usuário escreve | Mensagens: Outras mensagens no app |
| Fotos e PDFs | Quando ele os anexa | Fotos e vídeos: Fotos; Arquivos e documentos |
| Nome e e-mail | Se ele os informar, ou se você os passar para identify | Informações pessoais: Nome, Endereço de e-mail |
O seu userId | Se você o passar para identify | Informações pessoais: IDs de usuário |
| Dados livres | O que você passa para identify e setAttributes | Depende do que você coloca |
Eventos track | Quando você os envia, sem identificador de pessoa | Atividade no app: Outras ações (Análise) |
| Aparelho, idioma, fuso horário, app | Com a conversa | Informações técnicas para a sua equipe (veja abaixo) |
- Esses dados servem à Funcionalidade do app (o atendimento ao cliente), e as estatísticas à sua Análise. Eles são criptografados em trânsito (HTTPS e WebSocket seguro). O Hooky os trata em seu nome: no sentido do Google Play, isso não é um compartilhamento com terceiros.
- O aparelho é legível: “Samsung SM-S918B · Android 15” (fabricante, modelo e versão do Android). A página da conversa é
android-app://<seu.pacote>. Cada requisição levaX-Hooky-Client: hooky-android/1.0.0eX-Hooky-App: <package> <versionName> (<versionCode>): a sua equipe vê que a conversa vem de “Android · com.example.app 2.3.1 (231)”. - No aparelho: o token da conversa (a única chave do usuário), o
userIde o rascunho, por chave de site, em um arquivo privado do seu app emnoBackupFilesDir: nunca salvo em backup na nuvem nem restaurado em outro aparelho. Uma tradução só envia o identificador da mensagem e o idioma da conversa. - O Hooky é operador nos termos do RGPD (e da LGPD): veja a política de privacidade. A sua página na loja continua sendo responsabilidade sua: declare o que o seu app realmente envia.
Idioma, modo escuro, acessibilidade
- Idioma
- A interface existe em francês, inglês, espanhol, português, italiano e alemão. Ela segue o idioma do aparelho no momento do
configure, com inglês por padrão. O idioma vai com a primeira mensagem, para que a sua equipe responda no idioma certo e na hora certa (com o fuso horário). - Modo escuro
- A conversa e o balão seguem o tema claro ou escuro do sistema, com a cor do seu site. Nada a configurar.
- Acessibilidade
- Rótulos do TalkBack em cada controle (o balão: “Abrir o chat com …”, e o número de não lidas), tamanho do texto do sistema respeitado.
R8 e ProGuard
Nada a adicionar. O SDK não usa reflexão e traz as próprias regras: o R8 pode reduzir tudo no seu build de produção.
Solução de problemas
- O meu site cadastrou os endereços dele: o app é recusado?
- Não. Um app não tem endereço: ele se apresenta pelo cabeçalho
X-Hooky-Cliente funciona mesmo quando o site cadastrou os domínios dele. Não adicione nada em Sites. - O balão não aparece
- Ele espera a aparência do site. Confira se
configureé chamado, com a chave pública do site (não a chave secretahks_…, nem uma chave de APIhka_…). Sem rede na inicialização, ele aparece da próxima vez que o app voltar ao primeiro plano. - Falha com
HookyBubbleView - A activity precisa ser uma
AppCompatActivityou umaComponentActivity. - Sem conexão
- A mensagem mostra o erro e fica no campo;
identifyesetAttributessão enviados mais tarde. Os eventostrackenviados sem conexão se perdem. - Outro usuário vê a conversa antiga
- Chame
Hooky.reset()no logout e passe umuserIdparaidentify: um identificador diferente começa uma conversa do zero.
Histórico de versões
- 1.0.0
- Primeira versão:
configure, o balão Compose e XML,openeclose,identify(comuserIde dados livres),setAttributes,track,reset, as não lidas ao vivo (StateFlowe listener Java), fotos e PDFs, a tradução das mensagens da equipe, seis idiomas, modo escuro e TalkBack.