Guida all'SDK Android

Questa pagina spiega come utilizzare l'SDK Android.

Accedi all'app di esempio

Per scaricare l'app di esempio per Android, fai clic su App di esempio per Android.

Per creare un'app di esempio utilizzando l'SDK per dispositivi mobili Android, devi disporre di quanto segue:

  • Chiave aziendale e secret aziendale del portale CCAI Platform.

  • Android 5.0 (livello API 21, Lollipop) o versioni successive.

  • Firebase Cloud Messaging o Google Cloud Messaging per la notifica push.

  • App di cui è stata eseguita la migrazione ad AndroidX.

Requisiti per l'upgrade dell'SDK Twilio

Richiede che l'SDK Twilio segua versioni specifiche se l'SDK Android è integrato utilizzando direttamente il nostro pacchetto, altrimenti questo può essere ignorato.

// Twilio VoIP SDK
api 'com.twilio:voice-android:6.1.1'
// Twilio Conversations SDK
api 'com.twilio:conversations-android:3.1.0'

Inoltre, le regole di Proguard sono già incluse nell'SDK Android per garantire che la libreria Twilio Programmable Voice non venga rimossa da ProGuard e possa essere utilizzata per la risoluzione dei problemi nel caso in cui ProGuard rimuova accidentalmente la libreria.

-keep class com.twilio.** { *; }
-keep class tvo.webrtc.** { *; }
-dontwarn tvo.webrtc.**
-keep class com.twilio.voice.** { *; }
-keepattributes InnerClasses

Per supportare le ultime versioni di Twilio, a partire dalla versione 0.34.0 dell'SDK Android, l'SDK non è più compatibile con i file binari delle applicazioni che hanno come target Java 7. Per utilizzare questa release e quelle future, gli sviluppatori devono eseguire l'upgrade delle loro applicazioni per scegliere come target Java 8. Vedi l'esempio di codice che segue:

android {
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
}

Ottieni la chiave e il secret dell'azienda

  1. Accedi ad Admin Portal utilizzando le credenziali di amministratore.

  2. Vai a Impostazioni > Impostazioni sviluppatore > Chiave aziendale e codice segreto.

  3. Recupera la chiave aziendale e il token segreto aziendale.

Installazione

Aggiungi il repository dell'SDK Android all'impostazione Gradle per il progetto principale.

build.gradle (Project)

allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url "https://sdk.ujet.co/android/"
        }
    }
}

build.gradle (modulo: app)

dependencies {
    // Replace x.y.z with latest version of CCAI Platform SDK
    def ujetSdkVersion = "x.y.z"
    implementation "co.ujet.android:ujet-android:$ujetSdkVersion"

    // CCAI Platform supports co-browse for Web SDK version 0.46.0 or
    // higher.
    // To use co-browse, declare the following dependency.
    implementation "co.ujet.android:cobrowse:$ujetVersion"
}

Configura le impostazioni aziendali

Inserisci le impostazioni della tua azienda come metadati nel file AndroidManifest.xml.

AndroidManifest.xml

<application>
    // ...
    <!-- Company Settings -->
    <meta-data android:name="co.ujet.android.subdomain" android:value="@string/ujet_subdomain"/>
    <meta-data android:name="co.ujet.android.companyKey" android:value="@string/ujet_company_key"/>
    <meta-data android:name="co.ujet.android.companyName" android:value="@string/ujet_company_name"/>
    // ...
</application>

strings.xml

<resources>
    <string name="ujet_subdomain">YOUR_SUBDOMAIN</string>
    <string name="ujet_company_key">YOUR_COMPANY_KEY</string>
    <string name="ujet_company_name">YOUR_COMPANY_NAME</string>
</resources>

Firma JWT

Per motivi di sicurezza, le informazioni di un utente finale devono essere firmate come JWT nel tuo server.

L'app di esempio contiene APIManager per i test e devi inserire UJET_COMPANY_SECRET in mock/APIManager.java. APIManager deve implementare un metodo che avvii la chiamata asincrona per firmare il token di autenticazione JWT che restituisce il token.

In produzione, devi implementare la procedura di firma sul tuo server.

public class APIManager {
    public static final String UJET_COMPANY_SECRET = "Please input your UJET_COMPANY_SECRET from Ujet developer admin page";
    // ...
}

Inizializza l'SDK

Inizializza l'SDK nel metodo onCreate della classe dell'app per Android.

public class ExampleApplication extends Application implements UjetRequestListener {
    @Override
    public void onCreate() {
        super.onCreate();

        Ujet.init(this);
    }
    // ...
}

Autenticazione dell'utente finale

L'utente finale è il consumatore che contatta il tuo team di assistenza clienti tramite l'applicazione.

Per autenticare l'utente finale nell'applicazione, introduciamo un meccanismo di firma JWT.

L'SDK Android chiede di firmare il payload quando richiede l'autenticazione. Se la firma va a buon fine, l'applicazione scambia il JWT firmato con il token di autenticazione dell'utente finale.

In ExampleApplication devi implementare l'interfaccia UjetRequestListener per la firma del token Auth e per i dati dei clienti.

public class ExampleApplication extends Application implements UjetRequestListener {
    @Override
    public void onCreate() {
        super.onCreate();

        Ujet.init(this);
    }

    @Override
    public void onSignPayloadRequest(Map<String, Object> payload, UjetPayloadType ujetPayloadType, UjetTokenCallback tokenCallback) {
        if (ujetPayloadType == UjetPayloadType.AuthToken) {

            // In production, you should implement this on your server.

            // The server must implement a method that initiates an asynchronous call
to sign and return a JWT auth token.
            APIManager.getHttpManager()
                .getAuthToken(payload, UjetPayloadType.AuthToken, new UjetTokenCallback() {
                    @Override
                    public void onSuccess(@Nullable final String authToken) {
                        tokenCallback.onToken(authToken);
                    }

                    @Override
                    public void onFailure(@Nullable final String authToken) {
                        tokenCallback.onError();
                    }
                });
        }
    }
}

Per saperne di più, consulta Autenticazione degli utenti finali.

Configura le notifiche push

Questa sezione descrive come attivare le notifiche push mobile.

Prepara Firebase

Devi preparare un progetto Firebase.

Se hai già un progetto, puoi utilizzare il tuo e saltare questo processo.

  1. Crea un progetto Firebase nella console Firebase.

  2. Scarica google-services.json da Impostazioni > GENERALE nella console Firebase.

  1. Recupera la chiave server da Impostazioni > CLOUD MESSAGING nella console Firebase.

Aggiungi una chiave del account di servizio

Per ricevere notifiche push, devi aggiungere una chiave dell'account di servizio alla tua app mobile. Per ottenere una chiave del account di servizio, consulta Autenticati con un service account.

Per aggiungere una chiave del account di servizio alla tua app mobile, segui questi passaggi:

  1. Nel portale della piattaforma CCAI, fai clic su Impostazioni > Impostazioni sviluppatore. Se non vedi il menu Impostazioni, fai clic su Menu.

  2. Vai al riquadro App mobile.

  3. Fai clic su Modifica accanto alla tua app. Viene visualizzata la finestra di dialogo Modifica app mobile.

  4. Nel campo Service account, inserisci la chiave del account di servizio, quindi fai clic su Salva.

