מדריך ל-Android SDK

בדף הזה מוסבר איך להשתמש ב-Android SDK.

גישה לאפליקציה לדוגמה

כדי להוריד את האפליקציה לדוגמה ל-Android, לוחצים על Android example app.

כדי ליצור אפליקציה לדוגמה באמצעות Android Mobile SDK, צריך:

  • מפתח החברה והסוד של החברה בפורטל CCAI Platform.

  • ‫Android 5.0 (רמת API‏ 21, ‏ Lollipop) ואילך.

  • העברת הודעות בענן ב-Firebase או Google Cloud Messaging לשליחת הודעת הפוש.

  • האפליקציה הועברה אל AndroidX.

דרישות לשדרוג של Twilio SDK

אם ערכת Android SDK משולבת באמצעות החבילה שלנו באופן ישיר, צריך להשתמש בגרסאות ספציפיות של Twilio SDK. אחרת, אפשר להתעלם מההודעה הזו.

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

בנוסף, כללי Proguard כבר כלולים ב-Android SDK כדי לוודא שספריית Twilio Programmable Voice לא תוסר על ידי ProGuard, וניתן להשתמש בה כדי לפתור בעיות במקרה ש-Proguard מסיר את הספרייה בטעות.

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

כדי לתמוך בגרסאות האחרונות של Twilio, החל מגרסת Android SDK‏ 0.34.0, ה-SDK כבר לא תואם בינארית לאפליקציות שמיועדות ל-Java 7. כדי להשתמש בגרסה הזו ובגרסאות עתידיות, המפתחים צריכים לשדרג את האפליקציות שלהם כך שיעדן יהיה Java 8. דוגמה לקוד:

android {
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
}

קבלת מפתח חברה וסוד חברה

  1. נכנסים לפורטל האדמין באמצעות פרטי הכניסה של האדמין.

  2. עוברים אל הגדרות > הגדרות למפתחים > מפתח החברה וקוד סודי.

  3. מאחזרים את מפתח החברה ואת הקוד הסודי של החברה.

התקנה

מוסיפים את מאגר Android SDK להגדרות Gradle של פרויקט השורש.

build.gradle (פרויקט)

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

build.gradle (module: 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"
}

הגדרת הגדרות החברה

מזינים את הגדרות החברה כמטא-נתונים בקובץ 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>

חתימה על JWT

מטעמי אבטחה, צריך לחתום על פרטי משתמש הקצה כ-JWT בשרת.

אפליקציית הדוגמה מכילה APIManager לבדיקה, ואתם צריכים להזין את UJET_COMPANY_SECRET ב-mock/APIManager.java. ב-APIManager צריך להטמיע שיטה שמתחילה קריאה אסינכרונית כדי לחתום על אסימון אימות JWT שמחזיר את האסימון.

בסביבת הייצור, צריך להטמיע את תהליך החתימה בשרת.

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

אתחול ה-SDK

מפעילים את ה-SDK ב-method‏ onCreate של מחלקת האפליקציה ב-Android.

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

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

אימות משתמשי קצה

משתמש הקצה הוא הצרכן שפונה לצוות תמיכת הלקוחות שלכם דרך האפליקציה.

כדי לאמת את משתמש הקצה באפליקציה, אנחנו מציגים מנגנון לחתימה על JWT.

חבילת Android SDK מבקשת לחתום על מטען הייעודי (payload) כשהיא צריכה אימות. אם החתימה תתבצע בהצלחה, האפליקציה תחליף את ה-JWT החתום באסימון האימות של משתמש הקצה.

ב-ExampleApplication צריך להטמיע את הממשק UjetRequestListener לחתימה על אסימון האימות ועל נתונים מותאמים אישית.

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();
                    }
                });
        }
    }
}

מידע נוסף זמין במאמר בנושא אימות משתמשי קצה.

הגדרת התראות

בקטע הזה מוסבר איך להפעיל התראות לנייד.

הכנה של Firebase

צריך להכין פרויקט Firebase.

אם כבר יש לכם פרויקט, אתם יכולים להשתמש בו ולדלג על התהליך הזה.

  1. יוצרים פרויקט Firebase במסוף Firebase.

  2. מורידים את הקובץ google-services.json מהקטע Settings > GENERAL במסוף Firebase.

  1. מקבלים את מפתח השרת דרך 'הגדרות' > 'העברת הודעות בענן' במסוף Firebase.

הוספת מפתח של חשבון שירות

כדי לקבל התראות פוש, צריך להוסיף מפתח של חשבון שירות לאפליקציה לנייד. מידע על קבלת מפתח של חשבון שירות מופיע במאמר אימות באמצעות חשבון שירות.

כדי להוסיף מפתח של חשבון שירות לאפליקציה לנייד:

  1. בפורטל של CCAI Platform, לוחצים על הגדרות > הגדרות למפתחים. אם תפריט ההגדרות לא מופיע, לוחצים על תפריט.

  2. עוברים לחלונית אפליקציות לנייד.

  3. לוחצים על עריכה לצד האפליקציה. מוצגת תיבת הדו-שיח עריכת אפליקציה לנייד.

  4. בשדה Service Account Field (שדה חשבון השירות), מזינים את המפתח של חשבון השירות ולוחצים על Save (שמירה).

הגדרה של לקוח Android

  1. מעתיקים את google-services.json לספריית האפליקציה, לדוגמה, PROJECT_ROOT/app/google-services.json.

  2. מקבלים את הטוקן FCM באמצעות הקוד הבא:

    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);
        });
    

    מתבצעת קריאה ל-FirebaseMessagingService, שרשומה בקובץ Manifest אם האסימון רענן. מידע נוסף זמין במאמר בנושא הגדרה של אפליקציית לקוח של Firebase Cloud Messaging ב-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. מטמיעים את UjetRequestListener.onRequestPushToken במחלקה Application. ‫UjetRequestListener.onRequestPushToken אמור להחזיר את האסימון 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. טיפול בהתראה. אם רוצים ש-Contact Center AI Platform (CCAI Platform) יטפל בעיבוד של הודעות פוש משלו, אפשר להעביר את הנתונים ישירות אל UjetPushHandler.handle().

    • האפליקציה מעבדת רק הודעות שבהן השדה ujet_noti_type (או noti_type, לצורך תאימות לאחור) מוגדר.

    • אחרת, אפשר לבחור לשלוח לעיבוד רק הודעות עם ujet_noti_type עד UjetPushHandler.handle().

    דוגמה להודעה של התראה:

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

