Android SDK ガイド

このページでは、Android SDK の使用方法について説明します。

サンプルアプリにアクセスする

Android サンプルアプリをダウンロードするには、[Android サンプルアプリ] をクリックします。

Android モバイル SDK を使用してサンプルアプリを作成するには、次のものが必要です。

  • CCAI Platform ポータルの会社キーと会社シークレット。

  • Android 5.0(API レベル 21、Lollipop)以降。

  • プッシュ通知用の Firebase Cloud Messaging または 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'

また、Android SDK には Proguard ルールがすでに含まれているため、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. [Settings] > [Developer Settings] > [Company Key & Secret Code] に移動します。

  3. Company Key と Company Secret Code を取得します。

インストール

ルート プロジェクトの Gradle 設定に Android SDK リポジトリを追加します。

build.gradle(プロジェクト)

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

build.gradle(モジュール: 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 が含まれており、mock/APIManager.java に UJET_COMPANY_SECRET を配置する必要があります。APIManager は、JWT 認証トークンに署名する非同期呼び出しを開始し、トークンを返すメソッドを実装する必要があります。

本番環境では、サーバーに署名プロセスを実装する必要があります。

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

SDK を初期化する

Android アプリケーション クラスの onCreate メソッドで SDK を初期化します。

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

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

エンドユーザー認証

エンドユーザーは、アプリケーションを介してカスタマー サポート チームに連絡する消費者です。

アプリケーションでエンドユーザーを認証するために、JWT 署名メカニズムを導入します。

Android SDK は、認証が必要な場合にペイロードに署名するようリクエストします。署名が成功すると、アプリケーションは署名付き 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. Firebase コンソールの [設定] > [全般] から google-services.json をダウンロードします。

  1. Firebase コンソールの [設定] > [Cloud Messaging] でサーバーキーを取得します。

サービス アカウント キーを追加する

プッシュ通知を受信するには、モバイルアプリにサービス アカウント キーを追加する必要があります。サービス アカウント キーを取得するには、サービス アカウントを使用して認証するをご覧ください。

モバイルアプリにサービス アカウント キーを追加する手順は次のとおりです。

  1. CCAI Platform ポータルで、[Settings] > [Developer Settings] をクリックします。[設定] メニューが表示されない場合は、 メニュー をクリックします。

  2. [モバイルアプリ] ペインに移動します。

  3. アプリの横にある [編集] をクリックします。[モバイルアプリの編集] ダイアログが表示されます。

  4. [サービス アカウント フィールド] にサービス アカウント キーを入力し、[保存] をクリックします。

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 が呼び出されます。これは、トークンが更新された場合にマニフェストに登録されます。詳細については、Android で Firebase Cloud Messaging クライアント アプリを設定するをご覧ください。

    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. Application クラスに UjetRequestListener.onRequestPushToken を実装します。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. プッシュ通知を処理します。コンタクト センター AI プラットフォーム(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
        }
    }
}

GcmReceiver で GCM メッセージを処理する(古い方法)

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 Platform ポータル(管理者ロール)の Direct Access Point で作成できます。

  1. [設定] > [キュー] に移動します。

  2. メニュー構造からキューを選択します。

  3. [直接アクセス ポイントを作成] をオンにします。

  4. テキスト フォームにキーを入力します。

  5. [保存] をクリックします。

特定のチケット ID を指定して Android SDK を起動し、CRM に渡すこともできます。このチケット ID は、チャットまたは通話が接続されると開きます。

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

Ujet.start(ujetStartOptions);

SDK の構成

Android SDK を起動する前に、いくつかのオプションを構成できます。UjetOption クラスをご覧ください。次の表に示す代替電話番号とネットワーク感度のオプションは、CCAI Platform ポータルの [設定] > [デベロッパー設定] > [MMA] > [編集] で [PSTN フォールバックを有効にする] がオンになっている場合にのみ機能します。[PSTN フォールバックを有効にする] がオフの場合、PSTN へのフォールバックは行われません。CCAI Platform は、ネットワーク接続の確認にデフォルトのネットワーク感度(0.85)を使用します。