Configurazione del client Android

  1. Copia google-services.json nella directory dell'app, ad esempio PROJECT_ROOT/app/google-services.json.

  2. Ottieni il token FCM utilizzando il seguente codice:

    FirebaseMessaging.getInstance().getToken()
        .addOnCompleteListener(task -> {
            if (!task.isSuccessful() || task.getResult() == null) {
                Log.w("FCM", "Couldn't get FCM token");
                return;
            }
    
            String token = task.getResult();
            Log.i("FCM", "FCM token: " + token);
        });
    

    Viene chiamato FirebaseMessagingService, che viene registrato nel file manifest se il token viene aggiornato. Per saperne di più, consulta Configura un'app client Firebase Cloud Messaging su Android.

    public class YourFirebaseMessagingService extends FirebaseMessagingService {
       /**
           * There are two scenarios when onNewToken is called:
           * 1) When a new token is generated on initial app startup
           * 2) Whenever an existing token is changed
           * Under #2, there are three scenarios when the existing token is changed:
           * A) App is restored to a new device
           * B) User uninstalls/re-installs the app
           * C) User clears app data
           */
       @Override
       public void onNewToken(String token) {
           Log.i("FCM", "FCM token updated: " + token);
       }
    }
    
  3. Implementa UjetRequestListener.onRequestPushToken nella classe Application. UjetRequestListener.onRequestPushToken deve restituire il token FCM/GCM.

    public class YourApplication extends Application implements UjetRequestListener {
        /**
            * Return your FCM/GCM token
            */
        @Override
        public String onRequestPushToken() {
            return yourToken(); // As shown in the previous step, you can get your token using FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> { })
        }
    }
    
  4. Gestisci la notifica push. Se vuoi che Contact Center AI Platform (CCAI Platform) gestisca l'elaborazione dei propri messaggi push, puoi passare i dati direttamente a UjetPushHandler.handle().

    • L'applicazione elabora solo i messaggi con il campo ujet_noti_type (o noti_type, per la compatibilità con le versioni precedenti) impostato.

    • In caso contrario, puoi scegliere di inviare solo i messaggi con ujet_noti_type a UjetPushHandler.handle() per l'elaborazione.

    Di seguito è riportato un esempio di messaggio di notifica push:

    {
        "call_id"           : 12345,
        "ujet_noti_type"    : "connect_call",
        "noti_type"         : "connect_call",
        "call_type"         : "ScheduledCall",
        "fail_reason"       : "none",
        "fail_details"      : "none"
    }
    

Gestisci messaggio FCM

public class YourFirebaseMessagingService extends FirebaseMessagingService {
    private UjetPushHandler ujetPushHandler;

    @Override
    public void onCreate() {
        super.onCreate();
        this.ujetPushHandler = new UjetPushHandler(this);
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        if (ujetPushHandler.handle(remoteMessage)) {
            // Handled by CCAI Platform

        } else {
            // Handle your push notification message in here
        }
    }
}

Gestisci messaggio GCM

public class YourGcmListenerService extends GcmListenerService {
    private UjetPushHandler ujetPushHandler;

    @Override
    public void onCreate() {
        super.onCreate();
        this.ujetPushHandler = new UjetPushHandler(this);
    }

    @Override
    public void onMessageReceived(String s, Bundle bundle) {
        if (ujetPushHandler.handle(bundle)) {
            // Handled by CCAI Platform

        } else {
            // Handle your message
        }
    }
}

Gestisci il messaggio GCM in GcmReceiver (metodo precedente)

public class YourGcmReceiver extends WakefulBroadcastReceiver {
    private UjetPushHandler ujetPushHandler;

    @Override
    public void onReceive(Context context, Intent intent) {
        ujetPushHandler = new UjetPushHandler(context);
        if (ujetPushHandler.handle(intent.getExtras())) {
            // Handled by CCAI Platform

        } else {
            // Handle your message
        }
    }
}

Avvia la richiesta

Aggiungi la riga seguente nel punto in cui vuoi avviare l'applicazione (senza parametri):

Ujet.start(new UjetStartOptions.Builder().build());

Puoi anche avviare l'SDK Android senza la schermata iniziale.

UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
        .setSkipSplashEnabled(true)
        .build();

Ujet.start(ujetStartOptions);

Puoi anche avviare l'SDK Android da un punto specifico del menu con questo tasto utilizzando un punto di accesso diretto:

String menuKey = "MENU_KEY";
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
        .setMenuKey(menuKey)
        .build();

Ujet.start(ujetStartOptions);

menuKey può essere creato con un punto di accesso diretto nel portale della piattaforma CCAI (con ruolo di amministratore).

  1. Vai a Impostazioni > Coda.

  2. Seleziona una coda dalla struttura del menu.

  3. Seleziona Crea punto di accesso diretto.

  4. Inserisci la chiave nel modulo di testo.

  5. Fai clic su Salva.

Puoi anche avviare l'SDK Android con un ID ticket specifico per passarlo al CRM. Questo ID ticket verrà aperto quando viene stabilita una chat o una chiamata.

String ticketId = "TICKET_ID";
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
        .setTicketId(ticketId)
        .build();

Ujet.start(ujetStartOptions);

Configurazione dell'SDK

Puoi configurare diverse opzioni prima di avviare l'SDK Android. Consulta la classe UjetOption. Le opzioni Numero di telefono di riserva e Sensibilità della rete descritte nella tabella seguente funzionano solo quando l'opzione Attiva fallback PSTN è attiva nel portale della piattaforma CCAI in Impostazioni > Impostazioni sviluppatore > MMA > Modifica. Quando l'opzione Abilita fallback PSTN è disattivata, non viene eseguito il fallback alla rete PSTN. CCAI Platform utilizza la sensibilità di rete predefinita (0,85) per controllare le connessioni di rete.

