Panduan iOS SDK

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

  1. Login ke portal Contact Center AI Platform (CCAI Platform) menggunakan kredensial Admin.

  2. Buka Setelan > Setelan Developer.

  3. Di bagian Company Key dan Secret Code, catat Company Key dan Company Secret Code.

Memulai

Berikut ini panduan tentang cara memulai SDK seluler iOS CCAI Platform.

Penginstalan

Untuk memulai, Anda harus menginstal iOS SDK.

Mendownload aplikasi contoh

  1. Download Aplikasi Contoh iOS.

  2. Buka folder dan instal dependensi menggunakan CocoaPods:

    $ pod install --project-directory=ExampleApp
    
  3. Untuk mengonfigurasi setelan project dengan cepat, jalankan skrip shell:

    $ ./setup.sh
    

    Atau, Anda dapat mengedit setelan project secara manual dengan mengikuti langkah-langkah berikut:

    1. Buka ExampleApp.xcworkspace.

    2. Ganti nilai UJETCompanyKey dan UJETCompanySecret di Info.plist dengan nilai Company Key dan Company Secret Code dari halaman Settings > Developer Settings di portal CCAI Platform.

    3. Ganti nilai UJETSubdomain di Info.plist dengan subdomain di URL untuk portal CCAI Platform Anda. Subdomain langsung mendahului .ujet.com di URL— misalnya, your-subdomain di https://your-subdomain.ujet.com/settings/developer-setting.

Mengintegrasikan ke project Anda

Integrasi iOS SDK dengan aplikasi Anda bergantung pada lingkungan pengembangan Anda.

Swift Package Manager

  1. Tambahkan Paket Swift untuk iOS SDK dari GitHub.

  2. Di setelan build, masukkan -ObjC di Other Linker Flags.

  3. Mulai Xcode 13.2, ada masalah umum terkait penggunaan framework biner yang didistribusikan menggunakan Swift Package Manager. Solusi sementara untuk masalah ini adalah menambahkan Run Script Phase ke Build Phases project Xcode Anda. Run Script Phase ini harus muncul setelah fase build Embed Frameworks. Run Script Phase 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

  1. Tambahkan baris berikut ke Podfile:

    pod 'UJET', :podspec =>
    'https://sdk.ujet.co/ios/x.y.z/ujet.podspec' #specific version
    x.y.z
    
  2. Jalankan 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 CCAI Platform tidak mendukung Carthage.

Untuk menggunakan pengelola dependensi yang berbeda, ikuti langkah-langkah berikut:

  1. Tambahkan baris berikut:

    binary "https://sdk.ujet.co/ios/UJETKit.json"
    binary "https://sdk.ujet.co/ios/UJETFoundationKit.json"
    binary "https://sdk.ujet.co/ios/UJETCallRedKit.json"
    binary "https://sdk.ujet.co/ios/UJETChatRedKit.json"
    # optional
    # binary "https://sdk.ujet.co/ios/UJETChatBlueKit.json"
    binary "https://raw.githubusercontent.com/twilio/twilio-voice-ios/Releases/twilio-voice-ios.json"
    # this is not supported: https://github.com/twilio/conversations-ios/issues/12
    # binary "https://raw.githubusercontent.com/twilio/conversations-ios/master/twilio-convo-ios.json"
    
  2. Jalankan carthage bootstrap --use-xcframeworks (atau carthage update --use-xcframeworks jika Anda mengupdate dependensi).

Integrasi manual
  1. Download UJETKit.xcframework, UJETFoundationKit.xcframework, UJETChatRedKit.xcframework, UJETChatBlueKit.xcframework, UJETTwilioCallKit.xcframework, dan semua dependensi TwilioVoice.xcframework dan TwilioConversationsClient.xcframework.

  2. Tambahkan UJETKit.xcframework ke target Anda dengan menariknya ke bagian Frameworks, Libraries, and Embedded Content.

  3. Ulangi Langkah 2 dan 3 pada semua dependensi dari Langkah 1.

  4. Di Build Settings, tempatkan -ObjC di Other Linker Flags.

  5. Tambahkan libc++.tbd sebagai dependensi di bagian Linked Frameworks target.

Jika Anda akan mem-build SDK secara manual dengan project contoh, gunakan langkah-langkah di bagian berikut.

Membangun SDK secara manual dengan project contoh