オプション 説明 値 デフォルト値
ログレベル Logcat に出力されるログレベル。 データ型は int です。Android ログのログレベルについても同様です。(最小: 2、最大: 7) 5(Log.Warn)
デフォルトの言語 デフォルトの言語コード。 文字列。ISO 639 言語コード。(例: 英語の場合は en) null
代替電話番号 この電話番号は、インターネットが利用できない場合や、管理ポータルに会社の代表電話番号が存在しない場合の代替手段として使用されます。 文字列。電話番号。 null
キャッチされなかった例外ハンドラが有効 キャッチされなかった例外のハンドラを有効にします。true の場合、アプリは Thread.setDefaultUncaughtExceptionHandler を使用して、実行時にキャッチされなかったすべての SDK 例外を処理します。ただし、同じ例外が 2 回発生すると、アプリはクラッシュします。 ブール値 true
ネットワークの感度 ネットワーク状態を確認する感度。 0~1 の Double。0 は感度が最も低く、1 は感度が最も高いことを示します。1 の値は常に PSTN 通話にフォールバックします。使用する場合は、.97 の値から始めることをおすすめします。ポータルの [設定] > [デベロッパー設定] > [モバイルアプリ] > [代替] の電話番号のしきい値は、この値をオーバーライドします。 0.85
ダークモードが有効 ダークモードのテーマを有効にします。true の場合、ユーザーがダークモードをオンにすると、SDK はダークモードのテーマを適用します。それ以外の場合、このアクションは無視されます。 ブール値 false
単一チャネルが有効 単一チャンネルのチャンネル選択画面を表示するか、バイパスするかを設定するオプション。true の場合、メニューキューで有効になっているチャネルが 1 つだけであっても、SDK はチャネルを自動的に選択するのではなく、単一のチャネル選択画面を表示します。 ブール値 false
通話ビューを自動的に最小化 デフォルトで最初の通話画面の UI を自動的に最小化するか、ユーザーが最小化するまで待機するかを設定する構成オプション。 ブール値 false
エージェント アイコンの枠線が有効 エージェント アイコンの周囲に円形の枠線を表示または削除する構成オプション。 ブール値 false
選択ビューの静的フォントサイズ 選択アイテムのテキストサイズを自動調整または無効にする構成オプション。 ブール値 false
チャットでメディアの添付ファイルを非表示にする チャット UI でメディア添付アイコンを表示または非表示にする設定オプション。 ブール値 false
READ_PHONE_STATE 権限を無視する true に設定すると、SDK は READ_PHONE_STATE 権限をリクエストしません。アプリ内 IVR 通話を使用しない場合は、このフラグを true に設定して、この権限をリクエストしないようにします。また、アプリケーションで CCAI Platform SDK の android.permission.READ_PHONE_STATE 権限を明示的に削除する必要があります。この権限はアプリ内 IVR 通話が機能するために必要であるため、true に設定することはおすすめしません。 ブール値 false
Cobrowse.io ライセンスキー(該当する場合) Cobrowse.io ライブラリをセットアップするための構成オプション。Cobrowse ライセンスキーを確認するには、https://cobrowse.io/dashboard/settings にログインして [License Key] セクションに移動します。 文字列 null
カスタム チャット ヘッダーのタイトル チャット UI のチャット ヘッダーのタイトル テキストをカスタマイズする構成オプション。 文字列 null
チャット UI のクイック返信をカスタマイズする チャット UI で仮想エージェントのクイック返信をカスタマイズするための構成オプション。バーチャル エージェントのクイック返信はデフォルトでグループ化されていますが、個別に表示する場合は、この構成オプションを使用して QuickReplyButtonsStyle.INDIVIDUAL を設定できます。 UjetStylesOptions QuickReplyButtonsStyle.GROUPED
チャット UI のさまざまな属性をカスタマイズする フォント、背景色、アイコンなどのさまざまな属性をカスタマイズするための構成オプション。 UjetStylesOptions null
ステータスバーを非表示にする ステータスバーを表示または非表示にする構成オプション。値が true の場合、SDK はステータスバーを非表示にします。 ブール値 false
読み込み中スピナーのドローアブル リソースを設定する アプリ全体で読み込みスピナービューをカスタマイズするための構成オプション。利用できない場合や null の場合は、デフォルトの読み込みビューが使用されます。 Integer null
横向きが無効になっています 横向きを無効にします。値が true の場合、横向きは適用されません。 ブール値 false
チャットで新しい会話を開始するインライン ボタンを非表示にする チャット UI で新しい会話を開始するインライン ボタンを表示または非表示にする構成オプション。 ブール値 false
CSAT のスキップボタンを表示する CSAT ダイアログでスキップボタンを表示または非表示にする設定オプション ブール値 false
エンドユーザーによるチャットの終了をブロックする チャット UI でチャット終了ボタンを表示または非表示にする設定オプション ブール値 false
チャットの文字起こしのダウンロードを非表示にする チャットの操作メニューとチャット ユーザー インターフェースで、チャットの文字起こしをダウンロードするボタンを表示または非表示にします。ujet_common_hide 文字列にスペースを追加すると、Hide テキストが消え、戻る矢印のみが表示されます。 データ型は int です。値:

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