Opzione Descrizione Valore Valore predefinito
Livello di log Livello di log da stampare in Logcat. Numero intero. Lo stesso vale per il livello di log per il log di Android. (Min: 2, Max: 7) 5 (Log.Warn)
Lingua predefinita Il codice lingua predefinito. Stringa. Un codice lingua ISO 639. (ad es. en per l'inglese) null
Numero di telefono di riserva Il numero di telefono viene utilizzato come riserva quando internet non è disponibile o il numero di telefono rappresentativo dell'azienda non esiste nel portale di amministrazione. Stringa. Numero di telefono. null
Gestore delle eccezioni non rilevate abilitato Abilita il gestore delle eccezioni non rilevate. Se true, l'app gestisce tutte le eccezioni dell'SDK non rilevate in fase di runtime utilizzando Thread.setDefaultUncaughtExceptionHandler. Tuttavia, se la stessa eccezione si verifica due volte, l'app si arresta in modo anomalo. Valore booleano. true
Sensibilità della rete La sensibilità per il controllo dello stato della rete. Double tra 0 e 1, dove 0 è il valore meno sensibile e 1 è il più sensibile. Un valore pari a 1 utilizzerà sempre una chiamata PSTN come opzione di riserva. Se utilizzato, ti consigliamo di iniziare con un valore pari a .97. Il valore del portale in Impostazioni > Impostazioni sviluppatore > App mobile > Soglia numero di telefono di riserva sostituisce questo valore. 0.85
Modalità Buio attivata Attiva il tema della modalità Buio. Se true, l'SDK applica un tema della modalità Buio quando l'utente attiva la modalità Buio, altrimenti ignora l'azione. Valore booleano. false
Canale singolo abilitato Opzione di configurazione per mostrare o bypassare la schermata di selezione del canale per un singolo canale. Se true, l'SDK mostra una singola schermata di selezione del canale anziché selezionare automaticamente il canale, anche se nella coda del menu è attivato un solo canale. Valore booleano. false
Riduci automaticamente la visualizzazione della chiamata Opzione di configurazione per ridurre automaticamente l'UI della schermata di chiamata iniziale per impostazione predefinita o attendere che l'utente la riduca. Valore booleano. false
Bordo dell'icona dell'agente abilitato Opzione di configurazione per mostrare o rimuovere un bordo circolare intorno all'icona dell'agente. Valore booleano. false
Static Font Size In Picker View Opzione di configurazione per regolare o disattivare automaticamente le dimensioni del testo degli elementi del selettore. Valore booleano. false
Nascondi allegato multimediale nella chat Opzione di configurazione per mostrare o nascondere l'icona degli allegati multimediali nell'interfaccia utente della chat. Valore booleano. false
Ignora l'autorizzazione READ_PHONE_STATE Se impostato su true, l'SDK non richiede l'autorizzazione READ_PHONE_STATE. Se non vuoi utilizzare le chiamate IVR in-app, imposta questo flag su true per evitare di richiedere questa autorizzazione. Inoltre, la tua applicazione deve rimuovere esplicitamente l'autorizzazione android.permission.READ_PHONE_STATE per l'SDK CCAI Platform. Tieni presente che non consigliamo di impostare questa opzione su true, perché questa autorizzazione è necessaria per il funzionamento delle chiamate IVR in-app. Booleano false
Codice licenza Cobrowse.io (se applicabile) Opzione di configurazione per configurare la libreria Cobrowse.io. Puoi trovare il codice licenza di Cobrowse accedendo a https://cobrowse.io/dashboard/settings e andando alla sezione Codice licenza. Stringa null
Titolo dell'intestazione della chat personalizzata Opzione di configurazione per personalizzare il testo del titolo dell'intestazione della chat nell'interfaccia utente della chat. Stringa null
Personalizza le risposte rapide dell'interfaccia utente della chat Opzione di configurazione per personalizzare le risposte rapide dell'agente virtuale nella UI della chat. Le risposte rapide dell'agente virtuale sono raggruppate per impostazione predefinita, ma se vuoi visualizzarle singolarmente, puoi utilizzare questa opzione di configurazione per impostare QuickReplyButtonsStyle.INDIVIDUAL UjetStylesOptions QuickReplyButtonsStyle.GROUPED
Personalizza vari attributi dell'interfaccia utente della chat Opzione di configurazione per personalizzare vari attributi come il carattere, il colore di sfondo, l'icona e così via. UjetStylesOptions null
Nascondi barra di stato Opzione di configurazione per mostrare o nascondere la barra di stato. Se il valore è true, l'SDK nasconderà la barra di stato. Booleano false
Imposta la risorsa drawable della rotellina di caricamento Opzione di configurazione per personalizzare la visualizzazione dell'indicatore di caricamento nell'app. Se non è disponibile o è null, utilizziamo la visualizzazione di caricamento predefinita. Numero intero null
Orientamento orizzontale disattivato Disattiva l'orientamento orizzontale. Se il valore è true, l'orientamento orizzontale non viene applicato. Booleano false
Nascondi il pulsante in linea per avviare una nuova conversazione nella chat Opzione di configurazione per mostrare o nascondere il pulsante in linea per avviare una nuova conversazione nell'interfaccia utente della chat. Booleano false
Mostra il pulsante Salta CSAT Opzione di configurazione per mostrare o nascondere il pulsante Salta nella finestra di dialogo CSAT Booleano false
Blocca la chiusura della chat da parte dell'utente finale Opzione di configurazione per mostrare o nascondere il pulsante Termina chat nell'UI della chat Booleano false
Nascondi il download della trascrizione della chat Mostra o nascondi il pulsante per scaricare la trascrizione della chat nel menu Azioni della chat e nell'interfaccia utente della chat. Se aggiungi uno spazio alla stringa ujet_common_hide, il testo Hide scompare e viene visualizzata solo la Freccia indietro. Numero intero. Valori:

0 = Mostra ovunque

1 = Nascondi dal menu opzioni

2 = Nascondi dalla schermata post-chat

3 = Nascondi sia dal menu opzioni sia dalla schermata post-chat.

0

UjetOption.setBlockChatTerminationByEndUser

Disattiva le notifiche push a livello globale Se imposti UjetOption.setPushNotificationsAllowed su false, tutte le dipendenze delle notifiche push vengono ignorate e le notifiche push non vengono inviate agli utenti finali. Booleano true
Nascondi Prossima disponibilità Mostra o nascondi il messaggio Prossima disponibilità nella schermata di check-in della chat dopo l'orario di chiusura. Booleano false
Nascondi Ricomincia Mostra o nascondi il pulsante Ricomincia nella schermata di check-in della chat fuori orario. Booleano false
UjetOption ujetOption = new UjetOption.Builder()
        .setLogLevel(Log.INFO)
        .setDefaultLanguage("en")
        .setFallbackPhoneNumber("+18001112222")
        .setUncaughtExceptionHandlerEnabled(false)
        .setNetworkSensitivity(0)
        .setDarkModeEnabled(true)
        .setShowSingleChannelEnabled(true)
        .setAutoMinimizeCallView(true)
        .setShowAgentIconBorderEnabled(true)
        .setStaticFontSizeInPickerView(true)
        .setHideMediaAttachmentInChat(true)
        .setIgnoreReadPhoneStatePermission(true)
        .setCobrowseLicenseKey("COBROWSE_IO_LICENSE_KEY_HERE")
        .setCobrowseURL("COBROWSE_IO_API_URL_HERE")
        .setCustomChatHeaderTitle("CHAT_HEADER_TITLE_TEXT")
        .setUjetStylesOptions(
             new UjetStylesOptions.Builder()
            .setChatQuickReplyButtonsStyle(QuickReplyButtonsStyle.INDIVIDUAL)
            .setChatStyles(new ChatStyles(...)) // See `Content Cards Theme` item
            .build()            )
        .setBlockChatTerminationByEndUser(true)
        .setHideStatusBar(true)
        .setLoadingSpinnerDrawableRes(R.drawable.RESOURCE_NAME)
        .setLandscapeOrientationDisabled(true)
        .setShowCsatSkipButton(false)
        .setHideDownloadChatTranscript(0) // 0 to 3. 0 = Show everywhere, 1 = Hide from the options menu, 2 = Hide from the post chat screen, 3 = Hide from both the options menu and the post chat screen.
        .setPushNotificationsAllowed(true)
        .setHideNextAvailability(true)
        .setHideStartOver(true)
        .build();

//The following customizes various attributes in chat UI
ChatStyles chatStyles = new ChatStyles();
chatStyles.setBackButton(new BackButtonStyle(false, "ujet_agent_sample")); //customizes back button styles
chatStyles.setHeader(...); //customizes chat header styles
chatStyles.setAgentMessageBubbles(...); //customizes agent messages styles
chatStyles.setConsumerMessageBubbles(...); //customizes consumer messages styles
chatStyles.setSystemMessages(...); //customizes system messages styles
chatStyles.setEndChatButton(...); //customizes end chat button styles
chatStyles.setTimeStamps(...); //customizes timestamp styles
chatStyles.setUserInputBar(...); //customizes user input bar styles

UjetOption ujetOption = new UjetOption.Builder()
        .setUjetStylesOptions(
            new UjetStylesOptions.Builder()
            .setChatStyles(chatStyles)
            .build()
        )

//The following customizes various attributes in chat UI using json file. Store json file in assets folder
//and create a method to read json file contents and convert it into json string.
String chatStylesFromJson = parseJsonContentsFromAssetsFolder();

UjetOption ujetOption = new UjetOption.Builder()
        .setUjetStylesOptions(
            new UjetStylesOptions.Builder()
            .setChatStyles(chatStylesFromJson)
            .build()
        )

Autorizzazioni app

L'app richiede le seguenti autorizzazioni e le richiede all'utente quando necessario.

Autorizzazione Descrizione
VIDEOCAMERA Utilizzato per l'azione smart per scattare foto e registrare video
MICROPHONE Consente all'app di utilizzare la chiamata VoIP tramite Twilio
ARCHIVIAZIONE Consente all'app di salvare foto e video

Preferenze della lingua

L'SDK Android utilizzerà il seguente ordine di priorità per determinare la lingua.

  1. Lingua selezionata dalla schermata iniziale dell'app.

  2. Lingua predefinita selezionata utilizzando UjetOptions. Puoi impostare la lingua predefinita utilizzando setDefaultLanguage("en") in UjetOptions. Per maggiori dettagli, consulta la sezione Lingua predefinita nella configurazione dell'SDK.

  3. Verrà utilizzata la lingua selezionata nel dispositivo (tramite Impostazioni > Generali > Lingua), se supportata dall'app.

  4. Verrà utilizzato il dialetto più vicino alla lingua del dispositivo quando l'app non supporta la lingua del dispositivo, ma supporta il dialetto principale più vicino. Ad esempio, se l'utente ha selezionato lo spagnolo di Cuba come lingua sul dispositivo e l'app non supporta lo spagnolo di Cuba, ma supporta il dialetto principale spagnolo, verrà utilizzato lo spagnolo.

  5. L'inglese verrà utilizzato come lingua predefinita quando la lingua del dispositivo non è supportata dall'app.

Canale preferito

Il parametro Preferred Channel ti consente di indirizzare i consumatori direttamente a un canale specifico. L'utente finale salta quindi il passaggio di selezione del canale e avvia direttamente il contatto tramite il canale specificato nel parametro Preferred Channel.

UjetStartOptions.preferredChannel

Ujet.start(new)
UjetStartOptions.Builder().setPreferredChannel
(UjetPreferredChannel.UjetPreferredChannelChat).build());

Notifiche di eventi

Se vuoi, puoi impostare UjetEventListener per ricevere notifiche di eventi dell'applicazione.

I tipi di eventi disponibili e le relative descrizioni sono elencati qui.

