SDK seluler Contact Center AI Platform (CCAI Platform) untuk sistem operasi Apple iOS memberikan kemampuan untuk menyematkan pengalaman seluler CCAI Platform dalam aplikasi seluler iOS.
Persyaratan
SDK seluler iOS memiliki persyaratan berikut:
- iOS 12.0+
Mengambil kredensial perusahaan
Login ke portal Contact Center AI Platform (CCAI Platform) menggunakan kredensial Admin.
Buka Setelan > Setelan Developer.
Di bagian Company Key dan Secret Code, catat Company Key dan Company Secret Code.
Memulai
Berikut adalah panduan tentang cara memulai penggunaan SDK seluler iOS CCAI Platform.
Penginstalan
Untuk memulai, Anda perlu menginstal iOS SDK.
Download aplikasi contoh
Download Aplikasi Contoh iOS.
Buka folder dan instal dependensi menggunakan CocoaPods:
$ pod install --project-directory=ExampleAppUntuk mengonfigurasi setelan project dengan cepat, jalankan skrip shell:
$ ./setup.shAtau, Anda dapat mengedit setelan project secara manual dengan mengikuti langkah-langkah berikut:
Buka
ExampleApp.xcworkspace.Ganti nilai
UJETCompanyKeydanUJETCompanySecretdiInfo.plistdengan nilai Kunci Perusahaan dan Kode Rahasia Perusahaan dari halaman Setelan > Setelan Developer di portal Platform CCAI.Ganti nilai
UJETSubdomaindiInfo.plistdengan subdomain di URL untuk portal CCAI Platform Anda. Subdomain langsung mendahului.ujet.comdi URL—misalnya,your-subdomaindihttps://your-subdomain.ujet.com/settings/developer-setting.
Mengintegrasikan ke project Anda
Integrasi iOS SDK dengan aplikasi Anda bergantung pada lingkungan pengembangan Anda.
Pengelola paket Swift
Tambahkan Swift Package for iOS SDK.
Di setelan build Anda, masukkan -ObjC di Other Linker Flags.
Mulai rilis Xcode terbaru (saat ini 13.2), ada masalah umum dengan penggunaan framework biner yang didistribusikan menggunakan Swift Package Manager. Solusi sementara untuk masalah ini adalah menambahkan Fase Skrip Pengoperasian ke Tahapan Build project Xcode Anda. Fase Skrip yang Dijalankan ini harus dilakukan setelah fase build Embed Frameworks. Fase Run Script baru ini harus berisi kode berikut:
find "${CODESIGNING_FOLDER_PATH}" -name '*.framework' -print0 | while read -d $'0' framework do codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}" done
CocoaPods
Tambahkan baris berikut ke Podfile:
pod 'UJET', :podspec => 'https://sdk.ujet.co/ios/x.y.z/ujet.podspec' #specific version x.y.zJalankan pod install. Jika iOS SDK telah diintegrasikan sebelumnya, jalankan pod update CCAI Platform.
Carthage
Google Cloud merekomendasikan penggunaan pengelola dependensi atau integrasi manual karena dependensi Platform CCAI tidak mendukung Carthage. Untuk melakukannya, tambahkan baris berikut:
binary "https://sdk.ujet.co/ios/UJETKit.json
binary "https://sdk.ujet.co/ios/UJETFoundationKit.json
binary https://raw.githubusercontent.com/twilio/twilio-voice-ios/Releases/twilio-voice-ios.json
Integrasi manual
Hal ini tidak didukung: https://github.com/twilio/conversations-ios/issues/12.
biner https://raw.githubusercontent.com/twilio/conversations-ios/master/twilio-convo-ios.json
Jalankan
carthage bootstrap --use-xcframeworks(ataucarthage update --use-xcframeworks(jika Anda memperbarui dependensi).Download
UJETKit.xcframework,UJETFoundationKit.xcframework,UJETChatRedKit.xcframework,UJETChatBlueKit.xcframework,UJETTwilioCallKit.xcframework, dan semua dependensiTwilioVoice.xcframeworkdanTwilioConversationsClient.xcframework.Tambahkan UJETKit.xcframework ke target Anda dengan menariknya ke bagian Frameworks, Libraries, and Embedded Content.
Ulangi Langkah 2 dan 3 pada semua dependensi dari Langkah 1.
Di Build Settings, tetapkan
-ObjCkeOther Linker Flags.Tambahkan
libc++.tbdsebagai dependensi di bagianLinked Frameworkstarget.
Jika Anda akan membuat SDK secara manual dengan project contoh, gunakan langkah-langkah di bagian berikut.
Bangun SDK secara manual dengan project contoh
Ikuti langkah-langkah berikut secara berurutan:
Download semua framework termasuk
UJETKit.xcframeworkdan dependensi lainnya.Buat folder CCAI Platform di root project dan ekstrak semua framework.
Pilih target dan build
Objc-ManualatauSwift-Manual.
Framework impor
Bagian berikut memberikan petunjuk tentang cara mengimpor framework.
Project Objective-C
@import UJETKit;
Swift Project
swiftimport
UJETimport UJETKit
Lakukan inisialisasi SDK
Lakukan inisialisasi CCAI Platform dengan UJET_COMPANY_KEY dan UJET_SUBDOMAIN.
In application:didFinishLaunchingWithOptions: method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize CCAI Platform
[UJET.initialize:UJET_COMPANY_KEY subdomain:UJET_SUBDOMAIN delegate:self];
// YOUR CODE
return YES;
}
Anda dapat mengubah level log dari verbose menjadi error. Level log default adalah
UjetLogLevelInfo.
[UJET.setLogLevel:UjetLogLevelVerbose];
Autentikasi pengguna akhir
Akses iOS SDK melalui aplikasi iOS.
Untuk memastikan pengguna akhir diautentikasi, kami memperkenalkan mekanisme penandatanganan JWT.
SDK iOS akan meminta untuk menandatangani payload saat autentikasi diperlukan. Jika penandatanganan berhasil, aplikasi akan menukar JWT yang ditandatangani dengan token autentikasi pengguna akhir. Blok keberhasilan atau kegagalan harus dipanggil sebelum delegasi ditampilkan.
Untuk pengguna anonim (identifier = nil), aplikasi akan membuat UUID untuk pengguna. Jika di lain waktu pengguna diautentikasi dengan ID, aplikasi akan mencoba menggabungkan kedua pengguna berdasarkan UUID.
Di UJETObject.h dari contoh project:
@import UJETKit;
@interface UJETObject : NSObject <UJETDelegate>
Implementasikan signPayload: payloadType: success: failure: delegate method.
- (void)signPayload:(NSDictionary *)payload payloadType:(UjetPayloadType)payloadType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
if (payloadType == UjetPayloadAuthToken) {
[self signAuthTokenInLocal:payload success:success failure:failure];
}
}
- (void)signAuthTokenInLocal:(NSDictionary *)payload success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
NSMutableDictionary *payloadData = [payload mutableCopy];
NSDictionary *userData = [[NSUserDefaults standardUserDefaults] objectForKey:@"user-data"];
[payloadData addEntriesFromDictionary:userData];
payloadData[@"iat"] = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]; // required
payloadData[@"exp"] = [NSNumber numberWithDouble:([[NSDate date] timeIntervalSince1970] + 600)]; // required
NSString *signedToken = [self encodeJWT:payloadData];
if (signedToken.length > 0) {
success(signedToken);
} else {
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Failed to sign token" };
NSError *error = [NSError errorWithDomain:@"ExampleApp" code:0 userInfo:userInfo];
failure(error);
}
}
- (NSString *)encodeJWT:(NSDictionary *)payload {
id<JWTAlgorithm> algorithm = [JWTAlgorithmHSBase algorithm384];
NSString *secret = NSBundle.mainBundle.infoDictionary[@"UJETCompanySecret"];
return [JWTBuilder encodePayload:payload].secret().algorithm(algorithm).encode;
}
Sebaiknya tanda tangani payload dari server aplikasi Anda, bukan di klien.
Contoh ini menggunakan penandatanganan lokal untuk tujuan pengujian. Lihat
signDataInRemote: success: failure: dalam file UJETObject.m.
Untuk mengetahui informasi selengkapnya, lihat Autentikasi pengguna akhir SDK.
Menyiapkan notifikasi push
Aplikasi mengirimkan notifikasi push untuk meminta Smart Action seperti verifikasi dan foto, serta melaporkan panggilan masuk. Aplikasi memerlukan dua jenis sertifikat yang berbeda (VoIP dan APNs) untuk disimpan di Admin Portal.
Menyiapkan sertifikat layanan VoIP
Dokumentasi referensi tersedia untuk notifikasi push VoIP Apple.
Buat dan download sertifikat VoIP dari situs developer Apple.
Klik dua kali sertifikat untuk menambahkannya ke Keychain.
Mulai aplikasi Keychain Access di Mac Anda.
Pilih kategori Sertifikat Saya di sidebar sebelah kiri.
Klik kanan VoIP Services: your.app.id certificate.
Di menu pop-up, pilih Ekspor.
Simpan sebagai cert.p12 tanpa melindunginya dengan sandi dengan mengosongkan sandi.
Jalankan perintah berikut di terminal.
openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -debug -showcertBagian atas cert.pem adalah sertifikat dan bagian bawah adalah kunci pribadi.
Periksa apakah sertifikat Anda berfungsi dengan server push notification Apple.
openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -debug -showcertsJika berhasil, perintah akan menampilkan:
--- New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA Session-ID: Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None Start Time: 1475785489 Timeout : 300 (sec) Verify return code: 0 (ok) ---Login ke portal Platform CCAI dengan kredensial administrator, lalu buka Settings > Developer Settings > Mobile App.
Isi sertifikat di bagian 'VoIP Services Certificate', lalu simpan. Pastikan untuk menyertakan batas (
-----BEGIN-----dan-----END-----) untuk sertifikat dan kunci pribadi.Centang kotak Sandbox jika Anda menjalankan aplikasi dengan profil penyediaan pengembangan seperti saat men-debug di Xcode. Jika aplikasi Anda diarsipkan untuk Ad hoc atau App store dan menggunakan profil penyediaan distribusi, hapus centang kotak Sandbox.
Menyiapkan SSL layanan push notification Apple
Proses untuk hal ini mirip dengan proses untuk sertifikat layanan VOIP. Dalam kasus ini, sertifikat SSL layanan push notification Apple (Sandbox & Production) digunakan. Anda dapat membaca dokumentasi server notifikasi jarak jauh Apple untuk mendapatkan panduan tentang cara membuat sertifikat.
Mengintegrasikan notifikasi push
Di AppDelegate.m:
@import PushKit;
@interface AppDelegate() <PKPushRegistryDelegate>
In application:didFinishLaunchingWithOptions: method:
// Initialize CCAI Platform
[UJET] initialize:UJET_COMPANY_KEY subdomain:UJET_SUBDOMAIN delegate:self];
// Register for VoIP notifications on launch.
PKPushRegistry *voipRegistry = [[PKPushRegistry alloc] initWithQueue: dispatch_get_main_queue()];
voipRegistry.delegate = self;
voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
Tambahkan metode delegasi berikut dalam menerapkan file protokol UIApplicationDelegate:
Cetak token perangkat Anda untuk menguji notifikasi push.
// PKPushRegistryDelegate
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
[UJET updatePushToken:credentials.token type:UjetPushTypeVoIP];
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
if (payload.dictionaryPayload[@"ujet"]) {
[UjetreceivedNotification:payload.dictionaryPayload completion:completion];
} else {
completion();
}
}
// UIApplicationDelegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[UjetupdatePushToken:deviceToken type:UjetPushTypeAPN];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
if (userInfo[@"ujet"]) {
[UJET receivedNotification:userInfo completion:nil];
}
}
// UserNotificationsDelegate overrides [UIApplicationDelegate didReceiveRemoteNotification:]
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
NSDictionary *userInfo = notification.request.content.userInfo;
if (userInfo[@"ujet"] != nil) {
[UJET receivedNotification:userInfo completion:nil];
}
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[@"ujet"] != nil) {
[UJET receivedNotification:userInfo completion:nil];
}
}
Aktifkan notifikasi push
Pilih target Anda dan buka tab Kemampuan.
Aktifkan tombol Push Notifications.
Menguji notifikasi push
Bagian berikut memberikan panduan tentang cara menguji notifikasi push.
Bagian debug notifikasi push
Di portal administrator, buka Setelan > Setelan Developer. Di halaman ini, temukan bagian berjudul Push Notification Debug:

