L’SDK Flutter di Hooky
La conversazione Hooky nella tua app Flutter: un’API Dart e un widget della bolla, costruiti sugli SDK nativi di Hooky. La conversazione stessa è quella degli SDK iOS (SwiftUI) e Android (Jetpack Compose): nativa, senza WebView, con i colori del tuo sito.
HookyBubble su Android, e la conversazione nativa su iPhone, in modalità scura.Requisiti
- Flutter 3.35 o successivo (Dart 3.9).
- Android 7.0 o successivo (
minSdk 24, il minimo di Flutter stesso), compilato concompileSdk 36. - iOS 15 o successivo.
- Solo Android e iOS: sul web e sul desktop, le chiamate non fanno nulla.
- Un account Hooky e un sito: la sua chiave pubblica è in Siti › Installa, la stessa del
data-site-keydella bolla web.
Installazione
Il pacchetto si installa dal suo repository GitHub, come dipendenza git. Nel tuo pubspec.yaml:
dependencies:
hooky_sdk:
git:
url: https://github.com/Defdjamel/hooky-flutter
ref: 1.0.0poi flutter pub get. Gli SDK nativi iOS e Android sono inclusi nel pacchetto: nient’altro da aggiungere, nessun altro repository.
iOS
- Il plugin funziona sia con Swift Package Manager (attivo per impostazione predefinita nelle versioni recenti di Flutter) sia con CocoaPods: compila l’SDK iOS che include, con il suo manifesto sulla privacy.
- Porta il target di distribuzione a iOS 15.0: in Xcode, target Runner › General › Minimum Deployments.
- Per proporre la fotocamera, aggiungi
NSCameraUsageDescriptionaios/Runner/Info.plist. Senza, l’opzione è semplicemente nascosta.
Android
Niente da dichiarare: l’SDK Android è incluso, con la sua schermata di conversazione, il suo FileProvider e l’autorizzazione INTERNET. Le sue dipendenze (AndroidX, Compose, OkHttp) arrivano da google() e mavenCentral(), già presenti nei progetti Flutter.
Il codice sorgente è sotto licenza MIT: github.com/Defdjamel/hooky-flutter.
Iniziare in 3 righe
import 'package:hooky_sdk/hooky_sdk.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
Hooky.configure('LA_TUA_CHIAVE_PUBBLICA'); // 1. all’avvio
runApp(const MiaApp());
}
Scaffold(
floatingActionButton: const HookyBubble(), // 2. la bolla fluttuante
…
);
FilledButton(onPressed: Hooky.open, child: const Text('Scrivici')); // 3. o il tuo pulsanteconfigure 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. I suoi parametri con nome: translation: false rimuove la traduzione dei messaggi del team (vedi Traduzione dei messaggi), apiUrl serve solo per fare test sul tuo server.
Tutte le chiamate restituiscono un Future e non generano mai errori: gli errori vengono scritti solo nella console, in debug. Prima di configure, identify, setAttributes e track aspettano, mentre open, close e reset non fanno nulla.
La bolla
HookyBubble somiglia alla bolla nativa di ogni piattaforma: un quadrato arrotondato con ombre morbide su iOS (60 punti), la scheda con bordo e ombra netta della bolla web su Android (64 dp). Prende il colore del sito, mostra un badge per i non letti e compare appena configure è stato chiamato.
// Come pulsante fluttuante dello Scaffold
Scaffold(floatingActionButton: const HookyBubble(), …)
// Ovunque, in uno Stack
Stack(children: [
const MiaSchermata(),
const Positioned(right: 20, bottom: 20, child: SafeArea(child: HookyBubble())),
])
// La tua azione, un’altra dimensione, uno stile imposto
HookyBubble(onPressed: () => analytics.log('chat'), size: 52, style: HookyBubbleStyle.material)Aprire e chiudere la conversazione
Hooky.open(); // a schermo intero: un foglio su iOS, una Activity su Android
Hooky.close(); // la richiudeLa conversazione è disegnata dall’SDK nativo: le pagine iOS e Android descrivono cosa fa (foto, PDF, bozza, errori).
Messaggi non letti
La bolla mostra già il suo badge. Per i tuoi pulsanti, Hooky.unreadCount è insieme un ValueListenable<int> e uno Stream<int> (il valore attuale, poi ogni modifica). Torna a 0 quando la conversazione si apre.
// Un badge su una scheda
ValueListenableBuilder<int>(
valueListenable: Hooky.unreadCount,
builder: (context, n, _) => Badge(isLabelVisible: n > 0, label: Text('$n'), child: const Icon(Icons.chat)),
)
// O come flusso
Hooky.unreadCount.listen((n) => print('$n non letti'));
final adesso = Hooky.unreadCount.value;Hooky.state (un ValueListenable<HookyState>) fornisce anche isConfigured, siteName, siteColor e sitePosition, per la tua interfaccia. Le risposte arrivano in diretta finché l’app è in primo piano; la versione 1.0.0 non invia notifiche push ai tuoi utenti.
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: user.nome,
email: user.email,
userId: user.id, // il tuo identificativo
attributes: {'piano': 'Pro', 'ordini': 3, 'newsletter': true},
);
// Più tardi: uniti ai precedenti
Hooky.setAttributes({'carrello': 49.9, 'coupon': null}); // null cancella una chiave
// All’uscita
Hooky.reset();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 più tardi. nameedemailsostituiscono quelli della conversazione (nullli cancella sul dispositivo);userId: nulllo lascia invariato.- Uno
userIddiverso da quello della conversazione significa un altro account sullo stesso dispositivo: la conversazione viene dimenticata, come conreset(). Il nuovo utente non vede la conversazione del precedente. Hooky.reset()chiude la conversazione e dimentica i messaggi e l’identità. Chiamalo all’uscita.
Le regole dei dati
| Campo | Regola |
|---|---|
| Dati liberi | Una Map piatta: 50 chiavi al massimo, 8 KB in tutto. Le nuove chiavi sostituiscono le vecchie, le altre restano. |
| Chiave | Da 1 a 64 caratteri: lettere, cifre, spazi, _, . e -. Altrimenti viene ignorata. |
| Valore | Una String (tagliata a 500 caratteri), un num o un bool. null cancella la chiave. Il resto viene scartato, con un avviso in debug. |
userId | 200 caratteri al massimo. |
name, email | Il 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', value: 49.9, properties: {'piano': 'pro', 'posti': 3, 'prova': false});value: un importo o una quantità, sommato nella scheda. Le proprietà sono piatte (String,num,bool).- Chiamato prima di
configure, l’evento aspetta (100 al massimo). 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.
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('LA_TUA_CHIAVE_PUBBLICA', translation: false).
Cosa invia l’SDK
Quello che invia la bolla web, e nient’altro: i messaggi e i file dell’utente, il nome, l’email, l’identificativo e i dati che fornisci, la lingua e il fuso orario del dispositivo, e il suo modello con la versione del sistema («iPhone 17 Pro · iOS 27.0», «Pixel 8 · Android 15»). Nessun identificativo pubblicitario né tracciamento.
- Ogni richiesta porta
X-Hooky-Client: hooky-flutter/1.0.0eX-Hooky-App: <bundle id o package> <version> (<build>): il tuo team vede che la conversazione arriva da «Flutter · com.example.app 1.0 (1)». - Il token della conversazione è conservato dall’SDK nativo: nel Portachiavi su iOS (solo questo dispositivo), in un file privato mai salvato nel backup su Android.
- Il plugin include un manifest della privacy iOS (
PrivacyInfo.xcprivacy) che non dichiara alcun tracciamento. - Per le tue schede negli store, i dati sono quelli degli SDK nativi: vedi la scheda App Store (pagina iOS) e la sezione Sicurezza dei dati di Google Play (pagina Android).
Lingua, modalità scura, accessibilità
- Lingua
- L’interfaccia esiste in francese, inglese, spagnolo, portoghese, italiano e tedesco. Segue la lingua del dispositivo, l’inglese per impostazione predefinita. La lingua parte con il primo messaggio, perché il tuo team risponda nella lingua giusta e all’ora giusta.
- Modalità scura
- La conversazione e la bolla seguono la modalità chiara o scura del dispositivo, con il colore del tuo sito.
- Accessibilità
- La bolla è un pulsante per gli screen reader («Apri la chat con …», e il numero di non letti); la conversazione nativa mantiene VoiceOver e Dynamic Type su iOS, TalkBack e la dimensione del testo su Android.
R8 e ProGuard
Niente da aggiungere su Android: l’SDK non usa la reflection e include le sue regole.
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-Cliente funziona anche quando il sito ha dichiarato i suoi domini. Non aggiungere nulla in Siti. - «the Hooky plugin is not available on this platform»
- Dopo aver aggiunto il pacchetto, riavvia completamente l’app (
flutter run): un hot reload non basta. Sul web e sul desktop, il plugin non esiste. - La compilazione iOS fallisce
- Controlla il target di distribuzione (iOS 15.0): Swift Package Manager e CocoaPods ne rifiutano uno più basso. Dopo aver cambiato la versione del pacchetto, esegui
flutter cleane poiflutter pub get. - La bolla resta con i colori predefiniti
- Controlla la chiave pubblica del sito (non la chiave segreta
hks_…, né una chiave APIhka_…), e la rete. - Offline
- Il messaggio mostra l’errore e resta nel campo;
identifyesetAttributesripartono più tardi. Gli eventitrackinviati offline vanno persi.
Cronologia delle versioni
- 1.0.0
- Prima versione:
Hooky.configure,identify(conuserIde dati liberi),setAttributes,open,close,track,reset,unreadCountestatein diretta, il widgetHookyBubble, la traduzione dei messaggi del team (translation), sugli SDK nativi iOS 1.0.0 e Android 1.0.0.