アプリの権限

このアプリは以下の権限を必要とし、必要に応じてユーザーにこれらの権限をリクエストします。

権限 説明
カメラ 写真や動画を撮影するスマート アクションに使用されます
マイク Twilio を介した VoIP 通話の使用をアプリに許可します
ストレージ アプリに写真や動画の保存を許可します

言語設定

Android SDK は、次の優先順位で言語を決定します。

  1. アプリ内のスプラッシュ画面で選択された言語。

  2. UjetOptions を使用して選択されたデフォルトの言語。デフォルトの言語は、UjetOptions の setDefaultLanguage("en") を使用して設定できます。詳しくは、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 文字列 イベント名が含まれます。例: 「メールのクリック」。
application 文字列 アプリケーション名が含まれます。例: 「Android」。
app_id 文字列 Context.getPackageName() と同じアプリ ID が含まれます。
app_version 文字列 アプリのバージョン名とバージョン コードが含まれます。例: 「0.32.0(123)」。
sdk_version 文字列 SDK バージョンが含まれます。例: 「0.32.0」。
timestamp 文字列 UTC 形式のタイムスタンプ(yyyy-MM-dd'T'HH:mm:ss'Z' 形式)が含まれます。
device_model 文字列 ユーザーのデバイスモデルが含まれます。例: 「Google Pixel」。
device_version 文字列 ユーザーのデバイスのバージョンが含まれます。例: 「10、Q、SDK 29」。
company 文字列 会社名が格納されています。例: 「会社」。
menu_name 文字列 リーフノードの名前(ユーザーが最後に選択したメニュー)が含まれます。例: 「サブメニュー」。
menu_id 文字列 リーフノードの ID(ユーザーが最後に選択したメニュー)が含まれます。例: 「123」。
menu_path 文字列 ユーザーが選択したメニューの完全なシーケンスが含まれます。例: 「親 / 子 / サブメニュー」。
menu_key 文字列 DAP キーが含まれています。これは省略可能です。例: 「special_user_menu」。

メールで送信されたデータ

キー タイプ 説明
has_attachments ブール値 メールに添付ファイルがある場合は True、それ以外の場合は False を返します。

セッション データ

キー タイプ 説明
event_name 文字列 イベント名が含まれます。例: 「メールのクリック」。
type 文字列 セッション タイプが含まれます。例: 「チャット」、「通話」。
timestamp 文字列 UTC 形式のタイムスタンプ(yyyy-MM-dd'T'HH:mm:ss'Z' 形式)が含まれます。