Salin dan tempel token perangkat di area teks kanan, lalu pilih Aplikasi Seluler yang benar.
Mendapatkan token perangkat
Contoh string token perangkat terlihat seperti ini:
7db0bc0044c8a203ed87cdab86a597a2c43bf16d82dae70e8d560e88253364b7
Notifikasi push biasanya disetel di class yang sesuai dengan protokol UIApplicationDelegate atau PKPushRegistryDelegate. Pada titik tertentu, token perangkat tersedia untuk Anda. Anda dapat mencetaknya sebelum meneruskannya ke iOS SDK. Untuk mendapatkan token perangkat, gunakan cuplikan kode.
Swift
func tokenFromData(data: Data) -> String {
return data.map { String(format: "%02x", $0) }.joined()
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("apns token: ", tokenFromData(data: deviceToken))
...
}
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
print("voip token: ", tokenFromData(data: credentials.token))
...
}
Obj-C
- (NSString *)tokenFromData:(NSData *)data {
const char *d = data.bytes;
NSMutableString *token = [NSMutableString string];
for (NSUInteger i = 0; i < data.length; i++) {
[token appendFormat:@"%02.2hhX", d[i]];
}
return [[token copy] lowercaseString];
}
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
NSLog(@"voip token: %@", [self tokenFromData:credentials.token]);
...
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(@"apns token: %@", [self tokenFromData:deviceToken]);
}
Hasil
Setelah Anda memasukkan file PEM sertifikat dan token perangkat, klik tombol.
Hasilnya akan menampilkan pesan Notifikasi push berhasil dikonfigurasi jika notifikasi push pengujian berhasil dikirim.
Notifikasi push tidak dijamin 100% akan terkirim, bergantung pada koneksi jaringan perangkat.
Konfigurasi project
Bagian berikut menguraikan perubahan yang diperlukan untuk mengonfigurasi project.
Kemampuan
Di setelan target, aktifkan kemampuan berikut:
Notifikasi Push
Mode Latar Belakang (periksa item ini)
Audio dan AirPlay
Voice over IP
Info.plist
Untuk melindungi privasi pengguna, aplikasi iOS apa pun yang ditautkan pada atau setelah iOS 10.0 yang mengakses mikrofon, galeri foto, dan kamera perangkat, harus menyatakan niat untuk melakukannya. Sertakan kunci berikut dengan nilai string dalam file Info.plist aplikasi Anda dan berikan string tujuan untuk kunci ini. Jika aplikasi Anda mencoba mengakses mikrofon, library foto, dan kamera perangkat tanpa string tujuan yang sesuai, aplikasi akan keluar.
NSMicrophoneUsageDescription: Mengizinkan akses ke mikrofon untuk melakukan panggilan dan berbicara dengan tim dukungan atau tim pemecahan masalah, serta untuk mengirim video dengan suara terkait pertanyaan produk.
NSCameraUsageDescription: Mengizinkan akses ke kamera agar pelanggan dapat mengambil dan mengirim foto yang terkait dengan pertanyaan dukungan pelanggan mereka.
NSPhotoLibraryUsageDescription: Mengizinkan pelanggan mengirim foto yang terkait dengan pertanyaan dukungan pelanggan mereka.
NSFaceIDUsageDescription: Mengizinkan akses ke verifikasi menggunakan Face ID.
Mulai iOS SDK
Tambahkan baris berikut di tempat Anda ingin memulai iOS SDK:
[UJET startWithOptions:nil];
Anda juga dapat memulai iOS SDK dari titik tertentu di menu dengan kunci ini menggunakan Titik Akses Langsung:
UJETStartOptions *option = [[UJETStartOptions alloc] initWithMenuKey:@"MENU_KEY"];
[UJET startWithOptions:option];
menuKey dapat dibuat dengan membuat Titik Akses Langsung (DAP). Langkah-langkah berikut memberikan petunjuk tentang cara membuat DAP:
Login ke portal CCAI Platform dengan kredensial administrator.
Buka Setelan > Antrean.
Pilih antrean apa pun dari struktur menu.
Pilih Buat titik akses langsung
Masukkan kunci di formulir teks.
Klik Simpan.