Ikuti langkah-langkah berikut secara berurutan:

  1. Download semua framework termasuk UJETKit.xcframework dan dependensi lainnya.

  2. Buat folder CCAI Platform di root project dan ekstrak semua framework.

  3. Pilih target dan build Objc-Manual atau Swift-Manual.

Framework impor

Bagian berikut memberikan petunjuk tentang cara mengimpor framework.

Project Objective-C

@import UJETKit;

Project Swift

swiftimport
UJETimport UJETKit

Melakukan inisialisasi SDK

Melakukan 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 bahwa 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 berhasil atau gagal harus dipanggil sebelum delegasi ditampilkan.

Untuk pengguna anonim (ID = 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>

Terapkan metode delegasi signPayload: payloadType: success: failure:.

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

CCAI Platform mengirimkan notifikasi push untuk meminta tindakan cerdas seperti verifikasi dan foto, serta melaporkan panggilan masuk. Jika antrean chat Anda menggunakan Check In (memerlukan iOS SDK 2.16.0 atau yang lebih baru), CCAI Platform akan mengirimkan notifikasi push yang meminta konsumen yang menunggu untuk kembali ke chat dan mengonfirmasi bahwa mereka sudah siap. Lihat Check In untuk Mobile SDK. CCAI Platform memerlukan dua jenis sertifikat yang berbeda (VoIP dan APN) untuk disimpan di Portal Admin CCAI Platform.

Mengonfigurasi sertifikat

CCAI Platform memerlukan dua jenis sertifikat push Apple yang berbeda untuk disimpan di Portal Admin CCAI Platform:

  • Sertifikat SSL Apple Push Notification service (APNs) — digunakan untuk notifikasi push jarak jauh standar.

  • Sertifikat layanan VoIP — digunakan untuk notifikasi panggilan masuk dan tindakan cerdas tertentu terkait panggilan.

Kedua sertifikat dibuat di portal developer Apple, dikonversi ke format PEM, lalu diupload ke Portal Admin CCAI Platform.

Membuat sertifikat SSL APNs

Ikuti langkah-langkah berikutnya berdasarkan panduan resmi Apple Establishing a Certificate-Based Connection to APNs untuk membuat sertifikat SSL APNs.

  • Login ke developer.apple.com dan buka Certificates, identifiers & profiles.

  • Klik tombol + untuk membuat sertifikat baru.

  • Di bagian Services, pilih Apple push notification service SSL (Sandbox & production).

  • Pilih ID Aplikasi yang cocok dengan ID paket aplikasi Anda, lalu klik Continue.

  • Upload permintaan penandatanganan sertifikat (CSR) yang dibuat dari akses keychain di Mac Anda:

    • Buka Keychain access > Certificate assistant > Request a certificate from a certificate authority.

    • Masukkan alamat email Anda, biarkan CA email address kosong, pilih Saved to disk, lalu klik Continue.

  • Klik Lanjutkan, lalu Download file .cer yang dihasilkan.

  • Klik dua kali file .cer untuk menginstalnya di keychain Anda.

  • Di Keychain access, temukan sertifikat yang diinstal, klik kanan, dan pilih Export… untuk menyimpannya sebagai file .p12. Anda akan diminta untuk menetapkan sandi ekspor.

  • Konversikan file .p12 ke format PEM menggunakan openssl:

# 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

Membuat sertifikat layanan VoIP

Sertifikat layanan VoIP memungkinkan aplikasi Anda menerima notifikasi push prioritas tinggi melalui framework PushKit Apple, yang dapat mengaktifkan aplikasi Anda dari status dihentikan untuk menangani panggilan masuk. Untuk mengetahui langkah-langkah resmi terbaru, lihat Membuat sertifikat layanan VoIP dalam dokumentasi Apple Developer.

  • Login ke developer.apple.com dan buka Certificates, Identifiers & Profiles.

  • Klik tombol + untuk membuat sertifikat baru.

  • Di bagian Services, pilih VoIP services certificate.

  • Pilih ID Aplikasi yang cocok dengan ID paket aplikasi Anda, lalu klik Continue.

  • Upload Permintaan Penandatanganan Sertifikat (CSR) yang sama dengan yang Anda buat di bagian sebelumnya (atau buat yang baru).

  • Klik Lanjutkan, lalu Download file .cer yang dihasilkan.

  • Klik dua kali file .cer untuk menginstalnya di Keychain Anda.

  • Di Keychain access, temukan sertifikat VoIP Services yang diinstal, klik kanan, lalu pilih Export… untuk menyimpannya sebagai file .p12.

  • Konversikan file .p12 ke format PEM menggunakan openssl:

# 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

Mengupload sertifikat ke Portal Admin CCAI Platform

  • Login ke Portal Admin CCAI Platform.

  • Buka Setelan > Setelan developer > Aplikasi seluler.

  • Upload sertifikat PEM APN.

  • Upload sertifikat PEM VoIP.

Aktifkan notifikasi push

  1. Pilih target Anda dan buka tab Capabilities.

  2. Aktifkan tombol Notifikasi push.

Menguji notifikasi push

Bagian berikut memberikan panduan tentang cara menguji notifikasi push.

Bagian debug notifikasi push

Di portal administrator, buka Settings > Developer Settings. Di halaman ini, temukan bagian berjudul Debug notifikasi push:

Salin dan tempel token perangkat di area teks yang tepat, lalu pilih Aplikasi Seluler yang tepat.

Mendapatkan token perangkat

Contoh string token perangkat terlihat seperti ini:

7db0bc0044c8a203ed87cdab86a597a2c43bf16d82dae70e8d560e88253364b7

Notifikasi push biasanya ditetapkan di class yang sesuai dengan protokol UIApplicationDelegate atau PKPushRegistryDelegate. Pada titik tertentu, token perangkat akan 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 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

  • Background Modes (centang item ini)

  • Audio dan AirPlay

  • Voice over IP

Info.plist

Untuk melindungi privasi pengguna, setiap aplikasi iOS 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, galeri foto, dan kamera perangkat tanpa string tujuan yang sesuai, aplikasi akan keluar.

  • NSMicrophoneUsageDescription: Mengizinkan akses ke mikrofon untuk menelepon dan berbicara dengan tim dukungan atau pemecahan masalah, serta untuk mengirim video dengan suara terkait pertanyaan produk.

  • NSCameraUsageDescription: Mengizinkan akses ke kamera agar pelanggan dapat mengambil dan mengirim foto terkait pertanyaan dukungan pelanggan mereka.

  • NSPhotoLibraryUsageDescription: Mengizinkan akses bagi pelanggan untuk mengirim foto yang terkait dengan pertanyaan dukungan pelanggan mereka.

  • NSFaceIDUsageDescription: Mengizinkan akses ke verifikasi menggunakan Face ID.

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

  1. Login ke portal CCAI Platform dengan kredensial administrator.

  2. Buka Setelan > Antrean.

  3. Pilih antrean dari struktur menu.

  4. Pilih Buat titik akses langsung

  5. Masukkan kunci di formulir teks.

  6. Klik Simpan.

Menghapus cache dari lokal jika data pengguna telah diperbarui

Kami meng-cache token autentikasi di Keychain untuk digunakan kembali dan mengurangi frekuensi permintaan untuk menandatangani payload dari aplikasi host. SDK akan menggunakannya hingga masa berlakunya habis atau dicabut melalui panggilan clearUserData. Aplikasi host bertanggung jawab untuk mencabut cache ini setiap kali data terkait pengguna berubah atau diperbarui, seperti peristiwa logout.

[UJET clearUserData];

Memeriksa sesi yang ada sebelum memulai Contact Center AI Platform

Sebelum memulai sesi, periksa apakah tidak ada sesi yang sedang berlangsung. Hal ini sangat penting saat 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 untuk 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 Portal Admin > Setelan > Detail Pusat Dukungan > Nama Tampilan.

Anda dapat menetapkan gambar logo, bukan nama perusahaan, seperti ini:

theme.companyImage = [UIImage imageNamed:@"logo"];

Gambar akan diubah ukurannya agar pas dengan area jika terlalu besar.

String

Anda juga dapat menyesuaikan string dengan mengganti nilainya. Misalnya, tempatkan kunci - nilai ini di Localizable.strings Anda:

"ujet_greeting_title" = "Title";

"ujet_greeting_description" = "Description";

String yang dapat disesuaikan tersedia dalam file ujet.strings.

Mode gelap

Anda dapat menentukan tint warna yang diinginkan untuk mode gelap agar font lebih mudah dibaca.

@property (nonatomic, strong) UIColor \*tintColorForDarkMode;

Jika Anda tidak menetapkan properti, UJETGlobalTheme.tintColor akan digunakan untuk mode gelap. Sebaiknya tetapkan 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 tanda komentar pada metode customizeChatTheme.

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 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 hal 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 dari protokol UJETDelegate. Metode ini menerima peristiwa (kamus FormMessageReceivedEvent) sebagai parameter, yang berisi informasi terkait formulir. Kamus peristiwa (FormMessageReceivedEvent) menyertakan struktur JSON berikut:

  {
    "type": "form_message_received",
    "smart_action_id": 1,
    "external_form_id": "external_foobar"
    "signature": "4868a7e1dcb5..."
  }

Untuk menangani peristiwa, lakukan hal berikut:

  1. Ekstrak informasi yang relevan dari kamus peristiwa (smart_action_id, external_form_id, dan signature).

  2. Buat URI formulir dan tanda tangan untuk data formulir.

  3. Teruskan data formulir ke SDK sebagai kamus FormDataEvent menggunakan completion closure.

  4. Jika terjadi error selama pembuatan URI/tanda tangan, panggil callback menggunakan callback.onError() dengan Error.

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, yang ditandatangani dengan kunci rahasia bersama. Kunci objek data harus diurutkan menurut abjad sebelum membuat 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 boleh 0 atau 1 dan jika Anda tidak ingin membedakan pengalaman agen virtual pasca-sesi, Anda dapat menetapkan 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 lainnya 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 dalam aplikasi akan ditampilkan dengan layar panggilan dan menampilkan panggilan di histori panggilan telepon.

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 dengan nama 'icon-call-kit'.

Mengonfigurasi SDK

Anda dapat menetapkan 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;

Penggantian 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 masalah konfigurasi firewall atau penyedia.

Sebaiknya tetapkan nomor IVR perusahaan Anda di UJETGlobalOptions.fallbackPhoneNumber. Format yang direkomendasikan adalah + diikuti dengan kode negara dan nomor telepon. misalnya, +18001112222.

Sensitivitas Penggantian PSTN

Anda dapat menyesuaikan tingkat sensitivitas pemeriksaan kondisi jaringan ke 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 minimum masing-masing adalah 10.000 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:

  1. Login ke portal CCAI Platform sebagai administrator.

  2. Buka Setelan > Setelan Developer > Aplikasi Seluler.

  3. Temukan bagian Batas nomor telepon pengganti. Nilai defaultnya adalah 0,85.

  4. Tentukan nilai minimum baru.

  5. Klik Save.

Menonaktifkan notifikasi push di tingkat global

Anda dapat menonaktifkan notifikasi push di tingkat global. Menetapkan properti berikut ke false akan mengabaikan semua dependensi notifikasi push dan mencegah notifikasi push menjangkau pengguna akhir:

@property (nonatomic, assign) BOOL allowsPushNotifications;

Abaikan mode gelap

Anda dapat mengabaikan mode gelap di CCAI Platform SDK, khususnya dengan properti ini:

@property (nonatomic, assign) BOOL ignoreDarkMode;

Sembunyikan Status Bar

Anda dapat mengontrol visibilitas status bar dengan properti ini:

  @property (nonatomic, assign) BOOL hideStatusBar;

Secara default, hideStatusBar ditetapkan 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 loader 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 menetapkan UIUserInterfaceStyle sebagai Light di Info.plist aplikasi untuk memilih tidak menggunakan mode gelap sepenuhnya, Anda dapat mengabaikan properti ini.

Bahasa pilihan

CCAI Platform SDK akan menggunakan urutan prioritas berikut untuk menentukan bahasa pilihan.

  1. Bahasa yang dipilih dari layar pembuka dalam aplikasi.

  2. Bahasa default dipilih dari UJETGlobalOptions. Anda dapat menetapkan bahasa default dengan properti preferredLanguage. Kode bahasa yang didukung dapat ditemukan di file UJETGlobalOptions.h.

  3. Bahasa perangkat yang dipilih di perangkat (dari Setelan > Umum > Bahasa & Wilayah) akan digunakan, jika didukung oleh aplikasi.

  4. Dialek terdekat dari 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 dialek induk bahasa Spanyol, bahasa Spanyol akan digunakan.

  5. 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 Anda 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 Portal Admin 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.

Mengirim data kustom ke CRM Anda

Anda dapat mengirim data kustom ke tiket CRM.

Ada dua metode untuk mengirim data kustom:

  1. Metode aman: penandatanganan data yang telah ditentukan dengan JWT.

  2. 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 berdasarkan formulir yang ditentukan dan menandatanganinya dengan company.secret, 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 menciptakan potensi kerentanan yang dapat membuat aplikasi Anda rentan 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 telah 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 cukup 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 ditandatangani untuk mengirim transkrip chat eksternal

Anda dapat mengirim transkrip chat ke SDK saat dimulai dengan data kustom yang tidak ditandatangani 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

  • agent: kamus

    • name: string

    • avatar: string [URL avatar agen, opsional]

  • transcript: array

    • sender: string [end_user atau agent]

    • timestamp: string [misalnya, 2021-03-15 12:00:00Z]

    • content: array

      • type: string [salah satu dari text, media]

      • text: string [wajib ada untuk jenis teks]

      • media: kamus [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

Bagian ini menunjukkan contoh data kustom.

JSON dienkode ke JWT

File JSON harus memvalidasi JWT. Dan 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. Jenis 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

Berikut adalah 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 pelanggan

Anda dapat menggunakan properti invisible_to_agent dengan objek data kustom untuk mencegah data kustom yang ditandatangani atau tidak ditandatangani 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 data 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 yang ditandatangani 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": false,
        "type": "boolean"
      },
      "reserved_bad_actor": {
        "label": "Bad Actor",
        "value": false,
        "type": "boolean"
      },
      "reserved_repeat_customer": {
        "label": "Repeat Customer",
        "value": false,
        "type": "boolean"
      }
    }
  }
  