Ujet.setUjetEventListener(new UjetEventListener() {
    @Override
    public void onEvent(UjetEventType eventType, HashMap<String, Object> eventData) {
        // eventType specifies the event type and eventData holds the data related to the event.
        // You can parse the eventData and here we are just logging the event type and event data.
        Log.i("CCAI Platform Event Type", eventType.getValue());

        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, Object> entry : eventData.entrySet()) {
            builder.append(entry.getKey()).append(" : ").append(entry.getValue()).append("\n");
        }

        Log.i("CCAI Platform Event Data", builder.toString());
    }
});
Tipo di evento Descrizione Dati inclusi nell'evento
EmailClicked Si attiva quando l'utente finale fa clic sul canale email. Dati del menu della coda
EmailSubmitted Si attiva quando l'utente finale invia un'email. Dati del menu della coda, dati inviati via email
SessionPaused Si attiva quando l'utente finale riduce a icona una sessione di chat o di chiamata. Dati di sessione
SessionResumed Si attiva quando l'utente finale torna a una sessione di chat o chiamata dal background. Dati di sessione
SessionCreated Si attiva quando viene creata una sessione di chat o di chiamata. Dati del menu della coda, dati della sessione creata
SessionEnded Si attiva quando termina una sessione di chat o di chiamata. Dati del menu della coda, dati della sessione creata, dati della sessione terminata
SdkTerminated Si attiva quando l'SDK viene chiuso, anche in modo imprevisto. Dati relativi alla terminazione dell'SDK
ContentCardClicked Si attiva quando si fa clic su una scheda di contenuti. Dati sui clic sulle schede dei contenuti
ContentCardButtonClicked Si attiva quando viene fatto clic su un pulsante della scheda di contenuti. Dati relativi ai clic sui pulsanti delle schede di contenuti
QuickReplyClicked Si attiva quando viene fatto clic su una risposta rapida. Dati sui clic sulle risposte rapide
MessageLinkClicked Si attiva quando viene fatto clic su un link. Dati sui clic sui link dei messaggi

Dati del menu della coda

Chiave Tipo Descrizione
event_name Stringa Contiene il nome dell'evento. Ad esempio, "Email selezionata".
application Stringa Contiene il nome dell'applicazione. Ad esempio, "Android".
app_id Stringa Contiene l'identificatore dell'app, che corrisponde a Context.getPackageName().
app_version Stringa Contiene il nome e il codice della versione dell'app. Ad esempio, "0.32.0 (123)".
sdk_version Stringa Contiene la versione dell'SDK. Ad esempio, "0.32.0".
timestamp Stringa Contiene il timestamp in UTC (nel formato aaaa-MM-gg'T'HH:mm:ss'Z').
device_model Stringa Contiene il modello del dispositivo dell'utente. Ad esempio, "Google Pixel".
device_version Stringa Contiene la versione del dispositivo dell'utente. Ad esempio, "10, Q, SDK 29".
company Stringa Contiene il nome dell'azienda. Ad esempio, "Azienda".
menu_name Stringa Contiene il nome del nodo foglia (l'ultima selezione di menu dell'utente). Ad esempio, "Sottomenu".
menu_id Stringa Contiene l'ID del nodo foglia (l'ultima selezione di menu dell'utente). Esempio: "123".
menu_path Stringa Contiene la sequenza completa dei menu selezionati dall'utente. Ad esempio, "Principale / Secondario / Sottomenu".
menu_key Stringa Contiene la chiave DAP ed è facoltativo. Ad esempio, "special_user_menu".

Dati inviati via email

Chiave Tipo Descrizione
has_attachments Booleano Restituisce True se l'email contiene allegati, altrimenti False.

Dati di sessione

Chiave Tipo Descrizione
event_name Stringa Contiene il nome dell'evento. Ad esempio, "Email selezionata".
type Stringa Contiene il tipo di sessione. Ad esempio, "chat" o "chiamata".
timestamp Stringa Contiene il timestamp in UTC (nel formato aaaa-MM-gg'T'HH:mm:ss'Z').

Dati della sessione creata

Chiave Tipo Descrizione
session_id Stringa Contiene l'ID sessione. Ad esempio, "100".
type Stringa Contiene il tipo di sessione. Ad esempio, "chat" o "chiamata".
end_user_identifier Stringa Contiene l'identificatore dell'utente finale. Ad esempio, "Mario".
messages_end_user Stringa Contiene il conteggio dei messaggi dell'utente finale ed è incluso solo per la sessione di chat. Esempio: "3".
messages_agent Stringa Contiene il conteggio dei messaggi dell'agente ed è incluso solo per la sessione di chat. Esempio: "3".

Dati della sessione terminata

Chiave Tipo Descrizione
agent_name Stringa Contiene il nome dell'agente. Ad esempio, "Mario".
ended_by Stringa Contiene i dettagli su chi ha terminato la sessione. I valori possibili sono "agent" (quando l'agente termina la sessione), "end_user" (quando l'utente finale termina la sessione), "timeout" (quando la chat scade) o "dismissed" (quando la chat viene ignorata).
duration Stringa Contiene la durata della sessione in secondi ed è incluso solo per la sessione di chiamata. Ad esempio, "30 secondi".

Dati relativi alla terminazione dell'SDK

Chiave Tipo Descrizione
event_name Stringa Contiene il nome dell'evento. Ad esempio, "Email selezionata".

Dati sui clic sulle schede dei contenuti

Chiave Tipo Descrizione
title string Il titolo della scheda.
title string Il titolo della scheda.
subtitle string Il sottotitolo della scheda.
body string La descrizione della scheda di contenuti.
link string Un link a una pagina web o un deep link. L'SDK utilizza le funzionalità del sistema operativo per aprirlo.
event_params dictionary Un dizionario contenente informazioni aggiuntive sull'evento di clic. L'SDK utilizza questo valore.

Dati relativi ai clic sui pulsanti delle schede di contenuti

Chiave Tipo Descrizione
title string Il titolo della scheda.
title string Il titolo della scheda.
link string Un link a una pagina web o un deep link. L'SDK utilizza le funzionalità del sistema operativo per aprirlo.
event_params dictionary Un dizionario contenente informazioni aggiuntive sull'evento di clic. L'SDK utilizza questo valore.

Dati sui clic sulle risposte rapide

Chiave Tipo Descrizione
title string Il titolo della scheda.
title string Il titolo della scheda.
link string Un link a una pagina web o un deep link. L'SDK utilizza le funzionalità del sistema operativo per aprirlo.
event_params dictionary Un dizionario contenente informazioni aggiuntive sull'evento di clic. L'SDK utilizza questo valore.

Dati sui clic sui link dei messaggi

Chiave Tipo Descrizione
event_name Stringa Contiene il nome dell'evento, ad esempio "Clic sul link del messaggio".
link Stringa Un link a una pagina web o un deep link. L'SDK utilizza le funzionalità del sistema operativo per aprirlo.

Invia dati personalizzati al tuo CRM

I dati personalizzati possono essere inviati agli agenti dell'assistenza e verranno visualizzati nel ticket di assistenza per la chiamata/chat in arrivo.

Esistono due metodi per inviare dati personalizzati:

  • Metodo firmato: firma dei dati predefinita con JWT.

  • Metodo non firmato: dati predefiniti con JSON normale (non consigliato).

Utilizzo del metodo firmato per inviare dati personalizzati

Per inviare dati personalizzati utilizzando il metodo firmato, implementa un metodo di firma.

Innanzitutto, recupera i dati personalizzati nell'app host, poi inviali al server per la firma. Sul tuo server, puoi aggiungere altri dati utilizzando un modulo definito. Firmali con il secret della tua azienda e poi restituiscili tramite JWT.

public class ExampleApplication extends Application implements UjetRequestListener {
    @Override
    public void onCreate() {
        super.onCreate();

        Ujet.init(this);
    }

    @Override
    public void onSignPayloadRequest(Map<String, Object> payload, UjetPayloadType ujetPayloadType, UjetTokenCallback tokenCallback) {
        // ...
        if (ujetPayloadType == UjetPayloadType.CustomData) {
            /**
                * These codes are for providing signed custom data.
                * Add some data from app, and add more sensitive data from server and sign it.
                */
            UjetCustomData appCustomData = new UjetCustomData();
            appCustomData.put("model", "Model", "MODEL1234");
            appCustomData.put("customer_id", "Customer ID", 12345);
            appCustomData.put("temperature", "Temperature", 70.5f);
            appCustomData.put("purchase_date", "Purchase Date", new Date());
            appCustomData.put("battery", "Battery", "52%");
            appCustomData.put("location", "Location", "San Francisco, CA, United States");
            appCustomData.putURL("dashboard_url", "Dashboard URL", "https://internal.dashboard.com/12345");

            payload.put("custom_data", appCustomData.getData());

            tokenCallback.onToken(APIManager.getHttpManager().getSignedCustomData(payload));
        }
        // ...
    }
}