Hapus cache dari lokal jika data pengguna telah diperbarui
Kami menyimpan token autentikasi dalam Keychain untuk digunakan kembali dan membuat permintaan tanda tangan payload dari aplikasi host menjadi lebih jarang. SDK akan menggunakannya hingga habis masa berlaku atau dicabut melalui panggilan clearUserData. Aplikasi host bertanggung jawab untuk mencabut cache ini setiap kali data terkait pengguna telah berubah atau diperbarui, seperti peristiwa logout.
[UJET clearUserData];
Memeriksa sesi yang ada sebelum memulai Contact Center AI Platform
Sebelum memulai sesi, periksa untuk melihat apakah tidak ada sesi saat ini. Hal ini sangat penting jika userId telah berubah.
[UJET getStatus];
Jika ada sesi yang sudah ada, kita harus meminta pengguna untuk melanjutkan sesi atau membatalkan tindakan:
if ([UJET getStatus] != UjetStatusNone) {
// Display alert to cancel login or resume existing session
}
Sesuaikan
Ada beberapa opsi tema SDK yang tercantum di UJETGlobalTheme.h.
Tetapkan tema Anda setelah [UJET initialize]—misalnya:
UJETGlobalTheme *theme = [UJETGlobalTheme new];
theme.font = [UIFont fontWithName:@"OpenSans" size: 16.0f];
theme.lightFont = [UIFont fontWithName:@"OpenSans-Light" size: 16.0f];
theme.boldFont = [UIFont fontWithName:@"OpenSans-Bold" size: 16.0f];
theme.tintColor = [UIColor colorWithRed:0.243 green:0.663 blue:0.965 alpha:1.00];
[Ujet setGlobalTheme:theme];

Nama perusahaan diambil dari Admin Portal > Setelan > Detail Pusat Dukungan > Nama Tampilan.
Anda dapat menyetel gambar logo, bukan nama perusahaan, seperti ini:
theme.companyImage = [UIImage imageNamed:@"logo"];

Ukuran gambar akan diubah agar sesuai dengan area jika terlalu besar.
String
Anda juga dapat menyesuaikan string dengan mengganti nilainya. Misalnya, masukkan pasangan kunci - nilai ini di Localizable.strings Anda:
"ujet_greeting_title" = "Title";
"ujet_greeting_description" = "Description";

String yang dapat disesuaikan yang tersedia tercantum dalam file ujet.strings.
Mode gelap
Anda dapat menentukan warna yang diinginkan untuk mode gelap agar font lebih mudah dibaca.
@property (nonatomic, strong) UIColor \*tintColorForDarkMode;
Jika Anda tidak menyetel properti, UJETGlobalTheme.tintColor akan digunakan untuk mode gelap. Sebaiknya setel properti ini jika aplikasi Anda mendukung mode gelap. Lihat artikel Apple berikut tentang cara memilih warna tint yang tepat untuk mode gelap:
Tema chat
Untuk menyesuaikan layar chat, Anda memiliki opsi untuk menggunakan string JSON atau setiap class tema.
Sebagai referensi, lihat aplikasi contoh dan hapus komentar metode customizeChatTheme
ini.
func customizeChatTheme() throws {
guard let file = Bundle.main.path(forResource: "chat-theme-custom", ofType: "json") else { return }
let json = try String.init(contentsOfFile: file, encoding: .utf8)
let chatTheme = UJETChatTheme.init(jsonString: json)
let quickReplyTheme = UJETChatQuickReplyButtonTheme()
quickReplyTheme.style = .individual
quickReplyTheme.alignment = .right
quickReplyTheme.backgroundColor = UJETColorRef(assetName: "white_color")
quickReplyTheme.backgroundColorForHighlightedState = UJETColorRef(assetName: "quick_reply_color")
quickReplyTheme.textColor = UJETColorRef(assetName: "quick_reply_color")
quickReplyTheme.textColorForHighlightedState = UJETColorRef(assetName: "white_color")
let fontTheme = UJETFontTheme()
fontTheme.family = "Arial Rounded MT Bold"
fontTheme.size = 14
quickReplyTheme.font = fontTheme
chatTheme?.quickReplyButtonTheme = quickReplyTheme
let globalTheme = UJETGlobalTheme()
globalTheme.chatTheme = chatTheme
globalTheme.defaultAgentImage = UIImage(named: "agent_avatar_image")
globalTheme.font = UIFont(name: "Arial Rounded MT Bold", size: 14)
UJET.setGlobalTheme(globalTheme)
}

Tema kartu konten
Anda dapat menambahkan penyesuaian untuk kartu konten bersama dengan penyesuaian chat.
Anda dapat melakukannya menggunakan file json (lihat properti content_card) atau dengan
menggunakan class UJETChatContentCardTheme.
func customizeChatTheme() throws {
guard let file = Bundle.main.path(forResource: "chat-theme-custom", ofType: "json") else { return }
let json = try String.init(contentsOfFile: file, encoding: .utf8)
let chatTheme = UJETChatTheme.init(jsonString: json)
let contentCardTheme = UJETChatContentCardTheme()
contentCardTheme.backgroundColor = UJETColorRef(assetName: "agent_message_background_color")
contentCardTheme.cornerRadius = 16
let contentCardFontTheme = UJETFontTheme()
contentCardFontTheme.family = "Arial Rounded MT Bold"
contentCardFontTheme.size = 18
contentCardTheme.font = contentCardFontTheme
let contentCardBorder = UJETBorderTheme()
contentCardBorder.width = 1
contentCardBorder.color = UJETColorRef(assetName: "agent_message_border_color")
contentCardTheme.border = contentCardBorder
let contentCardFontTheme = UJETFontTheme()
contentCardFontTheme.family = "Arial Rounded MT Bold"
contentCardFontTheme.size = 18
contentCardTheme.font = contentCardFontTheme
// The font family is inherited from the contentCardFontTheme
let subtitle = UJETFontTheme()
subtitle.size = 12
contentCardTheme.subtitle = subtitle
// The font family is inherited from the contentCardFontTheme
let bodyFont = UJETFontTheme()
bodyFont.size = 10
contentCardTheme.body = bodyFont
theme.chatTheme?.contentCard = contentCardTheme
let globalTheme = UJETGlobalTheme()
globalTheme.chatTheme = chatTheme
globalTheme.defaultAgentImage = UIImage(named: "agent_avatar_image")
globalTheme.font = UIFont(name: "Arial Rounded MT Bold", size: 14)
UJET.setGlobalTheme(globalTheme)
}