Tetapkan setiap nilai ke true atau false.

  • reserved_verified_customer: true jika Anda menganggap pengguna akhir ini sebagai pelanggan yang sah.
  • reserved_bad_actor: true jika Anda menganggap pengguna akhir ini berpotensi menjadi pelaku kejahatan.
  • reserved_repeat_customer: true jika Anda telah menentukan bahwa pengguna akhir ini pernah menghubungi pusat kontak Anda sebelumnya.

Sesuaikan Alur

Bagian ini menjelaskan cara menyesuaikan alur.

Memutuskan hubungan CCAI Platform untuk menangani peristiwa aplikasi Host

// CCAI Platform is connected
...
// An event has come
[UJET disconnect:^{
  // Handle an event
}];

Menunda panggilan masuk atau chat CCAI Platform

Terapkan metode delegasi untuk menangani peristiwa yang 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 pada panggilan PSTN menggunakan tindakan cerdas melalui SMS, baik saat pengguna akhir memiliki maupun tidak memiliki aplikasi.

Buka Settings > Operation Management > Enable Send SMS to Download App di portal CCAI Platform.

Anda dapat menetapkan URL Aplikasi dengan halaman web Anda (yaitu, https://your-company.com/support) setelah mengonfigurasi Link Universal atau skema URL kustom. Anda dapat memilih salah satu cara.

Menerapkan metode delegasi untuk menangani deep link

Link universal dan URL kustom masing-masing 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 Portal Admin. Misalnya, masukkan your-company://support jika menggunakan skema URL kustom.

Dalam metode delegasi, pastikan untuk hanya memanggil [UJET start] jika jalur dan parameter URL di link universal atau URL kustom bersifat spesifik untuk CCAI Platform.

-   (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 menggunakan 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 memprosesnya dan menyesuaikan alur 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

    • duration: (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

  • application: @"iOS"

  • app_id: (NSString) ID paket

  • app_version: (NSString)

  • company: (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

Metadata

  • 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 ini ke target aplikasi Anda:

    ruby
target 'MyApp' do
  pod 'UJET'
  pod 'UJET/Cobrowse'
end

Menyiapkan berbagi layar dengan Carthage

Tambahkan baris ini di Cartfile:

binary "https://sdk.ujet.co/ios/UJETKit.json"

SwiftPM

Pilih produk UJET dan UJETCobrowse, lalu tambahkan ke target aplikasi Anda.

Dan tetapkan nilai UJETGlobalOptions.cobrowseKey ke kunci cobrowse perusahaan Anda.

swift
let options = UJETGlobalOptions()
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. Hal ini sering kali berguna saat agen dukungan perlu memeriksa status setelan sistem, atau perlu melihat pengguna beralih di antara beberapa aplikasi. Jika tidak menginginkan fitur ini, Anda dapat melewati bagian ini.

Untuk menyesuaikan dialog izin berbagi layar, Anda harus 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 lagi untuk menolak.

Setelah mendapatkan izin, teruskan ke SDK kami dengan memanggil closure consentStatus. UIViewController dari cobrowseFullDeviceRequestAlert. Delegasi harus berisi RPSystemBroadcastPickerView dengan judul (lihat dalam kode contoh di bawah) dan harus memiliki tombol tolak lainnya. Panggil penutupan yang ditutup saat mengklik tombol tolak.

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 lengkap 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 Broadcast Extension.

  1. Buka project Xcode Anda.

  2. Buka File > Target.

  3. Pilih Broadcast Upload Extension.

  4. Masukkan Nama untuk target.

  5. Hapus centang pada kotak Include UI Extension.

  6. Buat target, dan catat ID paket-nya.

  7. Ubah SDK target 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 Anda.

Menyiapkan berbagi keychain

Aplikasi Anda dan ekstensi aplikasi yang Anda buat sebelumnya perlu berbagi beberapa rahasia melalui Keychain iOS. Mereka melakukannya menggunakan grup Keychain mereka sendiri sehingga terisolasi dari keychain aplikasi Anda yang lain.

Di Xcode, pilih target aplikasi dan target ekstensi Anda. Tambahkan hak berbagi keychain untuk grup keychain io.cobrowse.

Menambahkan ID paket ke plist Anda

Ambil ID paket ekstensi yang Anda buat sebelumnya dan tambahkan entri ini di Info.plist aplikasi Anda.

xml
<key>CBIOBroadcastExtension</key>
<string>your.app.extension.bundle.ID.here</string>

Mengimplementasikan ekstensi

Xcode akan menambahkan file SampleHandler.m dan SampleHandler.h (atau SampleHandler.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

Sekarang Anda siap untuk membangun dan menjalankan aplikasi. Kemampuan perangkat lengkap hanya tersedia di perangkat fisik, dan tidak akan berfungsi di iOS Simulator.

Meminimalkan SDK

SDK Contact Center AI Platform dapat diperkecil 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 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
}

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

Tabel berikut menunjukkan error yang diproses 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 rating.

authenticationError 100 Terjadi error tidak terduga selama autentikasi.
authenticationJwtError 101 Terjadi error tidak terduga selama validasi JWT—misalnya, error penguraian.
voipConnectionError 1000 Gagal membuat koneksi ke penyedia VoIP. Callback SDK VoIP 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
    }
}

Pemecahan masalah

Bagian ini memberikan informasi untuk membantu Anda memecahkan masalah umum.

Penolakan pengiriman aplikasi

Pengiriman aplikasi ditolak karena penyertaan 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. Hal ini berlaku mulai SDK versi 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, menghapus bitcode dari biner dapat menjadi opsi lain. Jalankan perintah ini di folder UJETKit.xcframework.

xcrun bitcode_strip -r UJET -o UJET

Error dyld: Library not loaded

Tambahkan @executable_path/Frameworks di Runpath Search Paths dari Target > Build Settings > Linking.

Pengiriman aplikasi di iTunes Connect

Apple mungkin akan mengajukan pertanyaan berikut saat dalam proses peninjauan karena mode latar belakang Voice over IP diaktifkan:

Dapatkah pengguna menerima panggilan VoIP di aplikasi Anda?

Jawab Yes untuk pertanyaan tersebut.

Notifikasi Pemberitahuan tidak tersedia saat memulai SDK

Periksa hal-hal berikut:

  • Gunakan perangkat sebenarnya, bukan simulator.

  • Aktifkan Notifikasi push dan kemampuan Background Modes > Voice over IP.

Jika hal tersebut tidak membantu, coba build dengan profil penyediaan distribusi (Ad-hoc atau Apple Store).

Menguji notifikasi push terhadap aplikasi pengujian Anda

Siapkan sertifikat VoIP dan token perangkat Anda.

Di portal CCAI Platform, lihat bagian Debug Notifikasi Push di menu Settings > Developer Settings.

Jika sudah menetapkan sertifikat untuk APNS, Anda tidak perlu memasukkan sertifikat lagi.

Masukkan sertifikat Anda (opsional) dan centang apakah sandbox atau tidak (opsional), lalu masukkan token perangkat notifikasi push aplikasi pengujian Anda.

Memulai chat baru memerlukan waktu lebih dari 30 detik

Periksa apakah Anda merespons metode delegasi data kustom. Anda harus menampilkan data kustom yang valid berdasarkan permintaan atau cukup menampilkan nil pada 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)
    }
}