Utilizzo del metodo non firmato per inviare dati personalizzati

Google consiglia di utilizzare il metodo firmato per inviare dati personalizzati nella tua applicazione. Per saperne di più, consulta Utilizzo del metodo firmato per inviare dati personalizzati.

Puoi inviare dati non firmati avviando l'SDK Android con le opzioni di avvio per impostare dati personalizzati utilizzando UjetStartOptions.Builder#setUnsignedCustomData e UjetTokenCallback deve chiamare onToken(null).

HashMap<String, Object> jsonData = new HashMap<>();
// Convert json string into hashmap object and store it in jsonData
UjetCustomData customData = new UjetCustomData();
customData.putObject("external_chat_transfer", jsonData); // Use `external_chat_transfer` key to send chat transcript data

UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
        .setUnsignedCustomData(customData)
        .build();

Ujet.start(ujetStartOptions);

Utilizzo di dati personalizzati non firmati per inviare la trascrizione della chat esterna

Puoi inviare la trascrizione della chat esterna alla piattaforma CCAI utilizzando dati personalizzati non firmati quando viene avviata. Utilizza UjetCustomData.putObject("external_chat_transfer", hashMapObject) per impostare i dati della trascrizione in formato JSON come segue:

HashMap<String, Object> jsonData = new HashMap<>();
// Convert json string into hashmap object and store it in jsonData
UjetCustomData customData = new UjetCustomData();
customData.putObject("external_chat_transfer", jsonData); // Use `external_chat_transfer` key to send chat transcript data

UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
        .setUnsignedCustomData(customData)
        .build();

Ujet.start(ujetStartOptions);

Formato JSON:

  • greeting_override: string

  • agent: dizionario

    • name: string

    • avatar: stringa [URL dell'avatar dell'agente, facoltativo]

  • transcript: array

    • sender: stringa ["end_user" o "agent"]

    • timestamp: string [ie "2021-03-15 12:00:00Z"]

    • content: array

      • type: stringa [uno tra text, media]

      • text: stringa [obbligatoria per il tipo di testo]

      • media: dizionario [obbligatorio per il tipo di media]

        • type: stringa [uno tra image, video]

        • url: stringa [URL pubblico che rimanda al file multimediale]

Esempio JSON:

{
    "greeting_override": "Please hold while we connect you with a human agent.",
    "agent": {
        "name": "Name",
        "avatar": "avatar url"
    },
    "transcript": [
        {
        "sender": "agent",
        "timestamp": "2021-03-15 12:00:15Z",
        "content": [
            {
            "type": "text",
            "text": "**Suggestions shown:**\n\n* Help with batch or delivery\n* Help with metrics or order feedback\n* Help with Instant Cashout"
            }
        ]
        },
        {
        "sender": "end_user",
        "timestamp": "2021-03-15 12:00:16Z",
        "content": [
            {
            "type": "text",
            "text": "Help with batch or delivery"
            }
        ]
        }
    ]
}

Puoi utilizzare Markdown per il tipo di testo. Sono supportati i seguenti formati:

  • Grassetto

  • Corsivo

  • Sottolineato

  • Interruzioni di riga

  • Elenco puntato

  • Elenco numerato

  • Link

Formato dei dati personalizzato

Questa sezione mostra il formato dei dati personalizzati che possono essere trasmessi nel JWT.

JSON codificato in JWT

Il JSON deve includere iat ed exp per convalidare il JWT. L'oggetto dei dati dei clienti è il valore della chiave custom_data.

{
    "iat" : 1537399656,
    "exp" : 1537400256,
    "custom_data" : {
        "location" : {
            "label" : "Location",
            "value" : "1000 Stockton St, San Francisco, CA, United States",
            "type" : "string"
        },
        "dashboard_url" : {
            "label" : "Dashboard URL",
            "value" : "http://(company_name)/dashboard/device_user_ID",
            "type" : "url"
        },
        "contact_date" : {
            "label" : "Contact Date",
            "value" : 1537399655992,
            "type" : "date"
        },
        "membership_number" : {
            "label" : "Membership Number",
            "value" : 62303,
            "type" : "number"
        },
        "model" : {
            "label" : "Model",
            "value" : "iPhone",
            "type" : "string"
        },
        "os_version" : {
            "label" : "OS Version",
            "value" : "12.0",
            "type" : "string"
        },
        "last_transaction_id" : {
            "label" : "Last Transaction ID",
            "value" : "243324DE-01A1-4F71-BABC-3572B77AC487",
            "type" : "string"
        },
        "battery" : {
            "label" : "Battery",
            "value" : "-100%",
            "type" : "string"
        },
        "bluetooth" : {
            "label" : "Bluetooth",
            "value" : "Bluetooth not supported",
            "type" : "string"
        },
        "wifi" : {
            "label" : "Wi-Fi",
            "value" : "Wi-Fi not connected",
            "type" : "string"
        },
        "ssn" : {
            "invisible_to_agent" : true,
            "label" : "Social Security Number",
            "value" : "102-186-1837",
            "type" : "string"
        }
    }
}

La chiave è un identificatore univoco dei dati. Il tipo è il tipo di valore.

  • string

    • Stringa JSON
  • number

    • numero intero, float
  • date

    • Formato timestamp Unix UTC con 13 cifre. (contiene millisecondi)
  • url

    • Formato URL HTTP

L'etichetta è il nome visualizzato nella pagina CRM.

Impedisci la visualizzazione di dati dei clienti

Puoi utilizzare la proprietà invisible_to_agent con un oggetto dati personalizzato per impedire la visualizzazione di dati personalizzati firmati o non firmati nell'adattatore dell'agente. Nell'esempio precedente, il numero di previdenza sociale dell'utente finale non viene mostrato nell'adattatore dell'agente perché "invisible_to_agent" : true è incluso nell'oggetto ssn.

Quando includi la proprietà "invisible_to_agent" : true con un oggetto dati personalizzato, puoi aspettarti il seguente comportamento:

Per saperne di più, consulta Visualizza i dati della sessione nell'adattatore dell'agente.

Proprietà dei dati riservate

Puoi inviare proprietà dei dati riservati a Contact Center AI Platform (CCAI Platform) come dati personalizzati firmati all'inizio di una sessione. Per saperne di più, consulta Inviare proprietà dei dati prenotati.

Di seguito è riportato un esempio di proprietà dei dati riservate nei dati personalizzati:

  {
    "custom_data": {
      "reserved_verified_customer": {
        "label": "Verified Customer",
        "value": false,
        "type": "boolean"
      },
      "reserved_bad_actor": {
        "label": "Bad Actor",
        "value": false,
        "type": "boolean"
      },
      "reserved_repeat_customer": {
        "label": "Repeat Customer",
        "value": false,
        "type": "boolean"
      }
    }
  }
  

Imposta ogni valore su true o false.

  • reserved_verified_customer: true se ritieni che questo utente finale sia un cliente legittimo.
  • reserved_bad_actor: true se ritieni che questo utente finale possa essere un malintenzionato.
  • reserved_repeat_customer: true se hai stabilito che questo utente finale ha già contattato il tuo contact center.

Fallback

Puoi utilizzare UjetErrorListener per il fallback degli errori imprevisti. Se non imposti questo listener o restituisci false, l'SDK Android gestirà l'errore.

L'SDK Android reindirizzerà gli utenti al tastierino con un numero di riserva solo quando l'opzione Attiva riserva PSTN è ON in Impostazioni > Impostazioni sviluppatore > MMA > Modifica popup, altrimenti esci dall'SDK.