Tema kartu formulir
Anda dapat menambahkan penyesuaian untuk kartu formulir bersama dengan penyesuaian chat. Lakukan
ini dengan menggunakan file json (lihat form_card property) atau dengan menggunakan
class UJETChatFormCardTheme.
func customizeChatTheme() throws {
guard let file = Bundle.main.path(forResource: "chat-theme-custom", ofType: "json") else { return }
let json = try String.init(contentsOfFile: file, encoding: .utf8)
let chatTheme = UJETChatTheme.init(jsonString: json)
let formCardTheme = UJETChatFormCardTheme()
formCardTheme.backgroundColor = UJETColorRef(assetName: "agent_message_background_color")
formCardTheme.cornerRadius = 16
let formCardFontTheme = UJETFontTheme()
formCardFontTheme.family = "Arial Rounded MT Bold"
formCardFontTheme.size = 18
formCardTheme.font = formCardFontTheme
let formCardBorder = UJETBorderTheme()
formCardBorder.width = 1
formCardBorder.color = UJETColorRef(assetName: "agent_message_border_color")
formCardTheme.border = formCardBorder
let titleFontTheme = UJETFontTheme()
titleFontTheme.family = "Arial Rounded MT Bold"
titleFontTheme.size = 18
formCardTheme.title = titleFontTheme
// The font family is inherited from the formCardFontTheme
let subtitleFontTheme = UJETFontTheme()
subtitleFontTheme.size = 12
formCardTheme.subtitle = subtitleFontTheme
chatTheme?.formCard = formCardTheme
let globalTheme = UJETGlobalTheme()
globalTheme.chatTheme = chatTheme
globalTheme.defaultAgentImage = UIImage(named: "agent_avatar_image")
globalTheme.font = UIFont(name: "Arial Rounded MT Bold", size: 14)
UJET.setGlobalTheme(globalTheme)
}
Konfigurasi formulir web
Untuk mengonfigurasi kemampuan formulir web, terapkan metode ujetWebFormDidReceive
protokol UJETDelegate. Metode ini menerima peristiwa (kamus
FormMessageReceivedEvent) sebagai parameter, yang berisi informasi
terkait formulir. Kamus peristiwa (FormMessageReceivedEvent) mencakup struktur JSON berikut:
{
"type": "form_message_received",
"smart_action_id": 1,
"external_form_id": "external_foobar"
"signature": "4868a7e1dcb5..."
}
Untuk menangani peristiwa, lakukan hal berikut:
Ekstrak informasi yang relevan dari kamus peristiwa (
smart_action_id,external_form_id, dansignature).Buat URI formulir dan tanda tangan untuk data formulir.
Teruskan data formulir ke SDK sebagai kamus
FormDataEventmenggunakancompletion closure.Jika terjadi error selama pembuatan URI/tanda tangan, panggil callback menggunakan
callback.onError()denganError.
Kamus (FormDataEvent) yang diteruskan ke SDK harus memiliki struktur berikut:
{
"type": "form_data",
"signature": "4868a7e1dcb5...",
"data": {
"smart_action_id":1,
"external_form_id": "form_id",
"uri":"foobar"
}
}
Tanda tangan (HMAC-SHA:256) harus dibuat menggunakan data, ditandatangani dengan
kunci rahasia bersama. Kunci objek data harus diurutkan secara alfabet sebelum
menghasilkan tanda tangan dan data yang sama harus dikirim ke SDK.
Transfer setelah sesi
Anda dapat menambahkan penyesuaian untuk va pasca-sesi bersama dengan penyesuaian chat.
Hal ini dapat dilakukan menggunakan file JSON (lihat properti post_session) atau menggunakan class UJETChatPostSessionVaTheme. Lebar batas hanya dapat berupa 0 atau 1, dan jika Anda tidak ingin membedakan pengalaman VA pasca-sesi, Anda dapat menyetel containerColor putih dan batas ke 0.
func customizeChatTheme() throws {
guard let file = Bundle.main.path(forResource: "chat-theme-custom", ofType: "json") else { return }
let json = try String.init(contentsOfFile: file, encoding: .utf8)
let chatTheme = UJETChatTheme.init(jsonString: json)
let postSessionVaTheme = UJETChatPostSessionVaTheme()
postSessionVaTheme.containerColor = UJETColorRef(assetName: "white_color")
let postSessionVaBorder = UJETBorderTheme()
postSessionVaBorder.width = 0
postSessionVaBorder.color = UJETColorRef(assetName: "white_color")
containerColor.border = postSessionVaBorder
chatTheme?.postSessionVaTheme = postSessionVaTheme
let globalTheme = UJETGlobalTheme()
globalTheme.chatTheme = chatTheme
UJET.setGlobalTheme(globalTheme)
}
Menu tindakan chat
Anda dapat menambahkan penyesuaian untuk menu tindakan chat bersama dengan penyesuaian chat. Hal ini dapat dilakukan dengan menggunakan file JSON (lihat properti form_card) atau dengan menggunakan class UJETChatActionMenuTheme.
func customizeChatTheme() throws {
guard let file = Bundle.main.path(forResource: "chat-theme-custom", ofType: "json") else { return }
let json = try String.init(contentsOfFile: file, encoding: .utf8)
let chatTheme = UJETChatTheme.init(jsonString: json)
let actionMenuTheme = UJETChatActionMenuTheme()
let photoLibraryIcon = UJETChatUserInputIconTheme()
photoLibraryIcon.visible = true
photoLibraryIcon.image = UJETImageRef(assetName: "library_button_asset")
let cameraIcon = UJETChatUserInputIconTheme()
cameraIcon.visible = true
cameraIcon.image = UJETImageRef(assetName: "camera_button_asset")
let cobrowseIcon = UJETChatUserInputIconTheme()
cobrowseIcon.visible = true
cobrowseIcon.image = UJETImageRef(assetName: "cobrowse_button_asset")
actionMenuTheme.libraryIcon = photoLibraryIcon
actionMenuTheme.cameraIcon = cameraIcon
actionMenuTheme.cobrowseIcon = cobrowseIcon
chatTheme?.actionMenu = actionMenuTheme
let globalTheme = UJETGlobalTheme()
globalTheme.chatTheme = chatTheme
UJET.setGlobalTheme(globalTheme)
}
Penampilan lainnya
Anda dapat menyesuaikan tampilan lain seperti ukuran font dan warna latar belakang.
theme.supportTitleLabelFontSize = 30;
theme.supportDescriptionLabelFontSize = 20;
theme.supportPickerViewFontSize = 30;
theme.staticFontSizeInSupportPickerView = YES;
theme.backgroundColor = UIColor.darkGrayColor;
theme.backgroundColorForDarkMode = UIColor.lightGrayColor;