טיפול בהודעת 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
        }
    }
}

טיפול בהודעה ב-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
        }
    }
}

טיפול בהודעת GCM ב-GcmReceiver (השיטה הישנה)

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
        }
    }
}

הגשת הבקשה

מוסיפים את השורה הבאה במקום שבו רוצים להתחיל את האפליקציה (בלי פרמטרים):

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

אפשר גם להפעיל את Android SDK בלי מסך הפתיחה.

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

Ujet.start(ujetStartOptions);

אפשר גם להשתמש במקש הזה כדי להתחיל את Android SDK מנקודה ספציפית בתפריט באמצעות נקודת גישה ישירה:

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

Ujet.start(ujetStartOptions);

אפשר ליצור את menuKey באמצעות נקודת גישה ישירה בפורטל של פלטפורמת CCAI (עם תפקיד אדמין).

  1. עוברים אל הגדרות > תור.

  2. בוחרים תור כלשהו ממבנה התפריט.

  3. מסמנים את התיבה Create direct access point (יצירת נקודת גישה ישירה).

  4. מזינים את המפתח בטופס הטקסט.

  5. לוחצים על Save.

אפשר גם להפעיל את Android SDK עם מספר כרטיס ספציפי כדי להעביר אותו למערכת לניהול קשרי לקוחות. מזהה הכרטיס הזה ייפתח כשהצ'אט או השיחה יתחברו.

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

Ujet.start(ujetStartOptions);

הגדרת SDK

אפשר להגדיר כמה אפשרויות לפני שמפעילים את Android SDK. אפשר לעיין בכיתה UjetOption. האפשרויות 'מספר טלפון לגיבוי' ו'רגישות הרשת' שמתוארות בטבלה הבאה פועלות רק אם המתג הפעלת גיבוי ל-PSTN מופעל בפורטל CCAI Platform בכתובת הגדרות > הגדרות למפתחים > MMA > עריכה. כשהמתג הפעלה של מעבר אוטומטי ל-PSTN מושבת, המערכת לא מבצעת מעבר אוטומטי ל-PSTN. פלטפורמת CCAI משתמשת ברגישות הרשת שמוגדרת כברירת מחדל (0.85) כדי לבדוק את חיבורי הרשת.