セッション作成データ

キー タイプ 説明
session_id 文字列 セッション ID が含まれます。例: 「100」。
type 文字列 セッション タイプが含まれます。例: 「チャット」、「通話」。
end_user_identifier 文字列 エンドユーザー識別子が含まれます。例: 「John」。
messages_end_user 文字列 エンドユーザーのメッセージ数が含まれます。チャット セッションにのみ含まれます。例: 「3」。
messages_agent 文字列 エージェントのメッセージ数が含まれます。チャット セッションにのみ含まれます。例: 「3」。

セッション終了データ

キー タイプ 説明
agent_name 文字列 エージェント名が含まれます。例: 「John」。
ended_by 文字列 セッションを終了したユーザーの詳細が含まれます。指定できる値は、「agent」(エージェントがセッションを終了した場合)、「end_user」(エンドユーザーがセッションを終了した場合)、「timeout」(チャットがタイムアウトした場合)、「dismissed」(チャットが閉じられた場合)です。
duration 文字列 セッション継続時間(秒)が含まれます。通話セッションにのみ含まれます。例: 「30 秒」。

SDK で終了したデータ

キー タイプ 説明
event_name 文字列 イベント名が含まれます。例: 「メールのクリック」。

コンテンツ カードのクリックデータ

キー タイプ 説明
title 文字列 カードのタイトル。
title 文字列 カードのタイトル。
subtitle 文字列 カードのサブタイトル。
body 文字列 コンテンツ カードの説明。
link 文字列 ウェブページのリンクまたはディープリンク。SDK は OS の機能を使用してこれを開きます。
event_params dictionary クリック イベントに関する追加情報を含む辞書。SDK はこれを使用します。

コンテンツ カードのボタンがクリックされたデータ

キー タイプ 説明
title 文字列 カードのタイトル。
title 文字列 カードのタイトル。
link 文字列 ウェブページのリンクまたはディープリンク。SDK は OS の機能を使用してこれを開きます。
event_params dictionary クリック イベントに関する追加情報を含む辞書。SDK はこれを使用します。

クイック返信のクリックデータ

キー タイプ 説明
title 文字列 カードのタイトル。
title 文字列 カードのタイトル。
link 文字列 ウェブページのリンクまたはディープリンク。SDK は OS の機能を使用してこれを開きます。
event_params dictionary クリック イベントに関する追加情報を含む辞書。SDK はこれを使用します。

メッセージ リンクのクリックデータ

キー タイプ 説明
event_name 文字列 イベント名(「Message Link Clicked」など)が含まれます。
link 文字列 ウェブページ リンクまたはディープリンク。SDK は OS の機能を使用してこれを開きます。

CRM にカスタムデータを送信する

カスタムデータはサポート エージェントに送信され、着信通話/チャットのサポート チケットに表示されます。

カスタムデータを送信するには、次の 2 つの方法があります。

  • 署名付きメソッド: 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));
        }
        // ...
    }
}

署名なしのメソッドを使用してカスタムデータを送信する

アプリケーションでカスタムデータを送信するには、署名付きメソッドを使用することをおすすめします。詳細については、署名付きメソッドを使用してカスタムデータを送信するをご覧ください。

署名されていないデータを送信するには、UjetStartOptions.Builder#setUnsignedCustomData を使用してカスタムデータを設定する開始オプションを指定して Android SDK を起動します。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"
            }
        ]
        }
    ]
}

テキストタイプではマークダウンを使用できます。次の形式がサポートされています。

  • 太字

  • 斜体

  • 下線

  • 改行

  • 箇条書き

  • 番号付きリスト

  • リンク

カスタムデータ形式

このセクションでは、JWT で渡すことができるカスタムデータの形式について説明します。

JSON を JWT にエンコード