CallKit
Di iOS 10.0 dan yang lebih baru, CallKit diaktifkan untuk semua panggilan.
Dengan CallKit, panggilan masuk dalam aplikasi ditampilkan dengan layar panggilan dan panggilan ditampilkan di histori panggilan ponsel.
Untuk memulai sesi dukungan CCAI Platform baru dari histori panggilan, tambahkan blok berikut ke AppDelegate.m Anda:
AppDelegate.m:
- (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler {
if ([userActivity.activityType isEqualToString:@"INStartAudioCallIntent"]) {
// Open app from Call history
[UJET startWithOptions:nil];
}
return YES;
}
CallKit memungkinkan ikon 40x40 ditampilkan di layar kunci saat menerima panggilan saat perangkat terkunci. Tempatkan gambar di Xcassets Anda yang bernama 'icon-call-kit'.
Mengonfigurasi SDK
Anda dapat menyetel beberapa opsi sebelum memulai SDK.
Lihat class UJETGlobalOptions untuk mengetahui detailnya.
UJETGlobalOptions *options = [UJETGlobalOptions new];
options.fallbackPhoneNumber = @"+18001112222";
options.preferredLanguage = @"en";
[UJET setGlobalOptions:options];
Menampilkan atau menyembunyikan tombol download transkrip
Anda dapat mengonfigurasi SDK untuk menampilkan atau menyembunyikan tombol download transkrip di menu opsi chat dan di layar pasca-chat.
Kode berikut menunjukkan cara mengonfigurasi tombol download transkrip:
typedef NS_OPTIONS(NSUInteger, UJETChatDownloadTranscriptVisibilityOptions) {
UJETChatDownloadTranscriptVisibilityOptionsShowAll = 0,
UJETChatDownloadTranscriptVisibilityOptionsHideFromOptionsMenu = 1 << 0,
UJETChatDownloadTranscriptVisibilityOptionsHideFromPostChatScreen = 1 << 1,
UJETChatDownloadTranscriptVisibilityOptionsHideAll = UJETChatDownloadTranscriptVisibilityOptionsHideFromOptionsMenu | UJETChatDownloadTranscriptVisibilityOptionsHideFromPostChatScreen
};
@property (nonatomic, assign) UJETChatDownloadTranscriptVisibilityOptions transcriptVisibilityOptions;
Pengganti PSTN
Kami menyediakan penggantian PSTN untuk beberapa situasi:
Jaringan seluler sedang offline.
Backend aplikasi tidak dapat dijangkau.
VoIP tidak tersedia
Kondisi jaringan tidak cukup baik untuk terhubung. Lihat properti UJETGlobalOptions.pstnFallbackSensitivity untuk mengetahui detailnya.
Terjadi kegagalan selama koneksi karena konfigurasi firewall atau masalah penyedia.
Sebaiknya tetapkan nomor IVR perusahaan Anda di UJETGlobalOptions.fallbackPhoneNumber. Format yang direkomendasikan adalah + diikuti dengan kode negara dan nomor telepon. Misalnya. +18001112222.
Sensitivitas Pengalihan PSTN
Anda dapat menyesuaikan tingkat sensitivitas pemeriksaan kondisi jaringan untuk penggantian PSTN.
@property (nonatomic, assign) float pstnFallbackSensitivity;
Nilai harus dalam rentang 0,0 hingga 1,0. Jika disetel ke 1, panggilan akan selalu terhubung melalui PSTN, bukan VoIP. Latensi maksimum dan nilai minimum bandwidth masing-masing adalah 10000 md dan 10 KB/dtk untuk nilai 0. Misalnya, nilai 0, 5 berarti latensi dan bandwidth minimum masing-masing adalah 5.000 md dan 15 KB/dtk.
Nilai ini dapat dikonfigurasi dengan mengikuti langkah-langkah berikut:
Login ke portal CCAI Platform sebagai administrator.
Buka Setelan > Setelan Developer > Aplikasi Seluler.
Cari bagian Nilai minimum nomor telepon cadangan. Nilai defaultnya adalah 0,85.
Tentukan nilai batas baru.
Klik Save.
Menonaktifkan notifikasi push di tingkat global
Anda dapat menonaktifkan notifikasi push di tingkat global. Menetapkan properti
berikut ke false akan melewati semua dependensi notifikasi push dan mencegah
notifikasi push menjangkau pengguna akhir:
@property (nonatomic, assign) BOOL allowsPushNotifications;
Mengabaikan mode gelap
Anda dapat mengabaikan mode gelap di CCAI Platform SDK secara khusus dengan properti ini:
@property (nonatomic, assign) BOOL ignoreDarkMode;
Menyembunyikan Status Bar
Anda dapat mengontrol visibilitas status bar dengan properti ini:
@property (nonatomic, assign) BOOL hideStatusBar;
Secara default, hideStatusBar disetel ke false dan visible.
Melewati survei CSAT
Anda dapat menambahkan tombol yang memungkinkan pengguna melewati survei CSAT. Contoh kode berikut menunjukkan cara menambahkan tombol:
let options = UJETGlobalOptions()
options.skipCsat = true
Menyesuaikan indikator aktivitas
Anda dapat menambahkan animasi pemuat Anda sendiri (di dalam UIView) ke SDK dan mengganti UIActivityIndicatorView default. Terapkan metode
ujet_activityIndicator dari UJETDelegate dan tampilkan
tampilan yang disesuaikan.
public func ujet_activityIndicator() -> UIView! {
let loader = UIView.init()
let animation = CABasicAnimation()
loader.backgroundColor = .blue
loader.layer.cornerRadius = 15
animation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.easeOut)
animation.keyPath = "transform.scale"
animation.duration = 1.0
animation.fromValue = 0.0
animation.toValue = 1.0
animation.repeatCount = Float.infinity
animation.isRemovedOnCompletion = false
loader.layer.add(animation, forKey: "Load")
return loader
}
Jika Anda telah menyetel UIUserInterfaceStyle sebagai Light di Info.plist aplikasi untuk menonaktifkan mode gelap sepenuhnya, Anda dapat mengabaikan properti ini.
Bahasa pilihan
CCAI Platform SDK akan menggunakan urutan prioritas berikut untuk menentukan bahasa pilihan.
Bahasa yang dipilih dari layar pembuka dalam aplikasi.
Bahasa default dipilih dari
UJETGlobalOptions. Anda dapat menyetel bahasa default dengan propertipreferredLanguage. Kode bahasa yang didukung dapat ditemukan dalam fileUJETGlobalOptions.h.Bahasa perangkat yang dipilih di perangkat (dari Setelan > Umum > Bahasa & Wilayah) akan digunakan, jika didukung oleh aplikasi.
Dialek yang paling dekat dengan bahasa perangkat akan digunakan jika aplikasi tidak mendukung bahasa perangkat, tetapi mendukung dialek induk terdekatnya. Misalnya, jika pengguna memilih bahasa Spanyol Kuba sebagai bahasa di perangkat dan aplikasi tidak mendukung bahasa Spanyol Kuba, tetapi mendukung bahasa Spanyol induk, maka bahasa Spanyol akan digunakan.
Bahasa Inggris akan digunakan jika bahasa perangkat tidak didukung oleh aplikasi.
Mengonfigurasi ikon link pengalihan eksternal
Anda dapat menyesuaikan ikon di saluran link pengalihan eksternal dengan mengupload ikon ke katalog aset aplikasi dan pastikan untuk menggunakan nama ikon yang sama saat membuat link pengalihan eksternal di Setelan > Chat > Link Pengalihan Eksternal > Lihat link > Tambahkan Link Pengalihan di Portal Admin. Jika nama ikon di Admin Portal tidak cocok dengan ikon yang diupload ke aplikasi, SDK akan menggunakan ikon default. Anda dapat melihat link ini untuk mengetahui cara menambahkan gambar di katalog aset.