אפשרות תיאור ערך ערך ברירת המחדל
רמת הרישום ביומן רמת היומן להדפסה ב-Logcat. מספר שלם. כך גם לגבי רמת היומן של יומן Android. (מינימום: 2, מקסימום: 7) 5 (Log.Warn)
שפת ברירת המחדל קוד השפה שמוגדר כברירת מחדל. מחרוזת. קוד שפה לפי תקן ISO 639. (לדוגמה, en לאנגלית) null
מספר טלפון חלופי מספר הטלפון משמש כגיבוי אם האינטרנט לא זמין או אם מספר הטלפון של הנציג בחברה לא קיים בפורטל הניהול. מחרוזת. מספר טלפון. null
הופעל Uncaught Exception Handler מפעילים את הטיפול בחריגות שלא נתפסו. אם true, האפליקציה מטפלת בכל החריגים שלא נתפסו ב-SDK בזמן הריצה באמצעות Thread.setDefaultUncaughtExceptionHandler. עם זאת, אם אותה חריגה מתרחשת פעמיים, האפליקציה קורסת. בוליאני. true
רגישות הרשת רמת הרגישות לבדיקת מצב הרשת. הערך נע בין 0 לבין 1, כאשר 0 הוא הערך הכי פחות רגיש ו-1 הוא הערך הכי רגיש. ערך של 1 תמיד יחזור לשיחה ברשת PSTN. אם משתמשים בתג הזה, מומלץ להתחיל עם הערך .97. הערך שמופיע בפורטל בקטע הגדרות > הגדרות למפתחים > אפליקציות לנייד > סף מספר הטלפון של הגיבוי מבטל את הערך הזה. 0.85
מצב כהה מופעל מפעילים את העיצוב הכהה. אם הערך הוא true, ערכת ה-SDK מחילה עיצוב של מצב כהה כשהמשתמש מפעיל את המצב הכהה, אחרת היא מתעלמת מהפעולה. בוליאני. false
ערוץ יחיד מופעל אפשרות הגדרה להצגת מסך בחירת הערוץ או לדילוג עליו עבור ערוץ יחיד. אם true, ערכת ה-SDK מציגה מסך בחירה של ערוץ אחד במקום לבחור את הערוץ באופן אוטומטי, גם אם רק ערוץ אחד מופעל בתור של התפריט. בוליאני. false
הקטנה אוטומטית של תצוגת השיחה אפשרות הגדרה למזעור אוטומטי של ממשק המשתמש של מסך השיחה הראשוני כברירת מחדל, או להמתנה עד שהמשתמש ימזער אותו. בוליאני. false
הפעלת גבול לסמל הסוכן אפשרות להגדיר אם להציג או להסיר מסגרת עגולה מסביב לסמל של הנציג. בוליאני. false
גודל גופן קבוע בתצוגת הכלי לבחירת גודל הגופן אפשרות הגדרה להתאמה אוטומטית של גודל הטקסט בפריט בבוחר או להשבתה שלו. בוליאני. false
הסתרת קובץ מדיה מצורף בצ'אט אפשרות ההגדרה להצגה או להסתרה של סמל קובץ המדיה המצורף בממשק המשתמש של הצ'אט. בוליאני. false
התעלמות מההרשאה READ_PHONE_STATE אם הערך מוגדר כ-true, ה-SDK לא מבקש את ההרשאה READ_PHONE_STATE. אם אתם לא רוצים להשתמש בשיחות IVR בתוך האפליקציה, צריך להגדיר את הדגל הזה לערך true כדי להימנע מבקשת ההרשאה הזו. בנוסף, האפליקציה צריכה להסיר באופן מפורש את ההרשאה android.permission.READ_PHONE_STATE ל-CCAI Platform SDK. חשוב לזכור שאנחנו לא ממליצים להגדיר את ההרשאה הזו לערך true, כי היא נדרשת כדי ששיחות IVR באפליקציה יפעלו. בוליאני false
מפתח הרישיון של Cobrowse.io (אם רלוונטי) אפשרות הגדרה להגדרת הספרייה Cobrowse.io. כדי למצוא את מפתח הרישיון של Cobrowse, נכנסים לחשבון ב-https://cobrowse.io/dashboard/settings ועוברים לקטע מפתח רישיון. String null
כותרת מותאמת אישית של הצ'אט אפשרות הגדרה להתאמה אישית של הטקסט בכותרת של ממשק המשתמש של הצ'אט. String null
התאמה אישית של התגובות המהירות בממשק המשתמש של הצ'אט אפשרות הגדרה להתאמה אישית של תשובות מהירות של נציג וירטואלי בממשק המשתמש של הצ'אט. כברירת מחדל, התשובות המהירות של הנציג הווירטואלי מקובצות יחד, אבל אם רוצים להציג אותן בנפרד, אפשר להשתמש באפשרות ההגדרה הזו כדי להגדיר QuickReplyButtonsStyle.INDIVIDUAL UjetStylesOptions QuickReplyButtonsStyle.GROUPED
התאמה אישית של מאפיינים שונים בממשק המשתמש של הצ'אט אפשרות הגדרה להתאמה אישית של מאפיינים שונים כמו הגופן, צבע הרקע, הסמל וכו'. UjetStylesOptions null
הסתרת שורת הסטטוס אפשרות הגדרה להצגה או להסתרה של שורת המצב. אם הערך הוא true, ה-SDK יסתיר את סרגל הסטטוס. בוליאני false
הגדרת משאב drawable של סמל טעינה אפשרות להגדרת תצורה להתאמה אישית של תצוגת סמל הטעינה באפליקציה. אם האפשרות לא זמינה או שהיא מוגדרת כ-null, נעשה שימוש בתצוגת הטעינה שמוגדרת כברירת מחדל. מספר שלם null
הכיוון לרוחב מושבת השבתה של הכיוון לרוחב. אם הערך הוא true, המערכת לא תחיל את הכיוון לרוחב. בוליאני false
הסתרת הכפתור 'התחלת שיחה חדשה' בתוך הצ'אט אפשרות הגדרה להצגה או להסתרה של הלחצן 'התחלת שיחה חדשה' בתוך ממשק המשתמש של הצ'אט. בוליאני false
הצגת כפתור דילוג על שאלת שביעות רצון הלקוחות אפשרות הגדרה להצגה או להסתרה של לחצן הדילוג בתיבת הדו-שיח של CSAT בוליאני false
חסימת סיום הצ'אט על ידי משתמש קצה אפשרות הגדרה להצגה או להסתרה של לחצן סיום הצ'אט בממשק המשתמש של הצ'אט בוליאני false
הסתרת האפשרות להורדת תמליל הצ'אט הצגה או הסתרה של הלחצן להורדת תמליל הצ'אט בתפריט הפעולות של הצ'אט ובממשק המשתמש של הצ'אט. אם מוסיפים רווח למחרוזת ujet_common_hide, הטקסט Hide נעלם ומופיע רק החץ 'חזרה'. מספר שלם. ערכים:

0 = הצגת הבחירות בכל מקום

1 = הסתרה מתפריט האפשרויות

2 = הסתרה ממסך הצ'אט של הפוסט

3 = הסתרה גם מתפריט האפשרויות וגם ממסך הפוסט-צ'אט.

0

UjetOption.setBlockChatTerminationByEndUser

השבתת ההתראות ברמה הגלובלית הגדרה של UjetOption.setPushNotificationsAllowed לערך false עוקפת את כל התלות בהתראות פוש ומונעת את הגעתן של התראות פוש למשתמשי הקצה. בוליאני true
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)
        .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()
        )

הרשאות שניתנות לאפליקציות

האפליקציה דורשת את ההרשאות הבאות ומבקשת אותן מהמשתמשים כשנדרש.

הרשאה תיאור
מצלמה משמשת לפעולה חכמה של צילום תמונות והקלטת סרטונים
מיקרופון האפליקציה תוכל להשתמש בשיחות VoIP דרך Twilio
נפח אחסון מאפשרת לאפליקציה לשמור תמונות וסרטונים

העדפת שפה

ערכת Android SDK תשתמש בסדר העדיפויות הבא כדי לקבוע את השפה.

  1. השפה שנבחרה במסך הפתיחה באפליקציה.

  2. שפת ברירת המחדל שנבחרה באמצעות UjetOptions. אפשר להגדיר את שפת ברירת המחדל באמצעות setDefaultLanguage("en") ב-UjetOptions. פרטים נוספים זמינים בקטע 'שפת ברירת מחדל' במאמר בנושא הגדרת ה-SDK.

  3. אם האפליקציה תומכת בשפה שהוגדרה במכשיר (דרך הגדרות > כללי > שפה), היא תשתמש בה.

  4. הניב הכי קרוב לשפה של המכשיר ישמש את האפליקציה אם היא לא תומכת בשפה של המכשיר אבל תומכת בניב הכי קרוב שלה. לדוגמה, אם המשתמש בחר בספרדית קובנית כשפה במכשיר, והאפליקציה לא תומכת בספרדית קובנית אבל תומכת בניב האב של ספרדית, אז השפה שתשמש היא ספרדית.

  5. אם האפליקציה לא תומכת בשפה של המכשיר, אנגלית תשמש כשפת ברירת המחדל.