Tipo di errore Codice di errore Trigger
NETWORK_ERROR 1 La rete non è disponibile. Tieni presente che questo errore non viene attivato quando la rete non è disponibile durante la chat, la chiamata o la schermata di valutazione.
AUTHENTICATION_ERROR 100 Si è verificato un errore imprevisto durante l'autenticazione.
AUTHENTICATION_JWT_ERROR 101 Si è verificato un errore imprevisto durante la convalida del JWT (ad es. errore di analisi).
VOIP_CONNECTION_ERROR 1000 Impossibile stabilire una connessione con il provider VoIP. Viene gestita tramite il callback dell'SDK VoIP.
VOIP_LIBRARY_NOT_FOUND 1001 È prevista la connessione di una chiamata tramite un provider VoIP, ma non è stato possibile trovarne uno. Ciò potrebbe accadere quando uno sviluppatore ha integrato l'SDK sbagliato o non ha aggiunto la libreria del provider VoIP alle sue dipendenze.
CHAT_LIBRARY_NOT_FOUND 1100 Si verifica quando non è possibile trovare la libreria di chat. Questo potrebbe accadere quando uno sviluppatore ha integrato l'SDK sbagliato o non ha aggiunto la libreria Twilio Chat alle sue dipendenze.
Ujet.setUjetEventListener(new UjetEventListener() {
    @Override
    public void onEvent(UjetEventType eventType, HashMap<String, Object> eventData) {
        // eventType specifies the event type and eventData holds the data related to the event.
        // You can parse the eventData and here we are just logging the event type and event data.
        Log.i("CCAI Platform Event Type", eventType.getValue());

        StringBuilder builder = new StringBuilder();
        for (Map.Entry<String, Object> entry : eventData.entrySet()) {
            builder.append(entry.getKey()).append(" : ").append(entry.getValue()).append("\n");
        }

        Log.i("CCAI Platform Event Data", builder.toString());
    }
});

Deep linking

Se vuoi utilizzare le azioni smart per una chiamata IVR (PSTN), devi configurare il deep linking nel tuo progetto.

Il formato del deep linking è un URI univoco, ad esempio:

ujet:// <package_name>/smartchannel.

Inoltre, devi impostare questo link o qualsiasi URL che reindirizzi a questo link nel portale di amministrazione (Impostazioni > Gestione delle operazioni > Attiva l'invio di SMS per scaricare l'app).

Dovrai aggiungere un filtro per intent contenente il deep link nel manifest.

<activity android:name="co.ujet.android.activity.UjetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:host="<package_name>"
                android:scheme="ujet"
                android:path="/smartchannel" />
    </intent-filter>
</activity>

Resilienza della chat live

Per migliorare l'uptime della chat live, configura la resilienza della chat live. In questo modo viene aggiunto un livello multimediale di messaggistica di riserva secondario che viene utilizzato se il livello multimediale principale non funziona.

Per aggiungere questa funzionalità, aggiungi la seguente dipendenza al file build.gradle a livello di modulo:

dependencies {
    implementation "co.ujet.android:chat_blue:VERSION"
}

Sostituisci VERSION con l'ultima versione dell'SDK UJET.

Modifiche al comportamento delle chiamate in arrivo

A partire dai dispositivi con versione Android 10, la chiamata in arrivo non verrà ricevuta direttamente dagli utenti finali quando l'app host è in background. Utilizziamo invece le notifiche per avvisare gli utenti delle chiamate in arrivo (anche quando lo smartphone è bloccato), offrendo loro la possibilità di accettare o rifiutare la chiamata.

Mostriamo le stesse notifiche quando l'app host è in background e lo schermo è bloccato prima dell'arrivo della chiamata in arrivo. Questa modifica del comportamento è finalizzata a rispettare le recenti limitazioni di Google relative all'avvio di attività quando l'app è in background. Il comportamento non viene influenzato quando l'app host è in primo piano o è in esecuzione su dispositivi con versioni precedenti ad Android 10.

Personalizza la sessione dell'SDK

Questa sezione descrive come personalizzare ulteriormente l'SDK.

Verifica se esiste già una sessione

Prima di avviare una sessione, utilizza il metodo descritto per verificare se esiste una sessione esistente o in corso. Se esiste, puoi chiedere all'utente finale di ripristinarlo o annullarlo.

Questo è particolarmente importante quando un utente viene modificato.

if (Ujet.getStatus() != UjetStatus.None) {
    // Display alert to cancel login or resume existing session
}

Disconnetti la sessione

Consulta il metodo se vuoi disconnettere una sessione in corso.

Prima di utilizzare questo metodo, assicurati di verificare se esiste una sessione di questo tipo utilizzando Ujet.getStatus(). Se vuoi eseguire un'azione dopo che l'SDK disconnette la sessione, ad esempio mostrare un messaggio o chiudere l'app, puoi utilizzare il callback di risposta onFinished() come descritto nella sezione successiva, altrimenti imposta il callback su null.

Ujet.disconnect(new UjetResponseCallback() {
    @Override
    public void onFinished() {
        // `onFinished()` is triggered after CCAI Platform disconnects the session.
        finish(); // Finishes the activity.
    }
});

Cancella i dati degli utenti finali dalla cache

È tua responsabilità svuotare la cache quando i dati relativi all'utente finale sono stati aggiornati o modificati dalla tua app. Ad esempio, se l'utente finale ha eseguito la disconnessione, richiama il metodo per rimuovere la cache per quell'utente in modo che venga avviata una nuova sessione per il nuovo utente finale al successivo avvio dell'SDK.

Ujet.clearUserData();

Nascondi l'SDK

Puoi nascondere l'SDK utilizzando il metodo Ujet.hideSDK(). Ad esempio, questo è utile quando l'SDK interferisce con l'interfaccia utente dell'app. Inizializza l'SDK utilizzando Ujet.init() prima di chiamare questo metodo. Ujet.init() restituisce true se l'SDK viene nascosto correttamente, altrimenti restituisce false. Dopo aver nascosto l'SDK, puoi avviarlo di nuovo utilizzando il metodo Ujet.start().

L'esempio seguente nasconde l'SDK:

Ujet.hideSDK();

Configura le icone dei link di deviazione esterna

Personalizza l'icona nel canale Link di deviazione esterno caricandola in una cartella drawable della tua app e assicurati di utilizzare lo stesso nome dell'icona durante la creazione del link di deviazione esterno nel portale della piattaforma CCAI in Impostazioni > Chat > Link di deviazione esterni > Visualizza link > Aggiungi link di deviazione.

Se il nome dell'icona nel portale della piattaforma CCAI non corrisponde all'icona caricata nell'app, l'SDK Android utilizzerà l'icona predefinita.

Configura l'icona Grazie dei sondaggi

Puoi personalizzare o sostituire l'icona nella pagina di ringraziamento del sondaggio caricando un'icona nella cartella drawable della tua app e utilizzando il nome file ujet_survey_thank_you_icon come nome dell'icona.

Personalizzazione della UI e delle stringhe

Questa sezione spiega come personalizzare stringhe, schede di contenuti, temi e intestazioni della chat.

Strings

Puoi personalizzare le stringhe utilizzate nell'applicazione eseguendo l'override delle chiavi per ogni stringa in strings.xml.

<resources>
    <!--Greeting title and message in splash screen-->
    <string name="ujet_greeting_title">Customer Support</string>
    <string name="ujet_greeting_description">runs on UJET</string>
</resources>

Configurazione sondaggio

Personalizzazione delle dimensioni del testo

Personalizza le dimensioni del testo del titolo, della descrizione e del selettore utilizzati nell'applicazione eseguendo l'override delle seguenti chiavi in dimens.xml.

Le dimensioni del testo personalizzabili sono descritte di seguito:

<resources>
    <!-- Don't include the following tags if you don't want to customize any of these keys and prefer to use the CCAI Platform default values instead. -->

    <!-- You can customize title text size by updating value here. -->
    <dimen name="ujet_title">10sp</dimen>

    <!-- You can customize description text size by updating value here. -->
    <dimen name="ujet_description">10sp</dimen>

    <!-- You can customize picker text size by updating value here. -->
    <dimen name="ujet_picker_item_text_size">10sp</dimen>
</resources>

Tema