Pengganti
Anda dapat menggunakan fungsi didHandleUjetError untuk penggantian error yang tidak terduga. Jika Anda tidak menggunakan fungsi ini atau fungsi ini menampilkan false, iOS SDK akan menangani error.
Tabel berikut menunjukkan error yang dipantau oleh fungsi didHandleUjetError:
| Jenis error | Kode error | Deskripsi |
|---|---|---|
networkError |
1 | Jaringan tidak tersedia. Catatan: Error ini tidak dipicu saat jaringan tidak tersedia selama sesi chat atau panggilan atau layar pemberian rating. |
authenticationError |
100 | Terjadi error tidak terduga saat autentikasi. |
authenticationJwtError |
101 | Terjadi error yang tidak terduga selama validasi JWT—misalnya, error penguraian. |
voipConnectionError |
1000 | Gagal membuat koneksi ke penyedia VoIP. Callback VoIP SDK menangani hal ini. |
voipLibraryNotFound |
1001 | Sistem mengharapkan panggilan terhubung melalui penyedia VoIP, tetapi tidak dapat menemukannya. Hal ini dapat terjadi jika Anda mengintegrasikan SDK yang salah atau tidak menambahkan library penyedia VoIP ke dependensi Anda. |
chatLibraryNotFound |
1.100 | Terjadi saat sistem tidak dapat menemukan library chat. Hal ini dapat terjadi saat Anda mengintegrasikan SDK yang salah atau tidak menambahkan library chat Twilio ke dependensi Anda. |
Contoh kode berikut menunjukkan cara menggunakan fungsi didHandleUjetError:
public func didHandleUjetError(_ errorCode: Int32) -> Bool {
guard let ujetError = UjetErrorCode(rawValue: Int(errorCode)) else {
return false // Let the SDK handle unknown integer codes.
}
switch ujetError {
case .networkError:
// Example for if you have a custom UI for network errors. You can
// handle the error and prevent the SDK from showing its own alert.
showCustomNetworkAlert() // Your custom UI for this type of error.
return true
case .authenticationError, .voipConnectionError:
// For all other errors, use the default SDK behavior.
return false
@unknown default:
// Let the SDK handle future errors.
return false
}
}
Mengirim data kustom ke CRM Anda
Anda dapat mengirim data kustom ke tiket CRM.
Ada dua metode untuk mengirim data kustom:
Metode aman: penandatanganan data yang telah ditentukan sebelumnya dengan JWT.
Metode tidak aman: data yang telah ditentukan dengan JSON biasa (Tidak direkomendasikan).
Menggunakan metode aman untuk mengirim data kustom
Anda harus menerapkan metode penandatanganan. Pertama, Anda dapat menempatkan data kustom di sisi klien, dan mengirimkannya ke server untuk ditandatangani. Di server, Anda dapat menambahkan data tambahan dengan formulir yang ditentukan dan menandatanganinya dengan company.secret Anda, lalu menampilkannya dengan JWT.
- (void)signPayload:(NSDictionary *)payload payloadType:(UjetPayloadType)payloadType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure
{
if (payloadType == UjetPayloadCustomData) {
// sign custom data using UJET_COMPANY_SECRET on your server.
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] init];
mutableRequest.URL = [NSURL URLWithString:@"https://your.company.com/api/ujet/sign/custom_data"];
mutableRequest.HTTPMethod = @"POST";
NSError *error;
// Make client's custom data
UJETCustomData *customData = [[UJETCustomData alloc] init];
[customData set:@"name" label:@"Name" stringValue:@"USER_NAME"];
[customData set:@"os_version" label:@"OS Version" stringValue:[[UIDevice currentDevice] systemVersion]];
[customData set:@"model" label:@"Model number" numberValue:[NSNumber numberWithInteger:1234]];
[customData set:@"temperature" label:@"Temperature" numberValue:[NSNumber numberWithFloat:70.5]];
[customData set:@"purchase_date" label:@"Purchase Date" dateValue:[NSDate date]];
[customData set:@"dashboard_url" label:@"Dashboard" urlValue:[NSURL URLWithString:@"http://internal.dashboard.com/1234"]];
NSDictionary *data = @{@"custom_data": [customData getData]};
mutableRequest.HTTPBody = [NSJSONSerialization dataWithJSONObject:data options:0 error:&error];
NSURLSessionDataTask *task = [session dataTaskWithRequest:mutableRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(error) {
failure(error);
}
else {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
success(json[@"jwt"]);
}
}];
[task resume];
}
}
Menggunakan metode yang tidak aman untuk mengirim data kustom
Metode ini tidak direkomendasikan karena berpotensi menimbulkan kerentanan yang
dapat membuka aplikasi Anda terhadap serangan man-in-the-middle. Jika Anda memilih untuk menggunakan
metode ini, kami tidak bertanggung jawab atas eksposur keamanan dan potensi
kerusakan yang mungkin terjadi. Sebaiknya gunakan metode aman yang dijelaskan sebelumnya untuk mengirim data kustom di aplikasi Anda. Atau, Anda dapat memulai iOS SDK dengan instance UJETCustomData. Dalam hal ini, delegasi signPayload untuk
UJETPayloadCustomData hanya boleh memanggil success(nil);.
- (void)signPayload:(NSDictionary *)payload payloadType:(UjetPayloadType)payloadType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
if (payloadType == UjetPayloadCustomData) {
success(nil);
}
}
UJETStartOptions *options = [UJETStartOptions new];
options.unsignedCustomData = customData;
[UJET startWithOptions:options];
Menggunakan data kustom yang tidak bertanda untuk mengirim transkrip chat eksternal
Anda dapat mengirim transkrip chat ke SDK saat dimulai dengan data kustom yang tidak bertanda tangan dengan memanggil metode setExternalChatTransfer: atau setExternalChatTransferWithDictionary: untuk menetapkan data JSON dengan NSString atau NSDictionary.
UJETCustomData *customData = [UJETCustomData new];
[customData setExternalChatTransfer:jsonString];
UJETStartOptions *options = [UJETStartOptions new];
options.unsignedCustomData = customData;
[UJET startWithOptions:options];
Format JSON:
greeting_override: string
agen: kamus
name: string
avatar: string [URL avatar agen, opsional]
transkrip: array
pengirim: string ["end_user" atau "agent"]
timestamp: string [yaitu "2021-03-15 12.00.00Z"]
content: array
type: string [salah satu dari text, media]
text: string [wajib untuk jenis teks]
media: dictionary [wajib untuk jenis media]
type: string [salah satu dari image, video]
url: string [URL publik yang mengarah ke file media]
Contoh 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"
}
]
}
]
}
Anda dapat menggunakan Markdown pada jenis teks. Sintaksis yang didukung mencakup miring, tebal,
daftar berbutir, hyperlink, dan garis bawah (--text--).
Contoh data kustom { :#example-of-custom-data }
JSON dienkode ke JWT
File JSON harus memvalidasi JWT. Objek data kustom adalah nilai kunci 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"
}
}
}
Setiap data mirip dengan format objek JSON dan harus berisi kunci, nilai, jenis, dan label.
Kunci adalah ID unik untuk data. label adalah nama tampilan di halaman CRM type adalah jenis nilai.
string
- String JSON
angka
- integer, float
tanggal
- Format stempel waktu Unix UTC dengan 13 digit. (berisi milidetik)
URL
- Format URL HTTP
Contoh CRM