ערוץ מועדף

הפרמטר Preferred Channel מאפשר לכם להפנות צרכנים ישירות לערוץ ספציפי. משתמש הקצה מדלג על שלב בחירת הערוץ ויוצר קשר ישירות דרך הערוץ שצוין בפרמטר Preferred Channel.

UjetStartOptions.preferredChannel

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

עדכונים לגבי אירועים

אפשר להגדיר את UjetEventListener לקבלת התראות על אירועים באפליקציה.

סוגי האירועים הזמינים והתיאורים שלהם מפורטים כאן.

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());
    }
});
סוג אירוע תיאור הנתונים שנכללים באירוע
EmailClicked מופעל כשמשתמש הקצה לוחץ על ערוץ האימייל. נתונים בתפריט של רשימת ההמתנה
EmailSubmitted מופעל כשמשתמש הקצה שולח אימייל. נתונים בתפריט התור, נתונים שנשלחו באימייל
SessionPaused מופעל כשמשתמש הקצה מצמצם את הצ'אט או את הסשן של השיחה. נתוני ביקור
SessionResumed הטריגר מופעל כשמשתמש הקצה חוזר לסשן צ'אט או שיחה מהרקע. נתוני ביקור
SessionCreated מופעל כשנוצר סשן של צ'אט או שיחה. נתונים בתפריט התור, נתונים של סשן שנוצר
SessionEnded מופעל כששיחת צ'אט או שיחה מסתיימת. נתונים של תפריט התור, נתונים של סשן שנוצר, נתונים של סשן שהסתיים
SdkTerminated מופעל כשה-SDK נסגר, כולל כשהוא נסגר באופן בלתי צפוי. נתונים של SDK שהופסק השימוש בו
ContentCardClicked מופעל כשלוחצים על כרטיס תוכן. נתונים על קליקים בכרטיסי תוכן
ContentCardButtonClicked מופעל כשלוחצים על לחצן בכרטיס תוכן. נתונים על קליקים על כפתורים בכרטיסי תוכן
QuickReplyClicked מופעל כשלוחצים על תשובה מהירה. נתונים על הקלקות על תשובות מהירות
MessageLinkClicked מופעל כשלוחצים על קישור. נתונים של הפעלת קישור בהודעה

נתונים בתפריט של רשימת ההמתנה

מפתח סוג תיאור
event_name String מכיל את שם האירוע. לדוגמה, 'המשתמש לחץ על אימייל'.
application String כולל את שם האפליקציה. לדוגמה, 'Android'.
app_id String מכיל מזהה אפליקציה שזהה ל-Context.getPackageName().
app_version String מכיל את שם הגרסה ואת קוד הגרסה של האפליקציה. לדוגמה, ‎0.32.0 (123)‎.
sdk_version String מכיל את גרסת ה-SDK. לדוגמה, '0.32.0'.
timestamp String מכיל חותמת זמן ב-UTC (בפורמט yyyy-MM-dd'T'HH:mm:ss'Z').
device_model String מכיל את דגם המכשיר של המשתמש. לדוגמה, Google Pixel.
device_version String מכיל את גרסת המכשיר של המשתמש. לדוגמה, '10, Q, SDK 29'.
company String השדה מכיל את שם החברה. לדוגמה, 'חברה'.
menu_name String השם של צומת העלה (הבחירה האחרונה בתפריט של המשתמש). לדוגמה, "תפריט משנה".
menu_id String מכיל את המזהה של צומת העלה (הבחירה האחרונה של המשתמש בתפריט). לדוגמה, '123'.
menu_path String התווית מכילה את הרצף המלא של התפריטים שהמשתמש בחר. לדוגמה, 'תפריט ראשי / תפריט משני / תפריט משנה'.
menu_key String מכיל מפתח DAP והוא אופציונלי. לדוגמה, special_user_menu.

נתונים שנשלחו באימייל

מפתח סוג תיאור
has_attachments בוליאני הפונקציה מחזירה True אם לאימייל יש קבצים מצורפים, אחרת היא מחזירה False.

נתוני ביקור

מפתח סוג תיאור
event_name String מכיל את שם האירוע. לדוגמה, 'המשתמש לחץ על אימייל'.
type String מכיל את סוג הסשן. לדוגמה, 'צ'אט' או 'שיחה'.
timestamp String מכיל חותמת זמן ב-UTC (בפורמט yyyy-MM-dd'T'HH:mm:ss'Z').

נתונים של סשן שנוצר

מפתח סוג תיאור
session_id String מכיל מזהה סשן. לדוגמה, '100'.
type String מכיל את סוג הסשן. לדוגמה, 'צ'אט' או 'שיחה'.
end_user_identifier String מכיל מזהה של משתמש קצה. לדוגמה, 'John'.
messages_end_user String השדה הזה מכיל את מספר ההודעות של משתמשי הקצה, והוא נכלל רק בסשן צ'אט. לדוגמה, '3'.
messages_agent String מכיל את מספר ההודעות של הנציג, וכלול רק בסשן צ'אט. לדוגמה, '3'.

נתונים של סשן שהסתיים

מפתח סוג תיאור
agent_name String מכיל את שם הסוכן. לדוגמה, 'John'.
ended_by String כולל את הפרטים של מי שהפסיק את הסשן. הערכים האפשריים הם agent (כשהסוכן מסיים את הסשן), end_user (כשהמשתמש מסיים את הסשן), timeout (כשהשיחה מסתיימת בגלל חוסר פעילות) או dismissed (כשהשיחה נסגרת).
duration String המאפיין מכיל את משך הסשן בשניות, והוא נכלל רק בסשן שיחה. לדוגמה, "30 seconds".

נתונים של SDK שהופסק השימוש בו

מפתח סוג תיאור
event_name String מכיל את שם האירוע. לדוגמה, 'המשתמש לחץ על אימייל'.

