Vai al contenuto

L’SDK Android di Hooky

La conversazione Hooky, nativa nella tua app Android: scritta con Jetpack Compose (Material 3), senza WebView, con i colori del tuo sito. Funziona in un’app Compose come in un’app con viste XML, in Kotlin come in Java.

Una schermata di un’app Android con la bolla Hooky in basso a destra e un messaggio non letto. La conversazione Hooky su Android: una foto, un PDF ricevuto e un link.
La bolla con il suo badge dei non letti, e la conversazione con una foto e un PDF.

Requisiti

  • Android 6.0 o successivo (minSdk 23).
  • L’SDK è compilato con compileSdk 36 (Android 16): compila la tua app con la stessa versione o con una più recente.
  • Kotlin o Java. La tua app non deve per forza usare Compose: l’SDK lo porta con sé per la sua schermata.
  • Dipendenze: AndroidX (Activity, Core, Compose), le coroutine Kotlin e OkHttp. Nessuna libreria di immagini, di JSON o di analisi.
  • Un account Hooky e un sito: la sua chiave pubblica è in Siti › Installa, la stessa del data-site-key della bolla web.

Installazione

L’SDK è servito dal suo repository GitHub, come repository Maven (GitHub Pages). Aggiungilo al tuo progetto, in settings.gradle.kts:

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven("https://defdjamel.github.io/hooky-android")
    }
}

poi la dipendenza al modulo della tua app:

// app/build.gradle.kts
dependencies {
    implementation("com.heyhooky:hooky-android:1.0.0")
}

In Groovy: maven { url 'https://defdjamel.github.io/hooky-android' } e implementation 'com.heyhooky:hooky-android:1.0.0'. Le dipendenze dell’SDK (AndroidX, Compose, OkHttp, coroutine) arrivano da google() e mavenCentral(). Il codice sorgente è sotto licenza MIT: github.com/Defdjamel/hooky-android.

Iniziare in 3 righe

// 1. Una volta, all’avvio (Application.onCreate è il posto migliore)
Hooky.configure(context, "LA_TUA_CHIAVE_PUBBLICA")

// 2. La bolla già pronta, in un angolo della tua schermata (Compose)
HookyBubble(Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(20.dp))

// 3. O la conversazione dal tuo pulsante
Hooky.open(context)

configure carica il nome, il colore e il messaggio di benvenuto del sito, riprende la conversazione salvata e tiene aperta la connessione in diretta finché l’app è in primo piano.

class MiaApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Hooky.configure(this, "LA_TUA_CHIAVE_PUBBLICA")
    }
}
// AndroidManifest.xml: <application android:name=".MiaApp" …>

Tutte le chiamate avvengono sul thread principale e non generano mai errori. configure accetta anche translation = false, per rimuovere la traduzione dei messaggi del team (vedi Traduzione dei messaggi), e apiUrl, che serve solo per fare test sul tuo server.

La bolla

Un pulsante del colore del tuo sito (64 dp), con il logo Hooky e un badge per le risposte non ancora lette. Toccandolo si apre la conversazione. Compare appena l’aspetto del sito è caricato.

Jetpack Compose

Box(Modifier.fillMaxSize()) {
    MiaSchermata()
    HookyBubble(Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(20.dp))
}

// Con la tua azione
HookyBubble(onClick = { mostraAiuto = true })

Viste XML

<FrameLayout …>
    <!-- la tua schermata -->
    <com.heyhooky.sdk.HookyBubbleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="20dp" />
</FrameLayout>

L’activity che la mostra deve essere una AppCompatActivity o una ComponentActivity.

Aprire e chiudere la conversazione

Hooky.open(context)   // a schermo intero (una Activity), da qualsiasi Context
Hooky.close()         // la richiude

La schermata della conversazione, HookyActivity, è dichiarata dall’SDK: non devi aggiungere nulla al tuo manifest.

Messaggi non letti