JSON には、JWT を検証するための iat と exp を含める必要があります。カスタムデータのオブジェクトは、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

    • integer、float
  • date

    • 13 桁の UTC Unix タイムスタンプ形式。(ミリ秒を含む)
  • url

    • HTTP URL 形式

ラベルは CRM ページの表示名です。

顧客データの表示を防止する

カスタム データ オブジェクトで invisible_to_agent プロパティを使用すると、署名付きまたは署名なしのカスタム データがエージェント アダプタに表示されないようにできます。前の例では、"invisible_to_agent" : true が ssn オブジェクトに含まれているため、エンドユーザーの社会保障番号はエージェント アダプタに表示されません。

カスタム データ オブジェクトに "invisible_to_agent" : true プロパティを含めると、次の動作が想定されます。

詳細については、エージェント アダプタでセッション データを表示するをご覧ください。

予約済みのデータ プロパティ

セッションの開始時に、予約済みのデータ プロパティを署名付きカスタムデータとしてコンタクト センター AI プラットフォーム(CCAI プラットフォーム)に送信できます。詳細については、予約済みデータ プロパティを送信するをご覧ください。

カスタムデータの予約済みデータ プロパティの例を次に示します。

  {
    "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 は、[設定] > [デベロッパー設定] > [MMA] > [ポップアップを編集] で [PSTN フォールバックを有効にする] がオンになっている場合にのみ、フォールバック番号を使用してユーザーをダイヤラーにリダイレクトします。それ以外の場合は 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 送信を有効にする])で設定する必要があります。

マニフェストにディープリンクを含むインテント フィルタを追加する必要があります。

<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 を非表示にする

Ujet.hideSDK() メソッドを使用して SDK を非表示にできます。これは、SDK がアプリのユーザー インターフェースに干渉する場合などに便利です。このメソッドを呼び出す前に、Ujet.init() を使用して SDK を初期化します。Ujet.init() は、SDK が正常に非表示になった場合は true を返し、それ以外の場合は false を返します。SDK を非表示にした後、Ujet.start() メソッドを使用して再度開始できます。

次の例では、SDK を非表示にしています。

Ujet.hideSDK();

外部デフレクション リンクのアイコンを設定する

外部偏向リンク チャネルのアイコンをカスタマイズするには、アプリのドローアブル フォルダにアイコンをアップロードします。CCAI Platform ポータルの [設定] > [チャット] > [外部偏向リンク] > [リンクを表示] > [偏向リンクを追加] で外部偏向リンクを作成するときに、同じアイコン名を使用してください。

CCAI Platform ポータルのアイコン名がアプリにアップロードされたアイコンと一致しない場合、Android SDK はデフォルトのアイコンを使用します。

アンケートのサンキュー アイコンを設定する

アンケートの手続き完了ページのアイコンをカスタマイズまたはオーバーライドするには、アプリの drawable フォルダにアイコンをアップロードし、ファイル名 ujet_survey_thank_you_icon をアイコン名として使用します。

UI と文字列のカスタマイズ

このセクションでは、文字列、コンテンツ カード、テーマ、チャット ヘッダーをカスタマイズする方法について説明します。

文字列

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>
    

チャット ヘッダーのタイトルをカスタマイズする

UI のチャットでチャット ヘッダーのタイトル テキストをカスタマイズするオプションがあります。

チャット ヘッダーのタイトル テキストは、次のオプションを使用してカスタマイズできます。

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

チャット UI でバーチャル エージェントのクイック返信をカスタマイズするには、次のオプションを使用します。

<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 ファイル(app/src/main/assets/json/ujet_styles.json ファイルの content_card property を参照)を使用するか、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 ファイルを使用するか(app/src/main/assets/json/ujet_styles.json ファイルの form_card プロパティを参照)、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,
        ),
    )
)

サーベイ

アンケートの完了ページのアイコンを変更するには、アプリの drawable フォルダにアイコンをアップロードします。