נתונים של קליקים על כרטיסי תוכן

מפתח סוג תיאור
title מחרוזת כותרת הכרטיס.
title מחרוזת כותרת הכרטיס.
subtitle מחרוזת כותרת המשנה של הכרטיס.
body מחרוזת התיאור של כרטיס התוכן.
link מחרוזת קישור לדף אינטרנט או קישור עומק. ‫SDK משתמש ביכולות של מערכת ההפעלה כדי לפתוח אותו.
event_params מילון מילון שמכיל מידע נוסף על אירוע מסוג קליק. ה-SDK משתמש בזה.

נתונים על לחיצות על כפתורים בכרטיסי תוכן

מפתח סוג תיאור
title מחרוזת כותרת הכרטיס.
title מחרוזת כותרת הכרטיס.
link מחרוזת קישור לדף אינטרנט או קישור עומק. ‫SDK משתמש ביכולות של מערכת ההפעלה כדי לפתוח אותו.
event_params מילון מילון שמכיל מידע נוסף על אירוע מסוג קליק. ה-SDK משתמש בזה.

נתונים על הקלקות על תשובות מהירות

מפתח סוג תיאור
title מחרוזת כותרת הכרטיס.
title מחרוזת כותרת הכרטיס.
link מחרוזת קישור לדף אינטרנט או קישור עומק. ‫SDK משתמש ביכולות של מערכת ההפעלה כדי לפתוח אותו.
event_params מילון מילון שמכיל מידע נוסף על אירוע מסוג קליק. ה-SDK משתמש בזה.

נתונים של הפעלת קישור בהודעה

מפתח סוג תיאור
event_name String השם של האירוע, למשל Message Link Clicked (המשתמש לחץ על קישור בהודעה).
link String קישור לדף אינטרנט או קישור עומק. ערכת ה-SDK משתמשת ביכולות של מערכת ההפעלה כדי לפתוח את המודעה.

שליחת נתונים מותאמים אישית למערכת לניהול קשרי לקוחות (CRM)

אפשר לשלוח נתונים בהתאמה אישית לנציגי התמיכה, והם יופיעו בכרטיס התמיכה של השיחה או הצ'אט הנכנסים.

יש שתי שיטות לשליחת נתונים בהתאמה אישית:

  • שיטה חתומה: חתימה מוגדרת מראש של נתונים באמצעות JWT.

  • שיטה לא חתומה: נתונים מוגדרים מראש עם JSON רגיל (לא מומלץ).

שימוש בשיטה החתומה לשליחת נתונים בהתאמה אישית

כדי לשלוח נתונים בהתאמה אישית באמצעות השיטה החתומה, מטמיעים שיטת חתימה.

קודם כול, מאחזרים נתונים מותאמים אישית לאפליקציית המארח ואז שולחים אותם לשרת לחתימה. בשרת, אפשר להוסיף נתונים נוספים באמצעות טופס מוגדר. חותמים עליהם באמצעות הסוד של החברה ומחזירים אותם באמצעות 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));
        }
        // ...
    }
}

שימוש בשיטה לא חתומה לשליחת נתונים בהתאמה אישית

‫Google ממליצה להשתמש בשיטה החתומה כדי לשלוח נתונים מותאמים אישית באפליקציה. מידע נוסף מופיע במאמר בנושא שימוש בשיטה החתומה לשליחת נתונים בהתאמה אישית.

אפשר לשלוח נתונים לא חתומים על ידי הפעלת Android SDK עם אפשרויות הפעלה להגדרת נתונים בהתאמה אישית באמצעות UjetStartOptions.Builder#setUnsignedCustomData ו-UjetTokenCallback צריכים לקרוא ל-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);

שימוש בנתונים מותאמים אישית לא חתומים כדי לשלוח תמליל של שיחה חיצונית

אתם יכולים לשלוח את תמליל הצ'אט החיצוני ל-CCAI Platform באמצעות נתונים מותאמים אישית לא חתומים כשהוא מתחיל. משתמשים ב-UjetCustomData.putObject("external_chat_transfer", hashMapObject) כדי להגדיר את נתוני התמליל בפורמט JSON באופן הבא:

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);

קובץ JSON:

  • greeting_override: מחרוזת

  • agent: מילון

    • name: מחרוזת

    • avatar: מחרוזת [כתובת ה-URL של דמות נציג, אופציונלי]

  • transcript: array

    • sender: מחרוזת [‎"end_user" or "agent"‎]

    • timestamp: מחרוזת [לדוגמה, ‎ "2021-03-15 12:00:00Z"‎]

    • content: array

      • type: מחרוזת [אחת מהאפשרויות text, media]

      • text: מחרוזת [חובה לסוג טקסט]

      • media: מילון [חובה לסוג מדיה]

        • type: מחרוזת [אחת מהאפשרויות image, video]

        • url: מחרוזת [כתובת URL ציבורית שמפנה לקובץ מדיה]

דוגמה ל-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"
            }
        ]
        }
    ]
}

אפשר להשתמש ב-Markdown בסוג הטקסט. הפורמטים הנתמכים הם:

  • הטקסט המודגש

  • כתב נטוי

  • קו תחתון

  • מעברי שורה

  • רשימת תבליטים

  • רשימה ממוספרת

  • קישורים

פורמט נתונים בהתאמה אישית

בקטע הזה מוצג הפורמט של הנתונים המותאמים אישית שאפשר להעביר ב-JWT.

קידוד JSON ל-JWT

קובץ ה-JSON צריך לכלול את הערכים iat ו-exp כדי לאמת את ה-JWT. האובייקט של הנתונים בהתאמה אישית הוא הערך של המפתח 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"
        }
    }
}

המפתח הוא מזהה ייחודי של הנתונים. הסוג הוא הסוג של הערך.

  • string

    • מחרוזת JSON
  • number

    • מספר שלם, מספר ממשי
  • date

    • פורמט חותמת זמן של Unix ב-UTC עם 13 ספרות. (כולל אלפיות שנייה)
  • url

    • הפורמט של כתובת URL מסוג HTTP