Personalizza il tema e lo sfondo seguendo questi passaggi. Il passaggio 1 riguarda il tema e il passaggio 2 lo sfondo.

  1. Personalizza il tema eseguendo l'override delle chiavi per ogni elemento di stile in style.xml. Ad esempio,

    <!--Default style applies to both Light and Dark Mode Themes-->
    <style name="Ujet">
        <item name="ujet_typeFace">ProximaNova-Reg.otf</item>
        <item name="ujet_colorPrimary">@color/primaryDefault</item>
        <item name="ujet_colorPrimaryDark">@color/primaryDarkDefault</item>
        <item name="ujet_buttonRadius">10dp</item>
        <item name="ujet_companyLogo">@drawable/your_company_logo_default</item>
    
        <!-- You can customize the avatar in waiting UI before call or chat is connected by using the following option. -->
        <item name="ujet_defaultAvatar">@drawable/your_default_avatar</item>
    </style>
    
    <!--This is optional and can be used to update style in Light Mode Theme only-->
    <style name="Ujet.Light">
        <item name="ujet_typeFace">ProximaNova-Reg.otf</item>
        <item name="ujet_colorPrimary">@color/primaryLightMode</item>
        <item name="ujet_colorPrimaryDark">@color/primaryDarkLightMode</item>
        <item name="ujet_buttonRadius">10dp</item>
        <item name="ujet_companyLogo">@drawable/your_company_logo_light_mode</item>
    
        <!-- You can customize the avatar in waiting UI before call or chat is connected by using the following option. -->
        <item name="ujet_defaultAvatar">@drawable/your_default_avatar</item>
    </style>
    
    <!--This is optional and can be used to update style in Dark Mode Theme only-->
    <style name="Ujet.Dark">
        <item name="ujet_typeFace">ProximaNova-Reg.otf</item>
        <item name="ujet_colorPrimary">@color/primaryDarkMode</item>
        <item name="ujet_colorPrimaryDark">@color/primaryDarkForDarkMode</item>
        <item name="ujet_buttonRadius">10dp</item>
        <item name="ujet_companyLogo">@drawable/your_company_logo</item>
    
        <!-- You can customize the avatar in waiting UI before call or chat is connected by using the following option. -->
        <item name="ujet_defaultAvatar">@drawable/your_default_avatar</item>
    </style>
    
  2. Puoi personalizzare il colore di sfondo nell'applicazione eseguendo l'override delle chiavi per ogni elemento di stile in style.xml. Nello screenshot è mostrato il colore di sfondo personalizzabile.

    <style name="Ujet">
        <!-- Don't include the following tags if you don't want to customize any of these keys and prefer to use the CCAI Platform default values instead. -->
        <!-- You can customize light mode theme background color by updating value here in hex. -->
        <item name="ujet_colorBackground">@color/backgroundDefault</item>
        <!-- You can customize dark mode theme background color by updating value here in hex. -->
        <item name="ujet_colorBackgroundDark">@color/backgroundDefaultDark</item>
    </style>
    

Personalizza il titolo dell'intestazione della chat

Sono disponibili opzioni per personalizzare il testo del titolo dell'intestazione della chat nella chat della tua UI.

Puoi personalizzare il testo del titolo dell'intestazione della chat utilizzando le seguenti opzioni:

<item name="ujet_chatCustomHeaderTextColor">@color/chatHeaderTextLightMode</item>
<item name="ujet_chatCustomHeaderTextColowDark">@color/chatHeaderTextDarkMode</item>
<item name="ujet_chatCustomHeaderTextSize">16sp</item>
<item name="ujet_chatCustomHeaderTextStyle">bold</item>

Puoi personalizzare le risposte rapide dell'agente virtuale nell'interfaccia utente della chat utilizzando le seguenti opzioni:

<item name="ujet_colorChatQuickReplyButtonBackground">@color/chatQuickReplyButtonBackgroundLightMode</item>
<item name="ujet_colorChatQuickReplyButtonBackgroundDark">@color/chatQuickReplyButtonBackgroundDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedBackground">@color/chatQuickReplyButtonPressedBackgroundLightMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedBackgroundDark">@color/chatQuickReplyButtonPressedBackgroundDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonText">@color/chatQuickReplyButtonTextLightMode</item>
<item name="ujet_colorChatQuickReplyButtonTextDark">@color/chatQuickReplyButtonTextDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedText">@color/chatQuickReplyButtonPressedTextLightMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedTextDark">@color/chatQuickReplyButtonPressedTextDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonStroke">@color/chatQuickReplyButtonStrokeLightMode</item>
<item name="ujet_colorChatQuickReplyButtonStrokeDark">@color/chatQuickReplyButtonStrokeDarkMode</item>
<item name="ujet_chatQuickReplyButtonTypeFace">Kreon-Regular.ttf</item>
<item name="ujet_chatQuickReplyButtonStrokeWidth">3dp</item>
<item name="ujet_chatQuickReplyButtonCornerRadius">3dp</item>
<item name="ujet_chatQuickReplyButtonVerticalMargin">0dp</item>
<item name="ujet_chatQuickReplyButtonHorizontalPadding">10dp</item>
<item name="ujet_chatQuickReplyButtonVerticalPadding">1dp</item>
<item name="ujet_chatQuickReplyButtonAlignment">right</item>

Schede dei contenuti

Puoi aggiungere la personalizzazione delle schede di contenuti insieme alla personalizzazione della chat. Puoi farlo utilizzando il file JSON (fai riferimento a content_card property nel file app/src/main/assets/json/ujet_styles.json) o utilizzando la classe ContentCardStyle.

ChatStyles(
    ...
    contentCard = ContentCardStyle(
        backgroundColor = "color_reference",
        cornerRadius = 8,
        font = FontStyle(
            colorReference = "color_reference",
            size = 16,
            style = "bold|italic",
            family = "Roboto-Black.ttf",
        ),
        border = BorderStyle(
            color = "color_reference",
            width = 2,
        ),
        title = TextStyle(
            FontStyle(
                colorReference = "color_reference",
                size = 18,
                style = "bold|italic",
                family = "Roboto-Black.ttf",
            )
        ),
        subtitle = TextStyle(
            FontStyle(
                colorReference = "color_reference",
                size = 16,
                style = "bold|italic",
                family = "Roboto-Black.ttf",
            )
        ),
        body = TextStyle(
            FontStyle(
                colorReference = "color_reference",
                size = 16,
                style = "bold|italic",
                family = "Roboto-Black.ttf",
            )
        )
    )
)

Tema del modulo web

Puoi personalizzare la scheda del modulo web insieme alla personalizzazione della chat. Puoi farlo utilizzando il file JSON (fai riferimento alla proprietà form_card nel file app/src/main/assets/json/ujet_styles.json) o utilizzando la classe FormCardStyle.

ChatStyles(
    ...
    formCard = FormCardStyle(
        backgroundColor = "color_reference",
        cornerRadius = 8,
        font = FontStyle(
            colorReference = "color_reference",
            size = 16,
            style = "bold|italic",
            family = "Roboto-Black.ttf",
        ),
        border = BorderStyle(
            color = "color_reference",
            width = 2,
        ),
        title = TextStyle(
            FontStyle(
                colorReference = "color_reference",
                size = 18,
                style = "bold|italic",
                family = "Roboto-Black.ttf",
            )
        ),
        subtitle = TextStyle(
            FontStyle(
                colorReference = "color_reference",
                size = 16,
                style = "bold|italic",
                family = "Roboto-Black.ttf",
            )
        ),
        image = ImageStyle (
           height = 94,
        ),
    )
)

Sondaggi

Puoi modificare l'icona nella pagina di ringraziamento del sondaggio caricando un'icona nella cartella drawable dell'app.

Assicurati di utilizzare ujet_survey_thank_you_icon come nome dell'icona.

Per personalizzare la finestra di dialogo per il consenso alla condivisione schermo, implementa la classe astratta CoBrowseAlertProvider. Puoi utilizzare DialogFragment o AlertDialog per implementare la finestra di dialogo per il consenso personalizzata.

  • Se utilizzi DialogFragment, includi due pulsanti, uno per accettare e uno per negare il consenso. Passa un'istanza DialogFragment personalizzata al callback dialogInstance.

  • Se utilizzi AlertDialog, non passare l'istanza DialogFragment al callback dialogInstance.

Dopo aver ottenuto il consenso, trasmettilo all'SDK richiamando il callback consentStatus e trasmettendo il valore booleano di conseguenza.

Utilizza il seguente esempio di codice per implementare la finestra di dialogo per il consenso personalizzata:

class CoBrowseAlertProviderImpl : CoBrowseAlertProvider() {
    // You should only implement the cobrowse consent dialog methods that you want to customize and replace the default UI.
    override fun showCoBrowseSessionActivationRequestDialog(context: Context, dialogInstance: (DialogFragment) -> Unit, consentStatus: (Boolean) -> Unit) {

        // Using DialogFragment for customization
        val dialog = ConsentDialog.newInstance(
                title = context.getString(co.ujet.android.R.string.ujet_cobrowse_session_request_alert_title),
                message = context.getString(co.ujet.android.R.string.ujet_cobrowse_session_request_alert_message),
                positiveButton = context.getString(co.ujet.android.R.string.ujet_cobrowse_session_request_alert_button_allow),
                negativeButton = context.getString(co.ujet.android.R.string.ujet_cobrowse_session_request_alert_button_deny),
                cancelable = false,
                onNegativeClick = { consentStatus(false) }, // Pass consent value
                onPositiveClick = { consentStatus(true) }
            )
        // Pass DialogFragment instance
        dialogInstance(dialog)

        // Using AlertDialog for customization, if you use AlertDialog instead of DialogFragment then you don't need to call `dialogInstance(dialog)`, just pass consent value using `consentStatus()`
        val alertDialog = AlertDialog.Builder(context).apply {
           setTitle("Co-Browse Session Request") // Set dialog title
           setMessage("Allow the agent to co-browse with you?") // Set dialog message
           setPositiveButton("Allow"){dialogInterface, _ ->
               // Pass consent
               consentStatus(true)
           }
           setNegativeButton("Deny"){dialogInterface, _ ->
               // Pass consent
               consentStatus(false)
           }
        }.create()
        alertDialog.show()
    }

    override fun showCoBrowseSessionRemoteControlRequestDialog(context: Context, dialogInstance: (DialogFragment) -> Unit, consentStatus: (Boolean) -> Unit) {
        // Same as showCoBrowseSessionActivationRequestDialog
    }
    override fun showCoBrowseSessionFullDeviceRequestDialog(context: Context, dialogInstance: (DialogFragment) -> Unit, consentStatus: (Boolean) -> Unit) {
        // Same as showCoBrowseSessionActivationRequestDialog
    }
    override fun showCoBrowseConfirmationDialog(context: Context, dialogInstance: (DialogFragment) -> Unit, consentStatus: (Boolean) -> Unit) {
        // Same as showCoBrowseSessionActivationRequestDialog
    }
    override fun showStopCoBrowseConfirmationDialog(context: Context, dialogInstance: (DialogFragment) -> Unit, consentStatus: (Boolean) -> Unit) {
        // Same as showCoBrowseSessionActivationRequestDialog
    }
}
// A generic DialogFragment class
class ConsentDialog : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        // Implement your custom dialog UI here
    }
}

Passa questa implementazione all'SDK utilizzando la seguente API:

Ujet.setCoBrowseAlertProvider(CoBrowseAlertProviderImpl())

Configura i moduli web

Per configurare un modulo web, implementa il metodo ujetWebFormDidReceive dell'interfaccia UjetWebFormListener. Questo metodo riceve un evento (una mappa FormMessageReceived) come parametro, contenente informazioni relative al modulo. L'evento include la seguente struttura JSON:

{
    "type": "form_message_received",
    "smart_action_id": 1,
    "external_form_id": "external_foobar",
    "signature": "4868a7e1dcb5..."
}

Gestisci l'evento

Per gestire l'evento, segui questi passaggi:

  1. Estrai le informazioni pertinenti dalla mappa degli eventi (smart_action_id, external_form_id e signature).
  2. Genera un URI del modulo e una firma per i dati del modulo.
  3. Passa i dati del modulo all'SDK come mappa FormDataEvent utilizzando callback.onEvent(formDataEvent).
  4. Se si verifica un errore durante la generazione dell'URI o della firma, richiama il callback di errore utilizzando callback.onError().

La mappa (FormDataEvent) passata all'SDK deve avere la seguente struttura:

{
    "type": "form_data",
    "signature": "4868a7e1dcb5...",
    "data": {
        "external_form_id": "form_id",
        "smart_action_id": 1,
        "uri": "foobar"
    }
}

La firma (HMAC-SHA256) deve essere generata utilizzando i dati, firmati con una chiave segreta condivisa. Le chiavi degli oggetti dei dati devono essere ordinate in ordine alfabetico prima di generare le firme e gli stessi dati devono essere inviati all'SDK.

Il seguente esempio di codice mostra come implementare il listener del modulo web:

class UjetWebFormListenerImpl : UjetWebFormListener {
    override fun ujetWebFormDidReceive(event: Map<String, Any?>, callback: UjetWebFormCallback) {
        try {
            // Extract required fields from the event
            val smartActionId = event["smart_action_id"]
            val externalFormId = event["external_form_id"]
            val signature = event["signature"]
            // Simulate form URI generation (replace with actual implementation)
            val formUri = "generated_form_uri"
            // Prepare the data map, key should be alphabetically ordered
            val data = mapOf(
                "external_form_id" to externalFormId,
                "smart_action_id" to smartActionId,
                "uri" to formUri
            )
            // Generate the signature using `data`
            val generatedSignature = "generated_signature"
            // Create the FormDataEvent map
            val formDataEvent = mapOf(
                "type" to "form_data",
                "signature" to generatedSignature,
                "data" to data
            )
            // Pass the FormDataEvent to the SDK
            callback.onEvent(formDataEvent)
        } catch (e: Throwable) {
            // If any error occurs, invoke the error callback
            callback.onError()
        }
    }
}

Passa questa implementazione all'SDK utilizzando la seguente API:

Ujet.setUjetWebFormListener(UjetWebFormListenerImpl())

Risoluzione dei problemi

L'avvio di una nuova chat ha richiesto più di 30 secondi

Controlla se stai rispondendo a un metodo delegato di dati personalizzati. Devi restituire dati personalizzati validi su richiesta o semplicemente restituire null con un callback. Utilizza il seguente codice come riferimento.

    @Override
    public void onSignPayloadRequest(Map<String, Object> payload, UjetPayloadType ujetPayloadType, UjetTokenCallback tokenCallback) {
        if (ujetPayloadType == UjetPayloadType.CustomData) {
            tokenCallback.onToken(null);
        }
    }

Spiegazione della dichiarazione relativa alle norme

Se ricevi una notifica in Google Play Console che ti chiede di dichiarare una policy per i servizi o le autorizzazioni utilizzati dall'SDK Android, utilizza una delle seguenti spiegazioni.

Dichiara i servizi in primo piano utilizzati dall'SDK Android

Google ha introdotto i tipi di servizi in primo piano in Android 14 e ha reso obbligatorio specificarli all'avvio dei servizi in primo piano, in base a https://developer.android.com/about/versions/14/changes/fgs-types-required#remote-messaging. L'SDK Android di Contact Center AI Platform (CCAI Platform) utilizza i servizi in primo piano per avviare chat e chiamate, quindi abbiamo utilizzato il tipo di servizio FOREGROUND_SERVICE_REMOTE_MESSAGING per la chat, poiché si tratta di messaggi, e il tipo di servizio FOREGROUND_SERVICE_MICROPHONE per la chiamata. Senza questi tipi di servizi, l'SDK si arresta in modo anomalo durante l'avvio della chat o della chiamata a partire dai dispositivi con Android 14.

Dichiara l'autorizzazione per intent a schermo intero utilizzata dall'SDK Android

L'autorizzazione USE_FULL_SCREEN_INTENT è necessaria per mostrare la notifica push della chiamata in arrivo quando il dispositivo è bloccato. Avvisa l'utente finale e mostra l'avviso di chiamata a schermo intero (questo è il modo in cui l'app Telefono integrata notifica la chiamata in arrivo all'utente finale).

Supporto di Android 15

Per supportare Android 15, segui questi passaggi:

  1. Imposta compileSdkVersion = 35 e targetSdkVersion = 35 nel tuo build.gradle(:app).

  2. Assicurati che la versione del plug-in Android per Gradle (AGP) del tuo progetto sia 8.5.1 o successiva. Per ulteriori informazioni, consulta Aggiorna il pacchetto delle librerie condivise.

  3. Installa Java Development Kit (JDK) versione 17 o successive per creare progetti Android utilizzando AGP 8.0 o versioni successive. Per saperne di più, consulta JDK 17 richiesto per eseguire AGP 8.0.