このドキュメントでは、Android アプリケーションで SDK を統合してカスタマイズする方法について説明します。
使ってみる
Android 向け Headless Mobile SDK を使用すると、CCAI プラットフォームのコンタクト センター機能を独自の組み込み Android UI に統合できます。
CCAI プラットフォームのブランドのウィジェットを表示する代わりに、次の操作を行います。
CCAI Android SDK モジュールを依存関係として追加します。
Kotlin(推奨)または Java で独自の画面、フロー、ビジュアル デザインを作成します。
SDK を使用して次の操作を行います。
チャット セッションと音声セッションを開始して管理します。
メール、音声通話、回避のオプションを提示します。
スマート アクション、添付ファイル、セッション後のフロー(CSAT、アンケート、仮想エージェント)をサポートします。
CCAI プラットフォームは、コンタクト センターのロジック(ルーティング、キュー、チャネル、構成、レポート)を処理します。アプリのすべてのエクスペリエンス(UI、フロー、ブランディング)は、お客様が所有します。
構成可能なテーマ設定を備えた事前構築済みの UI を使用する場合は、標準のモバイル SDK を使用します。
要件と対応環境
このセクションでは、Android 向け Headless Mobile SDK の要件とサポートされている環境について説明します。
Android プラットフォームの要件
Android には、次のプラットフォーム要件が適用されます。
最小 Android バージョン: Android 6.0(API レベル 23)以降
コンパイル SDK: 36(推奨)
サポートされている言語: Kotlin(推奨)または Java
Java の互換性: Java 17 以降
Gradle / Android Studio: アプリと使用している SDK リリースに対応する最新の Android Gradle プラグインと Android Studio のバージョン
Kotlin バージョン: 1.6.0 以降
CCAI プラットフォーム インスタンスの要件
次の情報を取得するには、CCAI プラットフォーム インスタンスのデベロッパー設定にアクセスする必要があります。
会社キー
会社の秘密コード
ホスト URL - CCAI プラットフォームのホスト名(例: your_subdomain.ccaiplatform.com)
これらの値は次の目的で使用されます。
Company key と Host URL - SDK を初期化するために Android アプリで使用します。
会社の秘密コード - ユーザーの認証に使用される JSON Web Token(JWT)に署名するためにバックエンドで使用されます。
ネットワーキングと権限
アプリでは、CCAI Platform エンドポイントと構成した音声プロバイダ エンドポイントへの送信トラフィックを許可する必要があります。
一般的な Android の権限には、次のようなものがあります(実際のリストは SDK のバージョンと機能セットによって異なる場合があります)。
インターネット / ネットワークの状態: すべての SDK 通信。
マイク: 音声通話に使用します。
Notifications: Firebase Cloud Messaging(FCM)プッシュ通知用。
ストレージ / メディア: 添付ファイル用。
カメラ: スマート アクションで写真や動画を撮影する場合に使用します。
画面キャプチャ: 画面共有用(
MediaProjection)。
Android OS のガイドラインに沿って実行時の権限を宣言してリクエストします。
プッシュ通知
Headless Android SDK は、FCM を使用して次のものを配信します。
着信通知。
スマート アクションと通話に関連する一部のメッセージ。
アプリがバックグラウンドに移行したときに状態を維持するためのアップデート。
以下のものが必要になります。
Firebase プロジェクト
アプリ モジュール内の有効な google-services.json。
アプリでの FCM トークンの処理と登録。
アプリ内のカスタム通知と通話 UI。
ヘッドレス Android SDK がアプリにどのように適合するか
Android 向け Headless Mobile SDK は、3 つのレイヤで構成されていると考えることができます。
CCAI プラットフォームと SDK(CCAI プラットフォームによって処理)
SDK は CCAI プラットフォームと安全にやり取りし、次の機能を提供します。
JSON Web Token(JWT)を使用した認証。
キューとチャネルのルーティング メタデータ(チャット、音声通話、メール、外部のたらい回しリンク)。
サービス オブジェクト(
chatService、queueMenuServiceなど)を使用したリアルタイム セッション状態管理。スマート アクション、添付ファイル、画面共有の安全な転送パイプライン。
セッション後の階層評価と回避ロジック。
Android アプリ(UI とロジック - お客様が処理)
視覚的なエクスペリエンスとナビゲーション エクスペリエンス全体を制御できます。
エントリ ポイント: [ヘルプ] タブや [お問い合わせ] ボタンなど。
メニュー: キューの表示方法(例: Billing、Tech support)。
セッション中の UI: カスタム チャット バブル、通話画面、コントロール。
アプリの動作: SDK サービス API を呼び出してセッションを開始および終了し、Kotlin Coroutines と Flow を使用して SDK イベントを監視し、コンポーネント ナビゲーションを制御します。
CCAI プラットフォーム管理ポータルの構成
CCAI プラットフォーム管理者は、エンゲージメント ルール(営業時間、利用可能なチャネル、待ち時間しきい値、アンケート)を構成します。SDK はこの構成を読み取り、未加工のデータとイベントとしてアプリに公開します。画面にその構成を描画する方法を決定します。
会社の認証情報を取得する
SDK を統合する前に、CCAI Platform インスタンスから認証情報を取得します。
管理者アカウントで CCAI プラットフォーム管理ポータルにログインします。
[設定] > [デベロッパー向けの設定] に移動します。
[Company key & secret code] で、次のものをコピーします。
会社キー
会社の秘密コード
ホスト URL(CCAI プラットフォームのホスト名。例:
your_subdomain.ccaiplatform.com)をメモします。
使用するサービス:
Android アプリの場合: 会社キーとホスト URL。
バックエンド サーバー: エンドユーザー認証用の JWT の署名に使用される会社の秘密コードと、CCAI Platform で使用されるオプションのカスタムデータとコンテキスト。
Android アプリに SDK を追加する
Headless SDK はモジュール式アーキテクチャを使用します。アプリに必要な特定の機能モジュール(CCAIChat や CCAIScreenShare など)とともに、コア CCAIKit をインストールします。
CCAI Maven リポジトリを追加する
CCAI Maven リポジトリをプロジェクトの settings.gradle.kts(またはルート build.gradle)に追加します。
// settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://sdk.ujet.co/ccaip/android/") }
}
}
Gradle バージョン カタログを構成する(推奨)
Google Cloud では、SDK 依存関係の管理に Gradle バージョン カタログを使用することをおすすめします。gradle/libs.versions.toml に次の行を追加します。
[versions]
ccaiVersion = "3.3.1"
[libraries]
ccai-kit = { group = "com.ccaiplatform.android", name = "CCAIKit", version.ref = "ccaiVersion" }
ccai-chat = { group = "com.ccaiplatform.android", name = "CCAIChat", version.ref = "ccaiVersion" }
ccai-chat-red = { group = "com.ccaiplatform.android", name = "CCAIChatRed", version.ref = "ccaiVersion" }
ccai-call = { group = "com.ccaiplatform.android", name = "CCAICall", version.ref = "ccaiVersion" }
ccai-call-red = { group = "com.ccaiplatform.android", name = "CCAICallRed", version.ref = "ccaiVersion" }
ccai-screenshare = { group = "com.ccaiplatform.android", name = "CCAIScreenShare", version.ref = "ccaiVersion" }
依存関係を追加する
アプリレベルの build.gradle.kts で、コア SDK と特定の機能モジュールを追加します。
// app/build.gradle.kts
android {
compileSdk = 36
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
}
dependencies {
// 1. Core (always required)
implementation(libs.ccai.kit)
// 2. Chat (required for chat sessions)
implementation(libs.ccai.chat)
implementation(libs.ccai.chat.red) // media layer paired with CCAIChat
// 3. Voice (required for instant calls, voicemail, and scheduled calls)
implementation(libs.ccai.call)
implementation(libs.ccai.call.red) // media/transport layer paired with CCAICall
// 4. Screen Share (optional)
// implementation(libs.ccai.screenshare)
}
バージョン カタログを使用していない場合は、依存関係を直接宣言できます。
val ccaiVersion = "3.3.1"
dependencies {
implementation("com.ccaiplatform.android:CCAIKit:$ccaiVersion")
implementation("com.ccaiplatform.android:CCAIChat:$ccaiVersion")
implementation("com.ccaiplatform.android:CCAIChatRed:$ccaiVersion")
implementation("com.ccaiplatform.android:CCAICall:$ccaiVersion") // Voice calls
implementation("com.ccaiplatform.android:CCAICallRed:$ccaiVersion") // Twilio VoIP backend
implementation("com.ccaiplatform.android:CCAIScreenShare:$ccaiVersion") // Optional, for screen share
}
初期化と設定
アプリの起動時に SDK を初期化します。SDK のモジュール式アーキテクチャにより、最初にコア CCAI プラットフォーム システムを初期化してから、特定のチャネル プロバイダ(chat や screen share など)を登録します。
CCAIDelegate インターフェースを実装する
SDK は、認証コールバックに CCAIDelegate インターフェースを使用します。重要なメソッドは、JWT が必要なときに SDK が呼び出す Kotlin の suspend 関数 ccaiShouldAuthenticate() です。
import com.ccaiplatform.ccaikit.CCAIDelegate
class MyCCAIDelegate : CCAIDelegate {
/**
* Called by the SDK when it needs a signed JWT for authentication.
* This is a suspend function - you can make network calls here.
*
* @return The auth token returned by `authService.authenticate(jwt)`,
* or null on failure. This is what the SDK expects - not the raw JWT.
*/
override suspend fun ccaiShouldAuthenticate(): String? {
return try {
// 1. Call your backend server to get a signed JWT
val jwt = MyBackendApi.getSignedJwt() ?: return null
// 2. Exchange the JWT for an auth token using authService - this is
// what the SDK expects to be returned (not the raw JWT).
CCAI.authService?.authenticate(jwt)
} catch (e: Exception) {
null // Return null to signal authentication failure
}
}
}
上記のスニペットは、最小限の 2 ステップのフロー(署名 → 認証 → 戻り値)を示しています。
完全な認証コントラクトについては、エンドユーザーを認証してカスタムデータを渡すをご覧ください。
- バックエンドで JWT に署名する方法、
authenticate(jwt)がどのように認証トークンと交換するか、- トークンのキャッシュ保存と無効化、
- エラー処理を含む例。
アプリケーション クラスで SDK を初期化する
CCAI シングルトン オブジェクトを使用して、カスタム アプリケーション クラスで SDK を初期化します。
import android.app.Application
import com.ccaiplatform.ccaikit.CCAI
import com.ccaiplatform.ccaikit.InitOptions
import com.ccaiplatform.ccaichat.initializeChat
import com.ccaiplatform.ccaichat.model.ChatOptions
import com.ccaiplatform.ccaicall.initializeCall
import com.ccaiplatform.ccaikit.initializeScreenShare
import com.ccaiplatform.ccaikit.models.screenShare.ScreenShareOptions
class MainApplication : Application() {
private val delegate = MyCCAIDelegate()
override fun onCreate() {
super.onCreate()
// 1. Build InitOptions
val initOptions = InitOptions(
key = "YOUR_COMPANY_KEY",
urlHost = "your_subdomain.ccaiplatform.com",
languageCode = "en", // Optional: ISO 639 code
delegate = delegate // Your delegate implementation
)
// 2. Initialize the core SDK
CCAI.initialize(
context = this,
options = initOptions
)
// 3. Initialize chat (minimal)
CCAI.initializeChat(context = this)
// Initialize chat (with optional configuration)
// val chatOptions = ChatOptions(
// webFormInterface = null, // Implement to intercept and render custom web forms within your own UI
// downloadTranscriptVisibility = DownloadTranscriptVisibility.SHOW_ALL,
// greeting = "Hello! How can I help you?"
// )
// CCAI.initializeChat(
// context = this,
// options = chatOptions
// )
// 4. Initialize call (required whenever your app uses voice or scheduled calls)
CCAI.initializeCall(context = this)
// 5. Initialize screen share (optional)
// CCAI.initializeScreenShare(
// context = this,
// options = ScreenShareOptions(
// key = "YOUR_COMPANY_KEY",
// domain = "your_subdomain.ccaiplatform.com"
// )
// )
}
}
InitOptions 構成リファレンス
data class InitOptions(
/// The company key used for authentication
var key: String,
/// The host URL for CCAI platform (for example, "my-unique-instance.uc1.ccaiplatform.com")
var urlHost: String,
/// The preferred language code for localization (defaults to "en")
var languageCode: String? = "en",
/// Listener that handles authentication
var delegate: CCAIDelegate? = null,
/// Whether to cache the authentication token (defaults to true)
var cacheAuthToken: Boolean = true
)
AndroidManifest.xml を更新します
カスタム アプリケーション クラスが登録されていることを確認します。
<application
android:name=".MainApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.YourApp">
</application>
利用可能な SDK サービス
初期化後、CCAI シングルトン オブジェクトを介してさまざまなサービスにアクセスできます。
val authService = CCAI.authService
val companyService = CCAI.companyService
val queueMenuService = CCAI.queueMenuService
val optionsService = CCAI.optionsService
val languageService = CCAI.languageService
val pushNotificationService = CCAI.pushNotificationService
val chatService = CCAI.chatService // Only available after initializeChat()
val screenShareService = CCAI.screenShareService // Only available after initializeScreenShare()
val rateService = CCAI.rateService // For CSAT ratings and survey submission
val callService = CCAI.callService // Only available after initializeCall()
会社の構成を取得しています
初期化後、companyService を使用して会社レベルの構成を取得できます。これは、言語選択ツールへの入力、会社名の表示、ユーザーがキューに入る前のサポート連絡先の詳細の読み取りに役立ちます。
// Fetch company details
val company = CCAI.companyService?.get()
// CompanyResponse contains:
// - displayName: String
// - supportEmail: String?
// - languages: List<String>
// - phoneNumber: String?
// ...
エンドユーザーを認証してカスタムデータを渡す
Android 用 Headless Mobile SDK は、JSON Web Token(JWT)を使用してユーザーを認証し、コンテキスト情報をエージェントの CRM に安全に渡します。
仕組み
SDK は、簡略化された 2 段階の非同期認証フローを使用します。
SDK はユーザーの認証が必要であると判断します。
suspend 関数である
CCAIDelegateメソッド(ccaiShouldAuthenticate())を呼び出します。アプリは、`Company
アプリは、
Company Secret Codeを使用してバックエンド サーバーで JWT にリモートで署名します。アプリは署名付き JWT を
CCAI.authService?.authenticate(jwt)に渡し、認証トークンと交換します。認証トークンが SDK に返され、接続が完了します。
認証用の CCAIDelegate を実装する
アプリは CCAIDelegate インターフェースを実装する必要があります。認証が必要な場合、SDK は最初の suspend メソッドを呼び出します。
CCAIDelegate インターフェース
interface CCAIDelegate {
suspend fun ccaiShouldAuthenticate(): String?
}
実装例(Kotlin)
class CCAIDelegate : CCAIDelegate {
override suspend fun ccaiShouldAuthenticate(): String? {
// 1. Sign JWT remotely on your backend server
val jwt = signJWTRemotely() ?: return null
// 2. Authenticate JWT using authService to get an auth token
return try {
CCAI.authService?.authenticate(jwt)
} catch (e: Exception) {
null
}
}
}
JWT 署名を含む完全な例(参照とテストのみ)
class AuthController : CCAIDelegate {
override suspend fun ccaiShouldAuthenticate(): String? {
// First, sign JWT with company secret (do this on your backend in production)
val jwt = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS384, companySecret?.encodeToByteArray())
.compact()
// Then authenticate JWT using authService to get an auth token
return try {
CCAI.authService?.authenticate(jwt)
} catch (e: Exception) {
null
}
}
}
カスタムデータを CRM に渡す
コンテキスト データ(ユーザーの現在のデバイスの OS、位置情報、アカウントの階層など)をエージェントに渡す場合は、バックエンドで JWT ペイロードに custom_data オブジェクトを挿入してから署名する必要があります。
カスタムデータはそれぞれ、ラベル(エージェントに表示されるもの)、値、タイプを含む JSON オブジェクトとしてフォーマットする必要があります。
サポートされるデータタイプ
string: 標準テキスト(例: 「Google Pixel 8 Pro」)。number: 整数または浮動小数点数(1234 や 99.99 など)。date: ミリ秒を含む 13 桁の UTC Unix タイムスタンプ(例: 1537399655992)。url: 標準の HTTP/HTTPS URL 形式。boolean: 標準の true または false 値。
エージェントの可視性: 必要に応じて、人間のエージェントには表示されないが、転送やバックエンド分析に使用できるデータを CCAI プラットフォームに渡すことができます。これを行うには、データ オブジェクトに "invisible_to_agent": true を含めます。
予約済みの CRM キー
CCAI Platform は、プラットフォームの組み込み動作をトリガーする特定の予約済みキーをサポートしています。たとえば、ユーザーを VIP としてフラグ設定したり、悪意のあるユーザーについてエージェントに警告したりできます。これらは boolean タイプとしてフォーマットする必要があります。ペイロードが安全な JWT メソッドを使用して署名されている場合にのみ受け入れられます。
reserved_verified_customer: お客様が社内システムで正常に認証されたかどうかを示します。reserved_bad_actor: ユーザーをエージェントに対してスパムまたは不正なアカウントとして報告します。reserved_repeat_customer: このお客様が最近サポートに頻繁に連絡しているかどうかを示します。
予約済みキーを含むペイロードの例
{
"iat": 1537399656,
"exp": 1537400256,
"custom_data": {
"reserved_verified_customer": {
"label": "Verified Customer",
"value": true,
"type": "boolean"
},
"reserved_bad_actor": {
"label": "Bad Actor",
"value": false,
"type": "boolean"
},
"reserved_repeat_customer": {
"label": "Repeat Customer",
"value": false,
"type": "boolean"
}
}
}
認証トークンを管理する
SDK には、キャッシュに保存された認証トークンを手動で更新またはクリアするメソッドが用意されています。
// Set a new auth token
CCAI.authService?.updateAuthToken("new_auth_token")
// Clear the current token (for example, on user logout)
CCAI.authService?.updateAuthToken(null)
カスタムデータ JWT ペイロード スキーマ
バックエンドで Company
Secret Code を使用して署名する最終的なペイロードを構築する際は、このスキーマに厳密に準拠する必要があります。必須の iat(発行日)と exp(有効期限)のタイムスタンプに注意してください。
{
"iat": 1537399656,
"exp": 1537400256,
"custom_data": {
"os_version": {
"label": "OS Version",
"value": "14.0",
"type": "string"
},
"membership_tier": {
"label": "Membership Tier",
"value": "Platinum",
"type": "string"
},
"ssn_last_four": {
"label": "SSN",
"value": "1234",
"type": "string",
"invisible_to_agent": true
},
"reserved_verified_customer": {
"label": "Verified Customer",
"value": true,
"type": "boolean"
}
}
}
プッシュ通知を有効にする
SDK は、次の目的でプッシュ通知を使用します。
着信。
特定のスマート アクションと通話関連のイベント。
アプリがバックグラウンドにあるときに状態を維持する。
Firebase の設定
Firebase プロジェクトを作成するか、既存の Firebase プロジェクトを使用します。
Android アプリを登録して
google-services.jsonファイルをダウンロードします。google-services.jsonをアプリ モジュール ディレクトリに配置します。ルートレベルの
build.gradle.ktsで、Google サービス プラグインを追加します。// build.gradle.kts (Project) plugins { id("com.google.gms.google-services") version "4.4.2" apply false }アプリレベルの
build.gradle.ktsで、プラグインを適用し、Firebaseの依存関係を追加します。// app/build.gradle.kts plugins { id("com.google.gms.google-services") } dependencies { // Firebase BoM for version management implementation(platform("com.google.firebase:firebase-bom:33.5.1")) implementation("com.google.firebase:firebase-messaging") }プロジェクトを同期します。
FCM トークンを SDK に登録する
pushNotificationService を通じて FCM プッシュトークンを登録し、受信した FCM データ ペイロードを SDK に転送します。お客様向けの通知や通話中の UI のレンダリングは、アプリの責任で行います。
onMessageReceived を実装する
FCM を使用している場合は、プッシュ通知用のリスナーを FirebaseMessagingService クラスに実装します。これらが実装されていない場合、サービスは正常に機能しません。
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.ccaiplatform.ccaikit.CCAI
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class MyFirebaseMessagingService : FirebaseMessagingService() {
private val scope = CoroutineScope(Dispatchers.IO)
override fun onMessageReceived(remoteMessage: RemoteMessage) {
scope.launch {
// Forward CCAI platform push notifications to the SDK.
CCAI.pushNotificationService?.handlePushNotification(remoteMessage.data)
// Render any customer-facing notification UI in your own app code.
MyNotificationRenderer.showIfNeeded(application, remoteMessage.data)
}
}
}
onNewToken を実装する
また、トークンの更新を処理する onNewToken メソッドも実装します。これにより、Android 向け Headless Mobile SDK が最新のプッシュ通知トークンを受け取ります。
class MyFirebaseMessagingService : FirebaseMessagingService() {
// ...
override fun onNewToken(token: String) {
// Fetch the updated token from Firebase and update it in CCAI
CCAI.pushNotificationService?.updatePushToken(token)
}
}
AndroidManifest.xml にサービスを登録する
システムがサービスにプッシュ メッセージを配信できるように、Firebase Messaging Service を AndroidManifest.xml に追加します。
<application>
<service
android:name=".firebase.MyFirebaseMessagingService"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
初期トークン登録
アプリの起動時(SDK の初期化後)に、現在の FCM トークンを事前に登録します。
import com.google.firebase.messaging.FirebaseMessaging
// In your Application.onCreate(), after CCAI.initialize()
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
val token = task.result
CCAI.pushNotificationService?.updatePushToken(token)
}
}
通知権限の処理(Android 13 以降)
Android 13(API レベル 33)では、前述のアプリは POST_NOTIFICATIONS 実行時の権限をリクエストする必要があります。SDK には、このための組み込みユーティリティが用意されています。
import com.ccaiplatform.ccaikit.util.PermissionUtil
// Request notification permissions from the user
PermissionUtil.requestPermissionsForNotifications(activity)
// Check if permissions have been granted
val isGranted = PermissionUtil.isPermissionsForNotificationsGranted(context)
if (isGranted) {
Log.d("CCAI", "Push notifications permitted")
}
FCM トークンを登録する前に、アプリのライフサイクルの早い段階(オンボーディングや初回起動時など)でこのメソッドを呼び出して、プッシュ通知を配信できるようにします。