アイコン名として ujet_survey_thank_you_icon を使用してください。

画面共有の同意ダイアログをカスタマイズするには、CoBrowseAlertProvider 抽象クラスを実装します。DialogFragment または AlertDialog を使用して、カスタム同意ダイアログを実装できます。

  • DialogFragment を使用する場合は、同意を承諾するボタンと拒否するボタンの 2 つを含めます。カスタム DialogFragment インスタンスを dialogInstance コールバックに渡します。

  • AlertDialog を使用する場合は、DialogFragment インスタンスを dialogInstance コールバックに渡さないでください。

同意を取得したら、consentStatus コールバックを呼び出してブール値を渡すことで、SDK に同意を渡します。

次のコードサンプルを使用して、カスタム同意ダイアログを実装します。

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

次の API を使用して、この実装を SDK に渡します。

Ujet.setCoBrowseAlertProvider(CoBrowseAlertProviderImpl())

ウェブフォームを構成する

ウェブフォームを構成するには、UjetWebFormListener インターフェースの ujetWebFormDidReceive メソッドを実装します。このメソッドは、フォーム関連の情報を含むイベント(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. callback.onEvent(formDataEvent) を使用して、フォームデータを FormDataEvent マップとして SDK に渡します。
  4. URI または署名の生成中にエラーが発生した場合は、callback.onError() を使用してエラー コールバックを呼び出します。

SDK に渡されるマップ(FormDataEvent)は、次の構造にする必要があります。

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

次の API を使用して、この実装を SDK に渡します。

Ujet.setUjetWebFormListener(UjetWebFormListenerImpl())

トラブルシューティング

新しいチャットの開始に 30 秒以上かかった

顧客データのデリゲート メソッドに応答しているかどうかを確認します。リクエストに応じて有効なカスタムデータを返すか、コールバックで null を返す必要があります。次のコードを参考にしてください。

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

ポリシーの申告に関する説明

Android SDK で使用されるサービスまたは権限に関するポリシーを申告するよう求める通知が Google Play Console に表示された場合は、次のいずれかの説明を使用してください。

Android SDK で使用されるフォアグラウンド サービスを宣言する

Google は Android 14 でフォアグラウンド サービス タイプを導入し、フォアグラウンド サービスの開始時に指定することを義務付けました。詳しくは、https://developer.android.com/about/versions/14/changes/fgs-types-required#remote-messaging をご覧ください。Contact Center AI Platform(CCAI Platform)Android SDK は、フォアグラウンド サービスを使用してチャットと通話を開始します。そのため、テキスト メッセージを処理するチャットには FOREGROUND_SERVICE_REMOTE_MESSAGING サービスタイプを使用し、通話には FOREGROUND_SERVICE_MICROPHONE サービスタイプを使用しました。これらのサービスタイプがないと、Android 14 バージョンのデバイスからチャットまたは通話を開始する際に SDK がクラッシュします。

Android SDK で使用される全画面インテントの権限を宣言する

デバイスがロックされているときに着信のプッシュ通知を表示するには、USE_FULL_SCREEN_INTENT 権限が必要です。エンドユーザーにアラートを送信し、着信通知を全画面表示します(これは、組み込みの電話アプリがエンドユーザーに着信を通知する方法です)。

Android 15 をサポートする

Android 15 をサポートする手順は次のとおりです。

  1. build.gradle(:app) で compileSdkVersion = 35 と targetSdkVersion = 35 を設定します。

  2. プロジェクトの Android Gradle プラグイン(AGP)のバージョンが 8.5.1 以降であることを確認します。詳細については、共有ライブラリのパッケージを更新するをご覧ください。

  3. AGP 8.0 以降を使用して Android プロジェクトをビルドするには、Java Development Kit(JDK)バージョン 17 以降をインストールします。詳細については、AGP 8.0 の実行に JDK 17 が必要をご覧ください。