Lokasi
Gunakan framework CoreLocation. Untuk mengetahui detail selengkapnya, lihat AppDelegate.m.
Versi OS Perangkat
[customData set:@"os_version" label:@"OS Version" stringValue:[[UIDevice currentDevice] systemVersion]];
Mencegah tampilan data kustom
Anda dapat menggunakan properti invisible_to_agent dengan objek data kustom untuk mencegah data kustom bertanda atau tidak bertanda ditampilkan di adaptor agen. Dalam contoh sebelumnya, nomor jaminan sosial pengguna akhir tidak
ditampilkan di adaptor agen karena "invisible_to_agent" : true disertakan dalam
objek ssn.
Jika Anda menyertakan properti "invisible_to_agent" : true dengan objek data kustom, Anda dapat mengharapkan perilaku berikut:
- Data kustom disertakan dalam file metadata sesi.
- Data kustom tidak disertakan dalam catatan CRM.
Untuk mengetahui informasi selengkapnya, lihat Melihat data sesi di adaptor agen.
Properti data yang dicadangkan
Anda dapat mengirim properti data yang dicadangkan ke Contact Center AI Platform (CCAI Platform) sebagai data kustom bertanda tangan saat sesi dimulai. Untuk mengetahui informasi selengkapnya, lihat Mengirim properti data yang dicadangkan.
Berikut adalah contoh properti data yang dicadangkan dalam data kustom:
{
"custom_data": {
"reserved_verified_customer": {
"label": "Verified Customer",
"value": "VERIFIED_CUSTOMER_BOOLEAN": ,
"type": "boolean"
},
"reserved_bad_actor": {
"label": "Bad Actor",
"value": "VERIFIED_BAD_ACTOR_BOOLEAN": ,
"type": "boolean"
},
"reserved_repeat_customer": {
"label": "Repeat Customer",
"value": "REPEAT_CUSTOMER_BOOLEAN": ,
"type": "boolean"
}
}
}
Ganti kode berikut:
VERIFIED_CUSTOMER_BOOLEAN: Benar (True) jika Anda menganggap pengguna akhir ini sebagai pelanggan yang sah.VERIFIED_BAD_ACTOR_BOOLEAN: Benar jika Anda menganggap pengguna akhir ini berpotensi menjadi pihak tidak bertanggung jawab.REPEAT_CUSTOMER_BOOLEAN: Benar (True) jika Anda telah menentukan bahwa pengguna akhir ini telah menghubungi pusat kontak Anda sebelumnya.
Menyesuaikan Alur
Memutus koneksi Platform CCAI untuk menangani peristiwa aplikasi Host
// CCAI Platform is connected
...
// An event has come
[UJET disconnect:^{
// Handle an event
}];
Menunda panggilan atau chat masuk CCAI Platform
Menerapkan metode delegasi untuk menangani peristiwa masuk
- (BOOL)shouldConnectUjetIncoming:(NSString *)identifier forType:(UjetIncomingType)type {
if (weDoingSomething) {
// save identifier and type
return NO; // postpone
} else {
return YES;
}
}
Menghubungkan acara yang ditunda
[UJET connect:identifier forType:UjetIncomingTypeCall];
Menyiapkan Deep link
Hal ini memungkinkan agen dalam panggilan PSTN menggunakan tindakan smart melalui SMS, baik saat pengguna akhir memiliki atau tidak memiliki aplikasi.
Buka Setelan > Pengelolaan Operasi > Aktifkan Kirim SMS untuk Mendownload Aplikasi di portal Platform CCAI.
Anda dapat menyetel URL Aplikasi dengan halaman web Anda (yaitu, https://your-company.com/support) setelah mengonfigurasi Universal Link atau skema URL kustom. Anda dapat memilih salah satu cara.
Menerapkan metode delegasi untuk menangani deep link
Link universal dan URL kustom terlihat seperti
https://your-company.com/support?call_id=x&nonce=y dan
your-company://support?call_id=x&nonce=y. Masukkan salah satu link Anda
tanpa parameter kueri di bagian URL Aplikasi di Admin Portal. Misalnya, masukkan
your-company://support jika menggunakan skema URL kustom.
Dalam metode delegasi, pastikan untuk hanya memanggil [UJET start] saat jalur dan parameter URL di link universal atau URL kustom khusus untuk Platform CCAI.
- (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler {
...
if ([NSUserActivityTypeBrowsingWeb isEqualToString:userActivity.activityType]) {
NSURL *url = userActivity.webpageURL;
NSArray *availableSchema = @[
@"your-company", // custom URL scheme
@"https" // universal link
];
NSArray *availableHostAndPath = @[
@"ujet", // custom URL scheme
@"your-comany.com/ujet" // universal link
];
if (![availableSchema containsObject:url.scheme]) {
return NO;
}
NSString *hostAndPath = [NSString stringWithFormat:@"%@%@", url.host, url.path];
if (![availableHostAndPath containsObject:hostAndPath]) {
return NO;
}
// your-company://ujet?call_id={call_id}&nonce={nonce}
// https://your-company.com/ujet?call_id={call_id}&nonce={nonce}
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url
resolvingAgainstBaseURL:NO];
NSArray *queryItems = urlComponents.queryItems;
NSString *callId = [self valueForKey:@"call_id" fromQueryItems:queryItems];
// validate call id
if (![self isValidCallId:callId]) {
return NO;
}
NSString *nonce = [self valueForKey:@"nonce" fromQueryItems:queryItems];
UJETStartOptions *options = [[UJETStartOptions alloc] initWithCallId:callId nonce:nonce];
[UJET startWithOptions:options];
}
...
}
Jika aplikasi Anda mengadopsi UIWindowSceneDelegate, tambahkan cuplikan kode ini:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
//if app is called with universal Link and started from cold
if connectionOptions.urlContexts.first != nil {
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
}
guard let _ = (scene as? UIWindowScene) else { return }
}
func scene(_ scene: UIScene, willContinueUserActivityWithType userActivityType: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let _ = appDelegate.application(UIApplication.shared,
continue: NSUserActivity(activityType: userActivityType)) { _ in
}
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else {
return
}
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let _ = appDelegate.application(UIApplication.shared,
open: url,
options: [:])
}
}
Untuk mengetahui informasi selengkapnya, lihat kode contoh dari file UJETObject+DeepLink.
Mengamati peristiwa CCAI Platform
Kami memposting peristiwa berikut melalui NSNotificationCenter.defaultCenter. Anda dapat mendengarkannya dan menyesuaikan alur Anda bergantung pada kasus penggunaan, misalnya, tata letak keyboard kustom.
UJETEventEmailDidClick
- Data Menu Antrean
UJETEventEmailDidSubmit
Data Menu Antrean
has_attachment: (NSNumber) @YES, @NO
UJETEventSessionViewDidAppear
type: @"call", @"chat"
timestamp: (NSString) ISO 8601
UJETEventSessionViewDidDisappear
type: @"call", @"chat"
timestamp: (NSString) ISO 8601
UJETEventSessionDidCreate
- Data Sesi
UJETEventSessionDidEnd
Data Sesi
agent_name: (NSString) null jika agen tidak bergabung
durasi: (NSNumber) hanya untuk panggilan
ended_by: (NSString)
type=call: @"agent", @"end_user"
type=chat: @"agent", @"end_user", @"timeout", @"dismissed"
UJETEventSdkDidTerminate
UJETEventPostSessionOptInDidSelected
- opt_in_selected: (NSString) @"Yes", @"No"
Data Peristiwa
Metadata
aplikasi: @"iOS"
app_id: (NSString) ID paket
app_version: (NSString)
perusahaan: (NSString) subdomain
device_model: (NSString)
device_version: (NSString)
sdk_version: (NSString)
timestamp: (NSString) ISO 8601
Data Menu Antrean
Metadata
menu_id: NSString
menu_key: NSString, nullable
menu_name: NSString
menu_path : NSString
Data Sesi
Data Menu Antrean
session_id: NSString
type: @"call", @"chat"
end_user_identifier: NSString
Menyiapkan Berbagi Layar
Jika Anda ingin menggunakan fitur Berbagi Layar, integrasikan
UJETCobrowseKit.xcframework.
CocoaPods: Tambahkan subspec berikut ke target aplikasi Anda.
ruby
target 'MyApp' do
pod 'UJET'
pod 'UJET/Cobrowse'
end
Carthage: Tambahkan baris berikut di Cartfile:
binary "https://sdk.ujet.co/ios/UJETKit.json"
SwiftPM: Pilih produk UJET dan UJETCobrowse, lalu tambahkan ke target aplikasi Anda.
Lalu, tetapkan properti UJETGlobalOptions.cobrowseKey.
swift
let options = UJETGlobal
Options()options.cobrowseKey = cobrowseKey
UJET.setGlobalOptions(options)
Berbagi Layar perangkat penuh (opsional)
Berbagi layar perangkat penuh memungkinkan agen dukungan Anda melihat layar dari aplikasi di luar aplikasi Anda sendiri. Hal ini sering kali berguna jika agen dukungan perlu memeriksa status setelan sistem, atau perlu melihat pengguna bernavigasi di antara beberapa aplikasi. Jika tidak menginginkan fitur ini, Anda dapat melewati bagian ini.
Menyesuaikan dialog izin Berbagi Layar
Untuk menyesuaikan dialog izin Berbagi Layar, Anda perlu menerapkan
protokol UJETCobrowseAlertProvider di class penyedia. Dalam
implementasi ini, tampilkan UIViewController kustom atau objek lain yang diwarisi
UIViewController melalui metode protokol masing-masing. UIViewController
harus memiliki dua tombol, satu untuk menerima, dan satu untuk menolak.
Setelah mendapatkan izin, teruskan ke SDK kami dengan memanggil penutupan
consentStatus. UIViewController dari cobrowseFullDeviceRequestAlert. Delegasi harus berisi RPSystemBroadcastPickerView dengan judul (lihat di contoh kode di bawah) dan harus memiliki tombol tolak lainnya. Panggil penutupan
yang ditutup saat tombol tolak diklik.
class CobrowseAlertProvider: NSObject, UJETCobrowseAlertProvider {
func cobrowseSessionInitializationAlert(consentStatus: @escaping (Bool) -> Void) -> UIViewController? {
let customAlertViewController = CustomAlertViewController()
customAlertViewController.consentStatus = consentStatus
return customAlertViewController
}
func cobrowseSessionRequestAlert(consentStatus: @escaping (Bool) -> Void) -> UIViewController? {
// Same as cobrowseSessionInitializationAlert
}
func cobrowseRemoteRequestAlert(consentStatus: @escaping (Bool) -> Void) -> UIViewController? {
// Same as cobrowseSessionInitializationAlert
}
func cobrowseFullDeviceRequestAlert(dismissed: @escaping () -> Void) -> UIViewController? {
let customAlertViewController = CustomFullDeviceAlertViewController()
cobrowseSessionAlertViewController.dismissed = dismissed
return customAlertViewController
}
func cobrowseSessionEndAlert(consentStatus: @escaping (Bool) -> Void) -> UIViewController? {
// Same as cobrowseSessionInitializationAlert
}
}
Pengontrol tampilan kustom harus memiliki penutupan untuk meneruskan status izin ke SDK.
class CustomAlertViewController: UIViewController {
var consentStatus: ((Bool) -> Void)?
@IBAction func allowButtonClicked(_ sender: Any) {
dismiss(animated: true) {[weak self] in
self?.consentStatus?(true)
}
}
@IBAction func denyButtonClicked(_ sender: Any) {
dismiss(animated: true) {[weak self] in
self?.consentStatus?(false)
}
}
}
Pengontrol tampilan kustom untuk pemberitahuan permintaan perangkat penuh harus memiliki
RPSystemBroadcastPickerView dan penutupan untuk meneruskan status dismiss ke
SDK.
class CustomFullDeviceAlertViewController: UIViewController {
var broadcastPickerView: RPSystemBroadcastPickerView!
var dismissed: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
let frame = CGRect(x: x, y: y, width: 50, height: 50) // Set your own value
broadcastPickerView = RPSystemBroadcastPickerView(frame: frame)
broadcastPickerView.preferredExtension = Bundle.main.object(forInfoDictionaryKey: "CBIOBroadcastExtension") as? String // Should have this value as it is
view.addSubview(broadcastPickerView)
}
@IBAction func denyButtonClicked(_ sender: Any) {
dismiss(animated: true) {[weak self] in
self?.dismissed?()
}
}
}
Jangan lupa untuk meneruskan penyedia ini ke SDK kami melalui API berikut:
let provider = CobrowseAlertProvider()
UJET.setCobrowseAlertProvider(provider)
Ekstensi Siaran
Fitur ini memerlukan penambahan Ekstensi Siaran.
Buka project Xcode Anda.
Buka File > Target.
Pilih Broadcast Upload Extension.
Masukkan Nama untuk target.
Hapus centang pada Sertakan Ekstensi UI.
Buat target, dengan mencatat ID paket-nya.
Ubah target SDK Ekstensi Siaran Anda ke iOS 12.0 atau yang lebih tinggi.
Mengintegrasikan SDK
CocoaPods: Tambahkan subspec berikut ke target ekstensi Anda:
target 'MyApp' do
pod 'UJET'
pod 'UJET/Cobrowse'
end
target 'MyAppExtension' do
pod 'UJET/CobrowseExtension'
end
Jika Anda menggunakan SwiftPM, pilih produk UJETCobrowseExtension dan tambahkan ke target ekstensi.
Menyiapkan berbagi keychain
Aplikasi dan ekstensi aplikasi yang Anda buat sebelumnya harus berbagi beberapa rahasia melalui Keychain iOS. Mereka melakukannya menggunakan grup Keychain mereka sendiri sehingga mereka diisolasi dari Keychain aplikasi Anda lainnya.
Di target aplikasi dan target ekstensi, tambahkan hak Berbagi Keychain untuk grup keychain io.cobrowse.
Tambahkan ID paket ke plist Anda
Ambil ID paket ekstensi yang Anda buat sebelumnya dan tambahkan entri berikut di Info.plist aplikasi Anda (Catatan: bukan di Info.plist ekstensi), ganti ID paket berikut dengan ID Anda sendiri:
xml
<key>CBIOBroadcastExtension</key>
<string>your.app.extension.bundle.ID.here</string>
Menerapkan ekstensi
Xcode akan menambahkan file SampleHandler.m dan SampleHandler.h (atau
SampleHander.swift) sebagai bagian dari target yang Anda buat sebelumnya. Ganti
konten file dengan kode berikut:
Swift: Pilih produk UJETCobrowseExtension dan tambahkan ke target
ekstensi Anda:
import CobrowseIOAppExtension
class SampleHandler: CobrowseIOReplayKitExtension {
}
ObjC
objc// SampleHandler.h
@import CobrowseIOAppExtension;
@interface SampleHandler : CobrowseIOReplayKitExtension
@end// SampleHandler.m
#import "SampleHandler.h"
@implementation SampleHandler
@end
Buat dan jalankan aplikasi Anda
Anda kini siap membangun dan menjalankan aplikasi. Kemampuan perangkat penuh hanya tersedia di perangkat fisik, dan tidak akan berfungsi di Simulator iOS.
Minimalkan SDK
SDK Contact Center AI Platform dapat diminimalkan saat sesi chat atau panggilan sedang berlangsung. Hal ini dapat berguna saat Anda ingin mengarahkan pengguna kembali ke aplikasi Anda setelah peristiwa SDK diterima, seperti kartu konten yang diklik. Untuk meminimalkan SDK dan mengarahkan pengguna kembali ke aplikasi Anda, Anda dapat menggunakan:
UJET.minimize(nil)
// Or if you want to take some action once the SDK has been minimized:
UJET.minimize {
// Add the code you want to run once the SDK has been minimized here
}
Pemecahan masalah
Penolakan pengiriman aplikasi
Pengiriman aplikasi ditolak karena menyertakan framework CallKit di wilayah China.
Jika aplikasi Anda ditolak oleh Apple karena alasan ini, cukup tinggalkan komentar karena sistem dirancang untuk menonaktifkan framework CallKit untuk wilayah China pada panggilan VoIP. Perubahan ini berlaku mulai versi SDK 0.31.1.
Ukuran SDK terlalu besar
Jika ukuran SDK terlalu besar dan sulit dilacak di GitHub
Dalam artikel ini, mereka menawarkan dua pilihan. Sebaiknya gunakan Git LFS.
Jika Anda tidak menggunakan Bitcode, maka menghapus bitcode dari biner dapat menjadi opsi lain. Jalankan perintah ini di folder UJETKit.xcframework.
xcrun bitcode_strip -r UJET -o UJET
dyld: Error Library tidak dimuat
Tambahkan @executable_path/Frameworks di Runpath Search Paths dari Target > Build Settings > Linking.
Pengiriman aplikasi di iTunes Connect
Apple mungkin mengajukan pertanyaan berikut selama proses peninjauan karena mode latar belakang Voice over IP diaktifkan:
Dapatkah pengguna menerima panggilan VoIP di aplikasi Anda?
Jawab Ya untuk pertanyaan tersebut.
Notifikasi Pemberitahuan tidak tersedia saat memulai SDK
Periksa hal-hal berikut:
Gunakan perangkat sebenarnya, bukan simulator.
Aktifkan Notifikasi push dan Background Modes > Voice over IP capability.
Jika hal tersebut tidak membantu, coba buat dengan profil penyediaan distribusi (Ad-hoc atau Apple Store).
Menguji notifikasi push terhadap aplikasi pengujian Anda
Siapkan sertifikat VoIP dan token perangkat perangkat Anda.
Di portal Platform CCAI, lihat bagian Debug Notifikasi Push di menu Setelan > Setelan Developer.
Jika sudah menyetel sertifikat untuk APNS, Anda tidak perlu memasukkan sertifikat lagi.
Masukkan sertifikat Anda (opsional) dan periksa apakah sandbox atau tidak (opsional) dan masukkan token perangkat push notification aplikasi pengujian Anda.
Memulai percakapan baru memerlukan waktu lebih dari 30 detik
Periksa apakah Anda merespons metode delegasi data kustom. Anda harus menampilkan data kustom yang valid saat diminta atau hanya menampilkan nil di blok keberhasilan.
Gunakan cuplikan kode ini sebagai contoh konfigurasi:
public func signPayload(_ payload: [AnyHashable: Any]?, payloadType: UjetPayloadType, success: (String?) -> Void, failure: (Error?) -> Void)
{
if payloadType == .customData {
success(nil)
}
}