La bolla mostra già il suo badge. Per i tuoi pulsanti, il numero di risposte del team non ancora viste si segue in diretta; torna a 0 quando la conversazione si apre.

// Compose: uno StateFlow<Int>
val nonLetti by Hooky.unreadCount.collectAsState()
BadgedBox(badge = { if (nonLetti > 0) Badge { Text("$nonLetti") } }) { Icon(Icons.Default.Email, null) }

// Viste o Java: un listener (il valore attuale, poi ogni modifica)
val ascolto: Closeable = Hooky.addUnreadCountListener { n -> badge.isVisible = n > 0 }
ascolto.close()   // per fermarlo

In Java:

Hooky.configure(this, "LA_TUA_CHIAVE_PUBBLICA");
Closeable ascolto = Hooky.addUnreadCountListener(n -> badge.setText(String.valueOf(n)));

Le risposte arrivano in diretta finché l’app è in primo piano; quando torna attiva, l’SDK recupera ciò che si è perso. La versione 1.0.0 non invia notifiche push ai tuoi utenti. Hooky.isConfigured e Hooky.VERSION completano l’API.

Identificare l’utente

La tua app sa chi ha effettuato l’accesso: dillo a Hooky. Nella scheda della conversazione, il tuo team legge il nome, l’email, il tuo identificativo dell’utente, il dispositivo e i dati che aggiungi. Con un’email, la conversazione non chiede più né il nome né l’email.

// Dopo l’accesso
Hooky.identify(
    name = "Lou",
    email = "lou@example.com",
    userId = "u_1042",                                  // il tuo identificativo
    attributes = mapOf("piano" to "Pro", "carrello" to 49.9, "beta" to true),
)

// Più tardi: uniti ai precedenti
Hooky.setAttributes(mapOf("carrello" to 12, "ultima_schermata" to "Pagamento"))
Hooky.setAttributes(mapOf("beta" to null))             // null cancella una chiave

// All’uscita
Hooky.reset()

In Java: Hooky.identify("Lou", "lou@example.com", "u_1042");, oppure con una Map<String, Object> di dati come quarto parametro.

Come funziona

  • Nessuna conversazione ancora: tutto resta in memoria (anche prima di configure) e parte con il primo messaggio. Dopo, ogni modifica parte subito, raggruppata (un solo invio per tutto ciò che cambia nello stesso secondo). Offline, riparte con il messaggio successivo o quando l’app torna in primo piano.
  • name ed email sostituiscono quelli della conversazione (null li cancella sul dispositivo); userId = null lo lascia invariato.
  • Lo userId viene conservato con il token della conversazione. Uno userId diverso significa un altro account sullo stesso dispositivo: la conversazione viene dimenticata, come con reset(). Il nuovo utente non vede la conversazione del precedente.
  • Hooky.reset() chiude la conversazione e dimentica i messaggi, l’identità e i dati. Chiamalo all’uscita.

Le regole dei dati

CampoRegola
Dati liberiUna Map piatta: 50 chiavi al massimo, 8 KB in tutto. Le nuove chiavi sostituiscono le vecchie, le altre restano.
ChiaveDa 1 a 64 caratteri: lettere, cifre, spazi, _, . e -. Altrimenti viene ignorata.
ValoreUn testo (tagliato a 500 caratteri), un numero o un booleano. null cancella la chiave. Liste e mappe vengono ignorate, gli altri oggetti inviati come testo.
userId200 caratteri al massimo.
name, emailIl nome: 100 caratteri al massimo. L’email: un indirizzo valido, altrimenti viene ignorata.

Hooky ripulisce ciò che supera i limiti, senza mai rifiutare il messaggio del tuo utente.

Questi dati sono dichiarativi: la chiave del sito è pubblica, e chiunque può usarla per inviare un nome, un’email o uno userId a sua scelta. Aiutano il tuo team a inquadrare la persona, non provano chi è. Non metterci mai segreti (password, token, numero di carta) e non usarli mai per concedere un accesso o agire su un account: verifica sempre dalla tua parte.

