מדריך ל-Android SDK

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

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

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

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

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

  • ‫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, החל מגרסה 0.34.0 של Android SDK, ערכת ה-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 של המחלקה Application באפליקציה ל-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 מהקטע "הגדרות" > "כללי" במסוף Firebase.

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

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

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

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

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

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

  3. לוחצים על Edit לצד האפליקציה. תיבת הדו-שיח Edit Mobile App תופיע.

  4. בשדה Service Account, מזינים את מפתח חשבון השירות ולוחצים על 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, שרשום במניפסט אם האסימון מתרענן. מידע נוסף זמין במאמר הגדרת אפליקציית לקוח של העברת הודעות בענן ב-Firebase ב-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) תטפל בעיבוד של הודעות ה-Push שלה, אתם יכולים להעביר את הנתונים ישירות אל 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. מסמנים את האפשרות יצירת נקודת גישה ישירה.

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

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

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

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

Ujet.start(ujetStartOptions);

הגדרת SDK

אתם יכולים להגדיר כמה אפשרויות לפני שתפעילו את Android SDK. למידע נוסף, ראו את המחלקה UjetOption. האפשרויות Fallback Phone Number ו-Network Sensitivity שמתוארות בטבלה הבאה פועלות רק כשהמתג Enable PSTN Fallback מופעל בפורטל של פלטפורמת CCAI, בקטע Settings > Developer Settings > MMA > Edit. כשהמתג הפעלת חלופה ל-PSTN מושבת, אנחנו לא עוברים ל-PSTN. בפלטפורמת CCAI נעשה שימוש ברגישות ברירת המחדל של הרשת (0.85) כדי לבדוק את החיבורים לרשת.

אפשרות תיאור ערך ערך ברירת המחדל
רמת הרישום ביומן רמת הרישום ביומן שתודפס ב-Logcat. מספר שלם. אותו דבר לגבי רמת הרישום ביומן של Android. (מינימום: 2, מקסימום: 7) 5 (Log.Warn)
שפת ברירת המחדל קוד השפה שמוגדר כברירת מחדל. מחרוזת. קוד שפה לפי תקן ISO 639. (למשל, en לאנגלית) null
מספר טלפון חלופי מספר הטלפון משמש כגיבוי כשאין חיבור לאינטרנט או כשמספר הטלפון של נציג החברה לא קיים בפורטל Admin. מחרוזת. מספר טלפון. null
הפעלת הטיפול בחריגות שלא נתפסו מפעילים את הגורם המטפל בחריגות שלא נתפסו. אם 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 ועוברים לקטע License Key (מפתח רישיון). String null
כותרת מותאמת אישית לצ'אט אפשרות הגדרה להתאמה אישית של טקסט הכותרת של הצ'אט בממשק המשתמש של הצ'אט. String null
התאמה אישית של התשובות המהירות בממשק המשתמש של הצ'אט אפשרות הגדרה להתאמה אישית של התשובות המהירות של הנציג הווירטואלי בממשק המשתמש של הצ'אט. כברירת מחדל, התשובות המהירות של הסוכן הווירטואלי מקובצות יחד, אבל אם רוצים להציג אותן בנפרד, אפשר להשתמש באפשרות ההגדרה הזו כדי להגדיר את QuickReplyButtonsStyle.INDIVIDUAL UjetStylesOptions QuickReplyButtonsStyle.GROUPED
התאמה אישית של מאפיינים שונים בממשק המשתמש של הצ'אט אפשרות הגדרה להתאמה אישית של מאפיינים שונים כמו הגופן, צבע הרקע, הסמל וכו'. UjetStylesOptions null
הסתרת שורת הסטטוס אפשרות הגדרה להצגה או להסתרה של שורת הסטטוס. אם הערך הוא True, ה-SDK יסתיר את שורת הסטטוס. בוליאני false
הגדרת משאב שניתן לשרטוט של סימן גרפי שפעולה מתבצעת אפשרות הגדרה להתאמה אישית של תצוגת סמל הטעינה באפליקציה. אם היא לא זמינה או שהערך שלה הוא null, אנחנו משתמשים בתצוגת הטעינה שמוגדרת כברירת מחדל. מספר שלם null
הכיוון לרוחב מושבת משביתים את הכיוון לרוחב. אם הערך הוא True, הכיוון לרוחב לא מופעל. בוליאני false
הסתרת הכפתור להתחלת שיחה חדשה בתוך הצ'אט אפשרות הגדרה להצגה או להסתרה של הכפתור להתחלת שיחה חדשה בממשק המשתמש של הצ'אט. בוליאני false
הצגת כפתור הדילוג על סקר שביעות הרצון (CSAT) אפשרות הגדרה להצגה או להסתרה של כפתור הדילוג בתיבת הדו-שיח של שביעות רצון הלקוחות (CSAT) בוליאני false
חסימת האפשרות של משתמשי קצה לסיים את הצ'אט אפשרות הגדרה להצגה או להסתרה של כפתור סיום השיחה בממשק המשתמש של הצ'אט בוליאני false
הסתרת האפשרות להוריד את תמליל הצ'אט הצגה או הסתרה של הכפתור להורדת תמליל הצ'אט בתפריט הפעולות של הצ'אט ובממשק המשתמש של הצ'אט. אם מוסיפים רווח למחרוזת ujet_common_hide, הטקסט Hide נעלם ומופיע רק החץ חזרה. מספר שלם. ערכים:

0 = הצגה בכל מקום

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

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

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

0