התווית היא השם המוצג בדף ה-CRM.

מניעת הצגה של נתונים בהתאמה אישית

אפשר להשתמש במאפיין invisible_to_agent עם אובייקט נתונים בהתאמה אישית כדי למנוע הצגה של נתונים בהתאמה אישית עם או בלי חתימה במתאם של הסוכן. בדוגמה הקודמת, מספר הביטוח הלאומי של משתמש הקצה לא מוצג במתאם של הסוכן כי "invisible_to_agent" : true נכלל באובייקט ssn.

כשכוללים את מאפיין "invisible_to_agent" : true עם אובייקט נתונים בהתאמה אישית, צפויה ההתנהגות הבאה:

מידע נוסף זמין במאמר הצגת נתוני סשן במתאם הסוכן.

מאפייני נתונים שמורים

אתם יכולים לשלוח נכסי נתונים שמורים אל Contact Center AI Platform (פלטפורמת CCAI) כנתונים מותאמים אישית חתומים כשמתחיל סשן. מידע נוסף זמין במאמר בנושא שליחת מאפייני נתונים שמורים.

הדוגמה הבאה מציגה מאפייני נתונים שמורים בנתונים מותאמים אישית:

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

מחליפים את מה שכתוב בשדות הבאים:

  • VERIFIED_CUSTOMER_BOOLEAN: הערך True אם אתם מחשיבים את משתמש הקצה הזה כלקוח לגיטימי.
  • VERIFIED_BAD_ACTOR_BOOLEAN: הערך הוא True אם לדעתכם משתמש הקצה הזה הוא גורם זדוני פוטנציאלי.
  • REPEAT_CUSTOMER_BOOLEAN: הערך הוא True אם קבעתם שמשתמש הקצה הזה יצר קשר עם מוקד התמיכה שלכם בעבר.

חלופי

אפשר להשתמש ב-UjetErrorListener כגיבוי לשגיאות בלתי צפויות. אם לא מגדירים את מאזין השגיאות הזה או מחזירים false, ה-Android SDK יטפל בשגיאה.

‫Android SDK יפנה את המשתמשים לחייגן עם מספר חלופי רק אם המתג 'הפעלת מעבר חזרה ל-PSTN' מופעל בהגדרות > הגדרות למפתחים > MMA > עריכת חלון קופץ. אחרת, המשתמשים יצאו מ-SDK.

סוג השגיאה קוד שגיאה הטריגר
NETWORK_ERROR 1 הרשת לא זמינה. הערה: השגיאה הזו לא מופיעה כשהרשת לא זמינה במהלך צ'אט או שיחה, או במהלך מסך הדירוג.
AUTHENTICATION_ERROR 100 אירעה שגיאה לא צפויה במהלך האימות.
AUTHENTICATION_JWT_ERROR 101 אירעה שגיאה לא צפויה במהלך אימות ה-JWT (למשל, שגיאת ניתוח).
VOIP_CONNECTION_ERROR 1000 החיבור לספק ה-VoIP נכשל. היא מטופלת באמצעות הקריאה החוזרת של VoIP SDK.
VOIP_LIBRARY_NOT_FOUND 1001 השיחה אמורה להתבצע באמצעות ספק VoIP, אבל לא נמצא ספק כזה. זה יכול לקרות אם מפתח שילב SDK שגוי או לא הוסיף לספריות התלויות שלו את הספרייה של ספק ה-VoIP.
CHAT_LIBRARY_NOT_FOUND 1100 מתרחש כשלא ניתן למצוא את ספריית הצ'אט. הבעיה הזו יכולה לקרות אם מפתח שילב SDK שגוי או לא הוסיף את ספריית Twilio Chat לתלות שלו.
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());
    }
});

קישורי עומק

אם רוצים להשתמש בפעולות חכמות בשיחה במערכת IVR (PSTN), צריך להגדיר קישור עומק בפרויקט.

פורמט קישור העומק הוא URI ייחודי, כמו:

ujet:// <package_name>/smartchannel.

בנוסף, צריך להגדיר את הקישור הזה או כל כתובת URL שתפנה לקישור הזה בפורטל הניהול (הגדרות > ניהול פעולות > הפעלת שליחת SMS להורדת האפליקציה).

תצטרכו להוסיף מסנן Intent שמכיל את קישור העומק במניפסט.

<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>

עמידות של הצ'אט בשידור חי

כדי לשפר את זמינות הצ'אט בשידור חי, צריך להגדיר את עמידות הצ'אט בשידור חי. ההגדרה הזו מוסיפה שכבת מדיה משנית להעברת הודעות, שמשמשת כחלופה אם שכבת המדיה הראשית נכשלת.

כדי להוסיף את היכולת הזו, מוסיפים את יחסי התלות הבאים לקובץ build.gradle ברמת המודול:

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

מחליפים את VERSION בגרסה העדכנית ביותר של UJET SDK.

שינויים בהתנהגות של שיחות נכנסות

החל ממכשירים עם Android בגרסה 10, שיחות נכנסות לא יתקבלו ישירות אצל משתמשי הקצה כשאפליקציית המארח פועלת ברקע. במקום זאת, אנחנו משתמשים בהתראות כדי להודיע למשתמשים על שיחות נכנסות (גם כשהטלפון נעול), ומאפשרים להם לאשר או לדחות את השיחה.

ההתראות האלה מוצגות גם כשהאפליקציה המארחת פועלת ברקע והמסך נעול לפני שהשיחה הנכנסת מגיעה. השינוי הזה בהתנהגות נועד לעמוד בהגבלות האחרונות של Google על התחלת פעילויות כשהאפליקציה פועלת ברקע. ההתנהגות לא מושפעת כשאפליקציית המארח בחזית או פועלת במכשירים עם גרסה נמוכה מ-Android 10.

התאמה אישית של סשן SDK

בקטע הזה מוסבר איך אפשר להתאים אישית את ה-SDK.

