本文档介绍了如何开始使用适用于 iOS 的无头移动 SDK。
借助适用于 iOS 的无头移动 SDK,您可以将 CCAI 平台支持直接添加到自己的内置 iOS 体验中,而无需使用预构建的 CCAI 平台界面。
您无需展示 CCAI Platform 品牌的 widget,而是:
将 CCAI iOS SDK 集成到您的应用中。
构建您自己的界面、导航和视觉设计。
使用 SDK 可执行以下操作:
开始和管理聊天会话和语音会话。
提供电子邮件、预定通话和分流选项。
支持智能操作、附件和会话后流程(客户满意度 [CSAT]、调查问卷、虚拟客服)。
CCAI Platform 可处理联络中心逻辑(路由、队列、渠道、配置、报告)。您拥有整个应用体验(界面、流程和品牌)。
如果您不想自行构建界面,而是希望使用预建的可配置界面,请使用标准移动 SDK。
要求
以下是集成 Headless Mobile SDK for iOS 的要求。
iOS 平台要求
iOS 最低版本:iOS 16.6 或更高版本
语言:Swift
IDE:您的应用支持的最新稳定版 Xcode
架构:当前 Xcode 工具链支持的标准 iOS 架构。
应用权限
由于您的内置应用会处理智能操作(拍摄照片、录制视频或验证身份)的界面,因此您必须声明 Apple 的强制性隐私权限。
向 Info.plist 添加以下键,并说明您的应用如何使用相应数据:
NSCameraUsageDescription:用户拍摄和发送照片/视频或执行代理请求的智能操作时需要此权限。NSMicrophoneUsageDescription:即时语音通话和录制有声视频时需要此权限。NSPhotoLibraryUsageDescription:用户上传相机胶卷中的现有照片或视频时需要此权限。NSFaceIDUsageDescription:如果您支持生物识别验证智能操作,则必须提供此值。
CCAI Platform 实例要求
您需要访问 CCAI 平台实例的开发者设置,才能获取以下详细信息:
公司密钥
公司密码
主机网址 - CCAI 平台的主机名(例如
your_subdomain.ccaiplatform.com)
这些值用于:
公司密钥 + 主机网址:在 iOS 应用中初始化 SDK。
公司密钥:在后端用于对 JSON Web 令牌 (JWT) 进行签名,以对用户进行身份验证。
推送通知
对于通话和某些智能操作,您需要:
针对标准推送通知的 Apple 推送通知服务 (APNs) 配置。
用于支持来电和特定通话相关通知的 VoIP 服务证书。
您将学习以下内容:
在 Apple Developer 门户中配置 APNs 和 VoIP 凭据。
在 CCAI 平台管理员门户中,依次前往设置 > 开发者设置 > 移动应用,上传转换后的证书。
在应用中注册接收远程通知和 VoIP 推送。
将相应的设备令牌转发给 SDK。
在目标 > 签名和功能中,启用以下内容:
推送通知功能。
后台模式功能,并选中以下项:
IP 语音 - 对于 VoIP 推送通知(来电、使用 PSTN 的智能操作)是必需的。
音频、AirPlay 和画中画 - 当应用在后台运行时,需要此权限才能继续进行语音通话。
远程通知 - 标准 APNs 推送传送所必需。
无头 iOS SDK 如何融入您的应用
iOS 版无头移动 SDK 可以视为三个层:
CCAI Platform 平台和 SDK
该 SDK 可与 CCAI Platform 平台安全地互动,并提供以下功能:
使用 JSON Web 令牌 (JWT) 进行身份验证。
队列和渠道路由元数据(即时通讯、语音、预定通话、电子邮件、外部分流链接)。
实时会话状态管理。
用于智能操作、文件附件和屏幕共享的安全传输流水线。
分流逻辑和会话后层次结构评估。
您的 iOS 应用(界面和逻辑由您处理)
您可以控制整个视觉和导航体验:
入口点:例如帮助标签页或与我们联系按钮。
菜单:您如何显示队列(例如结算、技术支持)。
会话内界面:自定义聊天气泡、通话界面和控件。
应用的功能:调用 SDK API 来开始和结束会话、监听 SDK 事件,以及驱动视图控制器导航。
CCAI 平台管理员门户配置
CCAI 平台管理员配置互动规则(营业时间、可用渠道、等待时间阈值和调查问卷)。SDK 会读取此配置,并以原始数据和事件的形式将其公开给您的应用。您可以决定如何在屏幕上绘制该配置。
检索公司凭据
在集成 SDK 之前,请从 CCAI 平台实例获取凭据:
使用管理员账号登录 CCAI 平台管理员门户。
依次前往设置 > 开发者设置。
在公司密钥和密钥令牌下方,复制以下内容:
公司密钥
公司密码
记下您的主机网址:CCAI 平台的主机名(例如
your_subdomain.ccaiplatform.com)。
您将使用:
在 iOS 应用中:公司密钥 + 主机网址。
在后端服务器中:用于为 JWT 签名的公司密钥代码:
最终用户身份验证。
CCAI Platform 使用的可选自定义数据或上下文。
将 SDK 添加到您的 iOS 应用
无头 SDK 采用模块化架构构建。您需要安装核心 CCAIKit 以及应用所需的特定功能模块(例如 CCAIChat 或 CCAIScreenShare)。
如需在应用中集成 iOS SDK,请按以下步骤操作。
方案 A:Swift Package Manager(推荐)
请将以下内容添加到
Package.swift文件:dependencies: [ .package(url: "https://github.com/UJET/ccai-ios-sdk.git", from: "3.3.1") ], targets: [ .target( name: "YourTargetName", dependencies: [ .product(name: "CCAIKit", package: "CCAIKit") ] ) ]在
AppDelegate文件中导入CCAIKit:import CCAIKit如果您的项目是 SwiftUI 项目,请在
App结构体中声明@UIApplicationDelegateAdaptor:@main struct YourAppName: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate // ... }
初始化无头 SDK
在应用启动期间初始化 SDK。由于 SDK 采用模块化架构,您必须先初始化核心 CCAI 系统,然后注册特定的服务模块(例如聊天或屏幕共享)。
基本初始化
SDK 使用一个 InitOptions 结构体来捆绑所有必需的配置:
import CCAIKit
import CCAIChat // If using Chat
import CCAIScreenShare // If using Screen Share
class AppDelegate: NSObject, UIApplicationDelegate, CCAIDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 1. Configure initialization options
let options = InitOptions(
key: "YOUR_COMPANY_KEY",
urlHost: "your_subdomain.ccaiplatform.com",
delegate: self,
languageCode: "en", // ISO 639 code (defaults to "en")
cacheAuthToken: true // Whether to cache the auth token (defaults to true)
)
// 2. Initialize the core SDK
do {
try CCAI.shared.initialize(options: options)
} catch {
print("Failed to initialize CCAI: \(error.localizedDescription)")
return true
}
// 3. Initialize feature modules
// Chat minimal (no options required)
CCAI.shared.initializeChat()
// Chat with optional configuration
// let chatOptions = ChatOptions(
// delegate: webFormDelegate, // Implement to intercept and render custom web forms within your own UI
// downloadTranscriptVisibility: .hideInPostChat, // Hide the post-chat download affordance
// greeting: "Hello! How can I help you?"
// )
// CCAI.shared.initializeChat(chatOptions)
// Screen Share (optional)
// let screenShareOptions = ScreenShareOptions(
// key: "YOUR_SCREEN_SHARE_KEY",
// domain: "your_domain.com"
// )
// CCAI.shared.initializeScreenShare(screenShareOptions)
return true
}
// ... CCAIDelegate methods (Authentication) go here ...
}
InitOptions 配置参考文档
public struct InitOptions {
/// The company key used for authentication
public let key: String
/// The host URL for CCAI platform (for example, "my-unique-instance.uc1.ccaiplatform.com")
public let urlHost: String
/// The preferred language code for localization (defaults to "en")
public var languageCode: String
/// The delegate that receives SDK events and callbacks
public weak var delegate: CCAIDelegate?
/// Whether to cache the authentication token (defaults to true)
public let cacheAuthToken: Bool
}
可用的 SDK 服务
初始化后,您可以通过 CCAI.shared singleton 访问各种服务:
let authService = CCAI.shared.authService
let companyService = CCAI.shared.companyService
let queueMenuService = CCAI.shared.queueMenuService
let optionsService = CCAI.shared.optionsService
let languageService = CCAI.shared.languageService
let pushNotificationService = CCAI.shared.pushNotificationService
let endUserService = CCAI.shared.endUserService
let chatService = CCAI.shared.chatService // Only available after initializeChat()
let screenShareService = CCAI.shared.screenShareService // Only available after initializeScreenShare()
let rateService = CCAI.shared.rateService // For CSAT ratings and survey submission
let smartActionService = CCAI.shared.smartActionService // Dedicated service for smart action lifecycle
提取公司配置
初始化后,使用 companyService 获取公司级配置。这对于填充语言选择器、显示公司名称或在用户进入队列之前读取支持联系详情非常有用。
do {
let company = try await CCAI.shared.companyService?.get()
print("Company: \(company?.displayName ?? "Unknown")")
} catch {
print("Failed to get company info: \(error)")
}
对最终用户进行身份验证
Headless Mobile SDK 使用 JSON Web 令牌 (JWT) 对用户进行身份验证,并将情境信息安全地传递给客服人员的 CRM。
工作原理
该 SDK 使用简化的两步异步身份验证流程:
SDK 确定需要对用户进行身份验证。
它会调用您的
CCAIDelegate方法 -ccaiShouldAuthenticate()- 这是一个异步函数。您的应用使用公司密钥在后端服务器上远程签署 JWT。
然后,您的应用会将已签名的 JWT 传递给
CCAI.shared.authService?.authenticate(jwt),以换取身份验证令牌。身份验证令牌会返回到 SDK 以完成连接。
实现用于身份验证的 CCAIDelegate
您的应用必须实现 CCAIDelegate 协议。当 SDK 需要身份验证时,它会调用单个异步委托方法。
CCAIDelegate 协议
public protocol CCAIDelegate: AnyObject {
/// Authenticates the end user and returns an auth token
func ccaiShouldAuthenticate() async -> String?
}
实现示例 (Swift)
class AppDelegate: CCAIDelegate {
func ccaiShouldAuthenticate() async -> String? {
// 1. Sign JWT remotely on your backend server
guard let jwt = await signJWTRemotely() else { return nil }
// 2. Authenticate JWT using authService to get an auth token
return try? await CCAI.shared.authService?.authenticate(jwt)
}
}
包含 JWT 签名的完整示例,供参考和测试
class AuthController: CCAIDelegate {
func ccaiShouldAuthenticate() async -> String? {
var jwt = JWT(claims: claims)
// First, sign JWT with company secret (do this on your backend in production)
guard let secret = self.companySecret,
let key = secret.data(using: .utf8) else { return nil }
let signer = JWTSigner.hs384(key: key)
guard let encodedJWT = try? jwt.sign(using: signer) else { return nil }
// Then authenticate JWT using authService to get an auth token
return try? await CCAI.shared.authService?.authenticate(encodedJWT)
}
}
将自定义数据传递给 CRM
如果您想将情境数据传递给代理(例如用户的当前设备操作系统、位置或账号层级),您的后端必须在对 JWT 载荷进行签名之前将 custom_data 对象注入其中。
每条自定义数据都必须采用 JSON 对象格式,其中包含 label(代理看到的内容)、value 和 type。
支持的数据类型
string:标准文本(例如“iPhone 14 Pro”)。number:整数或浮点数(例如 1234 或 99.99)。date:一个 13 位数的 UTC Unix 时间戳,包含毫秒(例如 1537399655992)。url:标准 HTTP/HTTPS 网址格式。boolean:标准 true 或 false 值。
预留的 CRM 键
CCAI Platform 支持特定的预留键,这些键可触发平台中的内置行为,例如将用户标记为 VIP 或向客服人员发出有关作恶方的警告。这些必须采用布尔类型格式,并且只有在载荷使用安全的 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.shared.authService?.updateAuthToken("new_auth_token")
// Clear the current token (for example, on user logout)
CCAI.shared.authService?.updateAuthToken(nil)
自定义数据 JWT 载荷架构
当后端构建要使用公司密钥进行签名的最终载荷时,必须严格遵循此架构。请注意强制性 iat(签发时间)和 exp(失效时间)时间戳。
{
"iat": 1537399656,
"exp": 1537400256,
"custom_data": {
"os_version": {
"label": "OS Version",
"value": "16.4",
"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 使用推送通知来执行以下操作:
来电。
某些智能操作和与通话相关的事件。
在应用处于后台时保持状态。
配置证书
CCAI 平台要求在 CCAI 平台管理员门户中保存 两种不同类型的 Apple 推送证书:
Apple 推送通知服务 (APNs) SSL 证书 - 用于标准远程推送通知。
VoIP 服务证书 - 用于来电通知和某些与通话相关的智能操作。
这两个证书均在 Apple Developer 门户中创建,转换为 PEM 格式,然后上传到 CCAI Platform 管理员门户。
创建 APNs SSL 证书
请按照以下步骤(根据 Apple 的官方指南建立基于证书的 APNs 连接)创建 APNs SSL 证书。
登录 developer.apple.com,然后前往证书、标识符和个人资料。
选择 + 按钮以创建新证书。
在“服务”下,选择 Apple 推送通知服务 SSL(沙盒和生产环境)。
选择与应用的软件包标识符匹配的应用 ID,然后选择继续。
上传通过 Mac 上的“钥匙串访问”生成的证书签名请求 (CSR):
依次打开钥匙串访问 > 证书助理 > 从证书颁发机构请求证书…
输入您的电子邮件地址,将“CA 电子邮件地址”留空,选择保存到磁盘,然后选择继续。
选择继续,然后下载生成的
.cer文件。双击
.cer文件,将其安装到钥匙串中。在“钥匙串访问”中,找到已安装的证书,右键点击该证书,然后选择导出…以将其保存为
.p12文件。系统会提示您设置导出密码。使用
openssl将.p12文件转换为 PEM 格式:# Extract the certificate openssl pkcs12 -in apns_certificate.p12 -out apns_cert.pem -clcerts -nokeys # Extract the private key openssl pkcs12 -in apns_certificate.p12 -out apns_key.pem -nocerts -nodes # (Optional) Combine into a single PEM file cat apns_cert.pem apns_key.pem > apns_combined.pem
创建 VoIP 服务证书
借助 VoIP 服务证书,您的应用可以通过 Apple 的 PushKit 框架接收高优先级推送通知,从而可以在应用处于终止状态时将其唤醒以处理来电。如需查看最新的官方步骤,请参阅 Apple 开发者文档中的创建 VoIP 服务证书。
登录 developer.apple.com,然后前往证书、标识符和个人资料。
选择 + 按钮以创建新证书。
在“服务”下,选择 VoIP 服务证书。
选择与应用的软件包标识符匹配的应用 ID,然后选择继续。
上传您为 APNs SSL 证书生成的同一证书签名请求 (CSR)(或创建新的 CSR)。
选择继续,然后下载生成的
.cer文件。双击
.cer文件,将其安装到钥匙串中。在“钥匙串访问”中,找到已安装的 VoIP 服务证书,右键点击该证书,然后选择导出…以将其保存为
.p12文件。使用
openssl将.p12文件转换为 PEM 格式:# Extract the certificate openssl pkcs12 -in voip_certificate.p12 -out voip_cert.pem -clcerts -nokeys # Extract the private key openssl pkcs12 -in voip_certificate.p12 -out voip_key.pem -nocerts -nodes # (Optional) Combine into a single PEM file cat voip_cert.pem voip_key.pem > voip_combined.pem
将证书上传到 CCAI 平台管理员门户
登录 CCAI 平台管理员门户。
依次前往设置 > 开发者设置 > 移动应用。
上传 APNs PEM 证书。
上传 VoIP PEM 证书。
请求推送通知权限
该 SDK 提供了一种便捷方法来请求推送通知授权(仅限 iOS):
let options: UNAuthorizationOptions = [.alert, .sound]
try await CCAI.shared.pushNotificationService?.registerForPushNotifications(
options: options
) { granted in
if granted {
print("Push notifications granted")
} else {
print("Push notifications denied")
}
}
注册接收远程通知
在 AppDelegate 中实现推送通知委托。SDK 提供了用于转发令牌的 pushNotificationService:
import CCAIKit
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
CCAI.shared.pushNotificationService?.updatePushToken(
data: deviceToken,
type: .apns
)
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
CCAI.shared.pushNotificationService?.updatePushToken(
data: nil,
type: .apns
)
}
}
请务必在 Xcode 中通过 Target > Signing & capabilities(目标 > 签名和功能)标签页为远程通知启用功能 > 推送通知和后台模式。
处理传入的推送通知
收到推送载荷后,将其转发给 SDK 进行处理:
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
// Let the SDK determine if this push relates to an incoming call,
// session update, or another internal event
CCAI.shared.pushNotificationService?.handlePushNotification(userInfo)
completionHandler(.newData)
}
SDK 会确定推送是否与来电、会话更新或其他内部事件相关,并相应地处理推送。
注册接收 VoIP 推送通知
对于来电和某些 PSTN 智能操作,除了标准 APNs 令牌之外,SDK 还需要 VoIP 推送令牌。VoIP 推送以高优先级传送,并且可以从终止状态唤醒应用。
导入 PushKit 并在 AppDelegate 的 didFinishLaunchingWithOptions 中创建 PKPushRegistry
import PushKit
class AppDelegate: NSObject, UIApplicationDelegate, PKPushRegistryDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// ... SDK initialization ...
// Register for VoIP push notifications
let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
voipRegistry.delegate = self
voipRegistry.desiredPushTypes = [.voIP]
return true
}
}
实现 PKPushRegistryDelegate 方法,以将 VoIP 令牌和载荷转发到 SDK
// MARK: - PKPushRegistryDelegate
func pushRegistry(
_ registry: PKPushRegistry,
didUpdate credentials: PKPushCredentials,
for type: PKPushType
) {
// Forward the VoIP token to the SDK
CCAI.shared.pushNotificationService?.updatePushToken(
data: credentials.token,
type: .voip
)
}
func pushRegistry(
_ registry: PKPushRegistry,
didInvalidatePushTokenFor type: PKPushType
) {
// Clear the VoIP token
CCAI.shared.pushNotificationService?.updatePushToken(
data: nil,
type: .voip
)
}
func pushRegistry(
_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType,
completion: @escaping () -> Void
) {
guard type == .voIP else {
completion()
return
}
// Forward the VoIP payload to the SDK using the `handleVoIPPush`
// extension on `CCAI` (defined in the `CCAICall` module). The SDK
// takes ownership of the call lifecycle; invoke PushKit's completion
// handler in the trailing closure after the SDK has accepted the
// payload.
CCAI.shared.handleVoIPPush(payload: payload.dictionaryPayload) { completion() }
}