Statistiche

Conta quello che succede nella tua app, come Hooky.track sul web: le schede compaiono in Statistiche, insieme a quelle del sito. Chiamalo subito dopo che l’azione è andata a buon fine.

Hooky.track("iscrizione")
Hooky.track("ordine", 49.9, mapOf("piano" to "pro", "posti" to 3, "prova" to false))
  • Il secondo parametro, value: un importo o una quantità, sommato nella scheda. Le proprietà sono piatte (testi, numeri, booleani).
  • Chiama prima configure: prima, track non fa nulla. Gli errori sono silenziosi; offline, l’evento va perso.
  • Stesse regole del web (nome, 20 proprietà al massimo, limite): vedi Statistiche nella pagina.

Non inviare mai dati personali (email, nome, telefono) in un evento. Conta le azioni, non le persone.

Cosa fa la conversazione

  • Il primo messaggio, con nome ed email facoltativi (o quelli di identify), poi una conversazione come quella della bolla web: separatori dei giorni, nomi del team, link, emoji in grande, «Letto», «… sta scrivendo…», messaggi precedenti su richiesta.
  • Fino a 4 allegati per messaggio, 10 MB ciascuno, con una barra di avanzamento: foto dal selettore di sistema (nessuna autorizzazione da chiedere), dalla fotocamera (tramite l’app fotocamera del telefono) e PDF da File.
  • Le foto ricevute si aprono a schermo intero (pizzica o tocca due volte per lo zoom); i file nell’app che sa leggerli, o si condividono.
  • La bozza sopravvive alla chiusura della schermata e dell’app. La tastiera non copre mai il campo di testo.
  • Errori chiari: offline, troppi messaggi insieme, file troppo pesante o rifiutato.

Cosa aggiunge l’SDK alla tua app

  • L’autorizzazione INTERNET, e nessun’altra.
  • HookyActivity e un FileProvider (autorità <tuo.package>.hooky.fichiers, limitato alla cartella hooky/ della cache della tua app) per le foto della fotocamera e i file ricevuti.
  • Delle <queries> per le app che scattano foto o aprono i PDF (Android 11 e successivi).

Se la tua app dichiara lei stessa l’autorizzazione CAMERA, Android la richiede anche per aprire l’app fotocamera: in quel caso l’SDK la chiede prima.

Traduzione dei messaggi

Il tuo utente e il tuo team scrivono ognuno nella propria lingua, come con la bolla web (vedi Traduzione dei messaggi).

  • Sotto un messaggio del team scritto in una lingua diversa da quella della conversazione (quella del dispositivo), un link discreto Traduci. Una volta tradotto, il messaggio compare nella lingua dell’utente, con «Tradotto dall’inglese · Mostra l’originale» per tornare al testo di partenza.
  • Il pulsante di traduzione nell’intestazione propone Traduci sempre: i messaggi del team arrivano allora già tradotti. La scelta viene conservata sul dispositivo, per ogni chiave del sito.
  • Una traduzione non riuscita mostra un breve errore con Riprova. I messaggi dell’utente non vengono mai tradotti dalla sua parte; il tuo team ha il suo pulsante Traduci, nella dashboard e nell’app Hooky.
  • Si traduce solo il testo, non gli allegati. La traduzione è attiva per impostazione predefinita; per toglierla dalla tua app: Hooky.configure(context, "LA_TUA_CHIAVE_PUBBLICA", translation = false).

Cosa invia l’SDK

Quello che invia la bolla web, e nient’altro. Nessun identificativo pubblicitario, nessun identificativo del dispositivo, nessuna libreria di analisi. Per compilare la sezione Sicurezza dei dati della tua scheda Google Play:

DatoQuandoSicurezza dei dati
MessaggiQuando l’utente scriveMessaggi: Altri messaggi in-app
Foto e PDFQuando li allegaFoto e video: Foto; File e documenti
Nome ed emailSe li fornisce, o se li passi a identifyInformazioni personali: Nome, Indirizzo email
Il tuo userIdSe lo passi a identifyInformazioni personali: ID utente
Dati liberiQuello che passi a identify e setAttributesSecondo quello che ci metti
Eventi trackQuando li invii, senza identificativo della personaAttività nelle app: Altre azioni (analisi)
Dispositivo, lingua, fuso orario, appCon la conversazioneInformazioni tecniche per il tuo team (vedi sotto)
  • Questi dati servono al funzionamento dell’app (l’assistenza clienti), e le statistiche alla tua analisi. Sono criptati in transito (HTTPS e WebSocket sicuro). Hooky li tratta per tuo conto: nel senso di Google Play, non è una condivisione con terze parti.
  • Il dispositivo è leggibile: «Samsung SM-S918B · Android 15» (produttore, modello e versione di Android). La pagina della conversazione è android-app://<tuo.package>. Ogni richiesta porta X-Hooky-Client: hooky-android/1.0.0 e X-Hooky-App: <package> <versionName> (<versionCode>): il tuo team vede che la conversazione arriva da «Android · com.example.app 2.3.1 (231)».
  • Sul dispositivo: il token della conversazione (l’unica chiave dell’utente), lo userId e la bozza, per chiave del sito, in un file privato della tua app sotto noBackupFilesDir: mai salvato nel cloud né ripristinato su un altro dispositivo. Una traduzione invia solo l’identificativo del messaggio e la lingua della conversazione.
  • Hooky è responsabile del trattamento ai sensi del GDPR: vedi l’informativa sulla privacy. Resti responsabile della tua scheda: dichiara ciò che la tua app invia davvero.

Lingua, modalità scura, accessibilità

Lingua
L’interfaccia esiste in francese, inglese, spagnolo, portoghese, italiano e tedesco. Segue la lingua del dispositivo al momento di configure, l’inglese per impostazione predefinita. La lingua parte con il primo messaggio, perché il tuo team risponda nella lingua giusta e all’ora giusta (con il fuso orario).
Modalità scura
La conversazione e la bolla seguono il tema chiaro o scuro del sistema, con il colore del tuo sito. Niente da impostare.
Accessibilità
Etichette TalkBack su ogni controllo (la bolla: «Apri la chat con …», e il numero di non letti), dimensione del testo di sistema rispettata.

R8 e ProGuard

Niente da aggiungere. L’SDK non usa la reflection e include le sue regole: R8 può ridurre tutto nella tua build di produzione.

Risoluzione dei problemi

Il mio sito ha dichiarato i suoi indirizzi: l’app viene rifiutata?
No. Un’app non ha un indirizzo: si presenta con la sua intestazione X-Hooky-Client e funziona anche quando il sito ha dichiarato i suoi domini. Non aggiungere nulla in Siti.
La bolla non compare
Aspetta l’aspetto del sito. Verifica che configure venga chiamato, con la chiave pubblica del sito (non la chiave segreta hks_…, né una chiave API hka_…). Senza rete all’avvio, compare la prossima volta che l’app torna in primo piano.
Crash con HookyBubbleView
L’activity deve essere una AppCompatActivity o una ComponentActivity.
Offline
Il messaggio mostra l’errore e resta nel campo; identify e setAttributes ripartono più tardi. Gli eventi track inviati offline vanno persi.
Un altro utente vede la vecchia conversazione
Chiama Hooky.reset() all’uscita, e passa uno userId a identify: un identificativo diverso riparte da una conversazione vuota.

Cronologia delle versioni

1.0.0
Prima versione: configure, la bolla Compose e XML, open e close, identify (con userId e dati liberi), setAttributes, track, reset, i non letti in diretta (StateFlow e listener Java), foto e PDF, la traduzione dei messaggi del team, sei lingue, modalità scura e TalkBack.