בדיקה אם יש סשן קיים

לפני שמתחילים סשן, צריך להשתמש בשיטה שמתוארת כאן כדי לבדוק אם יש סשן קיים או סשן בתהליך. אם המינוי קיים, תוכלו להציג למשתמש הקצה הודעה להמשך או לביטול המינוי.

זה חשוב במיוחד כשמשנים משתמש.

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

ניתוק הסשן

אם רוצים לנתק סשן כלשהו שנמצא בתהליך, צריך לעיין בשיטה.

לפני שמשתמשים בשיטה הזו, חשוב לבדוק אם קיים סשן כזה באמצעות Ujet.getStatus(). אם רוצים לבצע פעולה אחרי שה-SDK מנתק את הסשן, למשל להציג הודעה או לסגור את האפליקציה, אפשר להשתמש בקריאה חוזרת לתגובה onFinished() כמו שמוסבר בקטע הבא. אחרת, צריך להגדיר את הקריאה החוזרת כ-null.

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

ניקוי נתוני משתמש מהמטמון

אתם אחראים לנקות את המטמון כשנתונים שקשורים למשתמשי קצה מתעדכנים או משתנים באפליקציה. לדוגמה, אם משתמש הקצה התנתק, צריך להפעיל את השיטה להסרת המטמון של המשתמש הזה כדי שסשן חדש יתחיל עבור משתמש הקצה החדש בפעם הבאה שערכת ה-SDK תופעל.

Ujet.clearUserData();

הסתרת ה-SDK

אפשר להסתיר את ה-SDK באמצעות ה-method‏ Ujet.hideSDK(). האפשרות הזו שימושית למשל אם ה-SDK מפריע לממשק המשתמש של האפליקציה. צריך להפעיל את ה-SDK באמצעות Ujet.init() לפני שמפעילים את ה-method הזו. הפונקציה Ujet.init() מחזירה true אם ערכת ה-SDK הוסתרה בהצלחה, ו-false אחרת. אחרי שמסתירים את ה-SDK, אפשר להפעיל אותו שוב באמצעות ה-method‏ Ujet.start().

בדוגמה הבאה, ה-SDK מוסתר:

Ujet.hideSDK();

הגדרת סמלים של קישורים להפניה חיצונית

כדי להתאים אישית את הסמל בערוץ 'קישור להפניה חיצונית', מעלים את הסמל לתיקיית drawable באפליקציה. חשוב להשתמש באותו שם סמל כשיוצרים את הקישור להפניה חיצונית בפורטל של פלטפורמת CCAI בכתובת Settings > Chat > External Deflection Links > View links > Add Deflection Link (הגדרות > צ'אט > קישורים להפניה חיצונית > הצגת קישורים > הוספת קישור להפניה).

אם שם הסמל בפורטל של CCAI Platform לא תואם לסמל שהועלה לאפליקציה, Android SDK ישתמש בסמל ברירת המחדל.

הגדרת הסמל תודה בסקרים

כדי להתאים אישית את הסמל בדף התודה של הסקר או להחליף אותו, אפשר להעלות סמל לתיקיית drawable של האפליקציה ולהשתמש בשם הקובץ ujet_survey_thank_you_icon כשם הסמל.

התאמה אישית של ממשק המשתמש והמחרוזות

בקטע הזה מוסבר איך להתאים אישית מחרוזות, כרטיסי תוכן, ערכות נושא וכותרות של צ'אטים.

מחרוזות

אפשר להתאים אישית מחרוזות שמשמשות באפליקציה על ידי החלפת מפתחות לכל מחרוזת בקובץ 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>

הגדרת הסקר

התאמה אישית של גודל הטקסט

כדי להתאים אישית את הגודל של הכותרת, התיאור והטקסט של הכלי לבחירת תאריכים שמופיעים באפליקציה, צריך להגדיר מחדש את המפתחות הבאים בקובץ dimens.xml.

הגדרנו גדלים שונים של טקסט שאפשר לבחור מתוכם:

<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>

עיצוב

כדי להתאים אישית את העיצוב והרקע, פועלים לפי השלבים הבאים. שלב 1 הוא לגבי ערכת הנושא, ושלב 2 הוא לגבי הרקע.

  1. כדי להתאים אישית את העיצוב, מחליפים את המקשים של כל פריט סגנון בקובץ style.xml. לדוגמה,

    <!--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. אפשר להתאים אישית את צבע הרקע באפליקציה על ידי החלפת המפתחות של כל פריט סגנון בקובץ style.xml. צבע הרקע שניתן להתאמה אישית מוצג בצילום המסך.

    <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>
    

התאמה אישית של הכותרת בצ'אט

יש אפשרויות להתאמה אישית של הטקסט בכותרת של הצ'אט בממשק המשתמש.

אתם יכולים להתאים אישית את הטקסט של הכותרת בצ'אט באמצעות האפשרויות הבאות:

<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>

אתם יכולים להתאים אישית את התשובות המהירות של הסוכן הווירטואלי בממשק המשתמש של הצ'אט באמצעות האפשרויות הבאות:

<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>

כרטיסי תוכן

אתם יכולים להתאים אישית את כרטיסי התוכן ואת הצ'אט. אפשר לעשות את זה באמצעות קובץ ה-JSON (ראו content_card property בקובץ app/src/main/assets/json/ujet_styles.json) או באמצעות המחלקה 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",
            )
        )
    )
)

עיצוב של טופס אינטרנטי

אתם יכולים להתאים אישית את כרטיס הטופס האינטרנטי, וגם את הצ'אט. אפשר לעשות את זה באמצעות קובץ ה-JSON (ראו את המאפיין form_card בקובץ app/src/main/assets/json/ujet_styles.json) או באמצעות המחלקה 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,
        ),
    )
)

Surveys

כדי לשנות את הסמל בדף התודה של הסקר, מעלים סמל לתיקיית ה-drawable של האפליקציה.

חשוב להשתמש ב-ujet_survey_thank_you_icon כשם הסמל.