UjetOption.setBlockChatTerminationByEndUser

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

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

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

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

העדפת שפה

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

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

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

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

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

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

הערוץ המועדף

הפרמטר "ערוץ מועדף" מאפשר לכם להפנות את הצרכנים ישירות לערוץ ספציפי. במקרה כזה, משתמש הקצה מדלג על שלב בחירת הערוץ ויוצר קשר ישירות דרך הערוץ שצוין בפרמטר 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 מכיל את שם האירוע. לדוגמה, "Email Clicked" (אימייל שנלחץ).
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 מכיל את שם האירוע. לדוגמה, "Email Clicked" (אימייל שנלחץ).
type String מכיל סוג פעילות. לדוגמה, "צ'אט" או "שיחה".
timestamp String מכיל חותמת זמן ב-UTC (בפורמט yyyy-MM-dd'T'HH:mm:ss'Z').

נתוני יצירת הסשן

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

נתונים על סשנים שהסתיימו

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

נתונים על ערכות SDK שהופסקו

מפתח סוג תיאור
event_name String מכיל את שם האירוע. לדוגמה, "Email Clicked" (אימייל שנלחץ).

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

מפתח סוג תיאור
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.

  • ‫Unsigned method (שיטה לא חתומה): נתונים מוגדרים מראש עם 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: מערך

    • ‫sender: מחרוזת ["end_user" או "agent"]

    • timestamp: מחרוזת [למשל "2021-03-15 12:00:00Z"]

    • content: מערך

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

    • מספר שלם, מספר ממשי (float)
  • date

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

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

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

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

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

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

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

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

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

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

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

מגדירים כל ערך כ-true או כ-false.

  • ‫reserved_verified_customer: true אם לדעתך משתמש הקצה הזה הוא לקוח לגיטימי.
  • ‫reserved_bad_actor: true אם לדעתכם משתמש הקצה הזה עלול להיות גורם זדוני.
  • ‫reserved_repeat_customer: true אם קבעתם שמשתמש הקצה הזה יצר קשר עם מוקד התמיכה שלכם בעבר.

חלופי

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

ערכת ה-Android SDK תפנה את המשתמשים לחייגן עם מספר חלופי רק אם המתג Enable PSTN Fallback (הפעלת חלופה ל-PSTN) מופעל בהגדרות > הגדרות למפתחים > MMA > עריכת החלון הקופץ. אחרת, ערכת ה-SDK תיסגר.

סוג השגיאה קוד שגיאה הטריגר
NETWORK_ERROR 1 הרשת לא זמינה. הערה: השגיאה הזו לא מופיעה כשהרשת לא זמינה במהלך צ'אט, שיחה או מסך דירוג.
AUTHENTICATION_ERROR 100 אירעה שגיאה לא צפויה במהלך האימות.
AUTHENTICATION_JWT_ERROR 101 אירעה שגיאה לא צפויה במהלך אימות ה-JWT (למשל, שגיאת ניתוח).
VOIP_CONNECTION_ERROR 1000 לא הצלחנו להתחבר לספק ה-VoIP. הוא מטופל באמצעות הקריאה החוזרת (callback) של ה-SDK של VoIP.
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 שתפנה לקישור הזה בפורטל Admin‏ (Settings > Operation Management > Enable Send SMS to Download App).

צריך להוסיף לקובץ המניפסט מסנן 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 בגרסה העדכנית של ה-SDK של UJET.

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

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

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

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

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

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

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

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

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

ניתוק הסשן

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

לפני שמשתמשים בשיטה הזו, צריך לבדוק אם קיים סשן כזה באמצעות Ujet.getStatus()‎. אם רוצים לבצע פעולה כלשהי אחרי שה-SDK מנתק את הסשן, למשל להציג הודעה או לסגור את האפליקציה, אפשר להשתמש בקריאה חוזרת(callback) לתגובה 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();

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

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

אם שם הסמל בפורטל של פלטפורמת CCAI לא תואם לסמל שהועלה לאפליקציה, 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 אל פונקציית ה-callback של dialogInstance.

  • אם משתמשים ב-AlertDialog, לא מעבירים את המכונה של DialogFragment אל הקריאה החוזרת (callback) של dialogInstance.

אחרי שמקבלים הסכמה, מעבירים אותה ל-SDK על ידי הפעלת פונקציית ה-callback‏ 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) כפרמטר, שמכיל מידע שקשור לטופס. האירוע כולל את מבנה ה-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 באמצעות callback.onEvent(formDataEvent).
  4. אם מתרחשת שגיאה במהלך יצירת ה-URI או החתימה, צריך להפעיל את פונקציית ה-callback של השגיאה באמצעות 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 שניות

בודקים אם אתם מגיבים ל-delegate method של נתונים בהתאמה אישית. צריך להחזיר נתונים מותאמים אישית תקינים לפי בקשה, או פשוט להחזיר ערך 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. ערכת ה-SDK ל-Android של Contact Center AI Platform (פלטפורמת CCAI) משתמשת בשירותים שפועלים בחזית כדי להתחיל צ'אט ושיחה. לכן, השתמשנו בסוג השירות FOREGROUND_SERVICE_REMOTE_MESSAGING לצ'אט כי אנחנו עוסקים בהודעות טקסט, ובסוג השירות FOREGROUND_SERVICE_MICROPHONE לשיחה. בלי סוגי השירותים האלה, ערכת ה-SDK תקרוס כשהיא תתחיל צ'אט או שיחה במכשירים עם גרסת Android 14 ואילך.

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

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

תמיכה ב-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.