כדי להתאים אישית את תיבת הדו-שיח להבעת הסכמה לשיתוף המסך, צריך להטמיע את CoBrowseAlertProvider המחלקה המופשטת. אפשר להשתמש ב-DialogFragment או ב-AlertDialog כדי להטמיע את תיבת הדו-שיח המותאמת אישית לבקשת הסכמה.

  • אם משתמשים ב-DialogFragment, צריך לכלול שני לחצנים, אחד לאישור ההסכמה ואחד לדחייה שלה. העברה של מופע DialogFragment בהתאמה אישית אל הקריאה החוזרת dialogInstance.

  • אם אתם משתמשים ב-AlertDialog, אל תעבירו את מופע DialogFragment אל הקריאה החוזרת dialogInstance.

אחרי קבלת ההסכמה, מעבירים אותה ל-SDK באמצעות הפעלת הקריאה החוזרת consentStatus והעברת הערך הבוליאני בהתאם.

אפשר להשתמש בדוגמת הקוד הבאה כדי להטמיע את תיבת הדו-שיח להבעת הסכמה המותאמת אישית:

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
    }
}

מעבירים את ההטמעה הזו ל-SDK באמצעות ה-API הבא:

Ujet.setCoBrowseAlertProvider(CoBrowseAlertProviderImpl())

הגדרת טפסים באינטרנט

כדי להגדיר טופס אינטרנט, מטמיעים את ה-method‏ ujetWebFormDidReceive של הממשק UjetWebFormListener. השיטה הזו מקבלת אירוע (FormMessageReceived map) כפרמטר, שמכיל מידע שקשור לטופס. האירוע כולל את מבנה ה-JSON הבא:

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

טיפול באירוע

כדי לטפל באירוע:

  1. מחפשים את המידע הרלוונטי במפת האירועים (smart_action_id, external_form_id ו-signature).
  2. ליצור URI של טופס וחתימה לנתוני הטופס.
  3. מעבירים את נתוני הטופס ל-SDK בתור FormDataEvent map באמצעות callback.onEvent(formDataEvent).
  4. אם מתרחשת שגיאה במהלך יצירת ה-URI או החתימה, צריך להפעיל את קריאת החזרה לשגיאה באמצעות callback.onError().

המפה (FormDataEvent) שמועברת ל-SDK צריכה להיות במבנה הבא:

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

החתימה (HMAC-SHA256) צריכה להיווצר באמצעות הנתונים, ולחתום עליה באמצעות מפתח סודי משותף. מפתחות האובייקט של הנתונים צריכים להיות מסודרים לפי סדר אלפביתי לפני יצירת החתימות, ואותם נתונים צריכים להישלח ל-SDK.

בדוגמת הקוד הבאה אפשר לראות איך מטמיעים את מאזין הטפסים באינטרנט:

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()
        }
    }
}

מעבירים את ההטמעה הזו ל-SDK באמצעות ה-API הבא:

Ujet.setUjetWebFormListener(UjetWebFormListenerImpl())

פתרון בעיות

התחלת שיחה חדשה נמשכה יותר מ-30 שניות

בודקים אם אתם מגיבים לשיטה של נתונים מותאמים אישית שהוקצו לנציג. צריך להחזיר נתונים מותאמים אישית תקינים לפי בקשה, או פשוט להחזיר null עם קריאה חוזרת (callback). הקוד הבא הוא לעיון בלבד.

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

הסבר לגבי הצהרת התאימות למדיניות

אם קיבלתם הודעה ב-Google Play Console שבה אתם מתבקשים להצהיר על מדיניות לגבי השירותים או ההרשאות שבהם נעשה שימוש ב-Android SDK, תוכלו להשתמש באחד מההסברים הבאים.

הצהרה על שירותים שפועלים בחזית שנעשה בהם שימוש ב-Android SDK

‫Google הציגה סוגים של שירותים שפועלים בחזית ב-Android 14, וקבעה שחובה לציין אותם כשמפעילים שירותים שפועלים בחזית. מידע נוסף זמין בכתובת https://developer.android.com/about/versions/14/changes/fgs-types-required#remote-messaging. ‫Android SDK של פלטפורמת Contact Center AI (פלטפורמת CCAI) משתמש בשירותים שפועלים בחזית כדי ליזום צ'אט ושיחה, ולכן השתמשנו בסוג השירות FOREGROUND_SERVICE_REMOTE_MESSAGING לצ'אט, כי מדובר בהודעות טקסט, ובסוג השירות FOREGROUND_SERVICE_MICROPHONE לשיחה. בלי סוגי השירותים האלה, ערכת ה-SDK תקרוס במהלך הפעלת צ'אט או שיחה, החל ממכשירים עם Android מגרסה 14.

הצהרה על ההרשאה להציג Intent במסך מלא שנעשה בה שימוש ב-Android SDK

ההרשאה USE_FULL_SCREEN_INTENT נדרשת כדי להציג התראת פוש על שיחה נכנסת כשהמכשיר נעול. היא מתריעה למשתמש הקצה ומציגה את ההתראה על השיחה הנכנסת במסך מלא (כך אפליקציית הטלפון המובנית מתריעה למשתמש הקצה על שיחה נכנסת).

תמיכה ב-Android 15

כדי לתמוך ב-Android 15, פועלים לפי השלבים הבאים:

  1. מגדירים את compileSdkVersion = 35 ואת targetSdkVersion = 35 ב-build.gradle(:app).

  2. מוודאים שגרסת פלאגין של Android Gradle ‏ (AGP) בפרויקט היא 8.5.1 או גרסה מתקדמת יותר. מידע נוסף זמין במאמר בנושא עדכון האריזה של הספריות המשותפות.

  3. כדי ליצור פרויקטים ל-Android באמצעות AGP 8.0 ואילך, צריך להתקין את Java Development Kit ‏ (JDK) בגרסה 17 ואילך. מידע נוסף זמין במאמר בנושא JDK 17 נדרש להרצת AGP 8.0.