Headless Mobile SDK for iOS: Mulai

Dokumen ini menjelaskan cara mulai menggunakan Headless Mobile SDK untuk iOS.

Headless Mobile SDK for iOS memungkinkan Anda menambahkan dukungan yang didukung CCAI Platform langsung ke pengalaman iOS bawaan Anda tanpa menggunakan UI CCAI Platform bawaan.

Daripada menampilkan widget bermerek CCAI Platform, Anda:

  • Integrasikan CCAI iOS SDK ke dalam aplikasi Anda.

  • Buat layar, navigasi, dan desain visual Anda sendiri.

  • Gunakan SDK untuk:

    • Mulai dan kelola sesi chat dan suara.

    • Menawarkan email, panggilan terjadwal, dan opsi pengalihan.

    • Mendukung tindakan smart, lampiran, dan alur pasca-sesi (CSAT, survei, agen virtual).

CCAI Platform menangani logika pusat kontak (perutean, antrean, saluran, konfigurasi, pelaporan). Anda memiliki seluruh pengalaman aplikasi (UI, alur, dan branding).

Jika Anda lebih memilih UI yang dapat dikonfigurasi bawaan daripada membuat UI sendiri, gunakan Standard Mobile SDK.

Persyaratan

Berikut persyaratan untuk mengintegrasikan Headless Mobile SDK untuk iOS.

Persyaratan platform iOS

  • Versi iOS minimum: iOS 16.6 atau yang lebih baru

  • Bahasa: Swift

  • IDE: Versi Xcode stabil terbaru yang didukung oleh aplikasi Anda

  • Arsitektur: Arsitektur iOS standar yang didukung oleh toolchain Xcode saat ini.

Izin aplikasi

Karena aplikasi bawaan Anda menangani UI untuk tindakan smart (mengambil foto, merekam video, atau memverifikasi identitas), Anda harus mendeklarasikan izin privasi wajib Apple.

Tambahkan kunci berikut ke Info.plist dengan deskripsi tentang cara aplikasi Anda menggunakan data:

  • NSCameraUsageDescription: Diperlukan agar pengguna dapat mengambil dan mengirim foto/video, atau untuk tindakan smart yang diminta agen.

  • NSMicrophoneUsageDescription: Diperlukan untuk panggilan suara instan dan untuk merekam video dengan suara.

  • NSPhotoLibraryUsageDescription: Diperlukan agar pengguna dapat mengupload foto atau video yang sudah ada dari rol kamera mereka.

  • NSFaceIDUsageDescription: Diperlukan jika Anda mendukung verifikasi biometrik tindakan smart.

Persyaratan instance CCAI Platform

Anda memerlukan akses ke Setelan developer instance Platform CCAI untuk mendapatkan detail berikut:

  • Kunci perusahaan

  • Kode rahasia perusahaan

  • URL Host - nama host untuk platform CCAI (misalnya, your_subdomain.ccaiplatform.com)

Nilai ini digunakan untuk:

  • Kunci perusahaan + URL host: Di aplikasi iOS Anda untuk menginisialisasi SDK.

  • Kode rahasia perusahaan: Di backend Anda untuk menandatangani Token Web JSON (JWT) yang digunakan untuk mengautentikasi pengguna.

Notifikasi push

Untuk panggilan dan tindakan smart tertentu, Anda memerlukan:

  • Konfigurasi layanan Apple Push Notification (APNs) untuk notifikasi push standar.

  • Sertifikat layanan VoIP untuk mendukung panggilan masuk dan notifikasi terkait panggilan tertentu.

Anda akan:

  • Konfigurasi kredensial APNs dan VoIP di portal developer Apple.

  • Upload sertifikat yang dikonversi di portal administrator Platform CCAI di bagian Setelan > Setelan developer > Aplikasi seluler.

  • Mendaftar untuk notifikasi jarak jauh dan push VoIP di aplikasi Anda.

  • Teruskan token perangkat yang sesuai ke SDK.

  • Di Target > Signing & capabilities, aktifkan berikut ini:

    • Kemampuan notifikasi push.

    • Kemampuan Mode latar belakang dengan item ini dicentang:

      • Voice-over IP - diperlukan untuk notifikasi push VoIP (panggilan masuk, tindakan smart menggunakan PSTN).

      • Audio, AirPlay, dan Picture in Picture - diperlukan agar audio panggilan suara dapat dilanjutkan saat aplikasi berada di latar belakang.

      • Notifikasi jarak jauh - diperlukan untuk pengiriman push APNs standar.

Cara kerja headless iOS SDK di aplikasi Anda

Headless Mobile SDK for iOS dapat dilihat sebagai tiga lapisan:

Platform dan SDK CCAI Platform

SDK berinteraksi dengan aman dengan platform CCAI Platform dan menyediakan:

  • Autentikasi menggunakan Token Web JSON (JWT).

  • Metadata perutean saluran dan antrean (chat, suara, panggilan terjadwal, email, link pengalihan eksternal).

  • Pengelolaan status sesi real-time.

  • Pipeline transportasi yang aman untuk tindakan smart, lampiran file, dan berbagi layar.

  • Logika pengalihan dan evaluasi hierarki pasca-sesi.

Aplikasi iOS Anda (UI dan logika ditangani oleh Anda)

Anda mengontrol seluruh pengalaman visual dan navigasi:

  • Titik entri: Misalnya, tab Bantuan atau tombol Hubungi kami.

  • Menu: Cara Anda menampilkan antrean (misalnya, Penagihan, Dukungan Teknis).

  • UI dalam sesi: Balon chat, layar panggilan, dan kontrol kustom Anda.

  • Tindakan yang dilakukan aplikasi Anda: Memanggil API SDK untuk memulai dan mengakhiri sesi, memproses peristiwa SDK, dan mendorong navigasi pengontrol tampilan.

Konfigurasi portal administrator CCAI Platform

Admin CCAI Platform Anda mengonfigurasi aturan interaksi (jam operasional, saluran yang tersedia, batas waktu tunggu, dan survei). SDK membaca konfigurasi ini dan mengeksposnya ke aplikasi Anda sebagai data dan peristiwa mentah. Anda yang memutuskan cara menggambar konfigurasi tersebut di layar.

Mengambil kredensial perusahaan

Sebelum mengintegrasikan SDK, dapatkan kredensial dari instance Platform CCAI Anda:

  1. Login ke portal administrator CCAI Platform dengan akun administrator.

  2. Buka Setelan > Setelan developer.

  3. Di bagian Kunci perusahaan & kode rahasia, salin:

    • Kunci perusahaan

    • Kode rahasia perusahaan

  4. Catat URL host Anda:nama host untuk platform CCAI (misalnya, your_subdomain.ccaiplatform.com).

Anda akan menggunakan:

  • Di aplikasi iOS Anda: Kunci perusahaan + URL host.

  • Di server backend Anda: Kode rahasia perusahaan untuk menandatangani JWT untuk:

    • Autentikasi pengguna akhir.

    • Data atau konteks kustom opsional yang digunakan oleh Platform CCAI.

Menambahkan SDK ke aplikasi iOS Anda

Headless SDK dibangun menggunakan arsitektur modular. Anda menginstal CCAIKit inti bersama modul fitur tertentu yang diperlukan aplikasi Anda (misalnya, CCAIChat atau CCAIScreenShare).

Untuk mengintegrasikan iOS SDK di aplikasi Anda, ikuti urutan langkah berikutnya.

  1. Tambahkan kode berikut ke file Package.swift Anda:

    dependencies: [
       .package(url: "https://github.com/UJET/ccai-ios-sdk.git", from: "3.3.1")
    ],
    targets: [
       .target(
           name: "YourTargetName",
           dependencies: [
               .product(name: "CCAIKit", package: "CCAIKit")
           ]
       )
    ]
    
  2. Impor CCAIKit di file AppDelegate Anda:

    import CCAIKit
    
  3. Jika project Anda adalah SwiftUI, deklarasikan @UIApplicationDelegateAdaptor di struct App Anda:

    @main
    struct YourAppName: App {
       @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
       // ...
    }
    

Menginisialisasi SDK tanpa UI

Lakukan inisialisasi SDK selama peluncuran aplikasi. Karena arsitektur modular SDK, Anda harus melakukan inisialisasi sistem CCAI inti terlebih dahulu, lalu mendaftarkan modul layanan tertentu (seperti chat atau berbagi layar).

Inisialisasi dasar

SDK menggunakan struct InitOptions yang menggabungkan semua konfigurasi yang diperlukan:

import CCAIKit
import CCAIChat       // If using Chat
import CCAIScreenShare // If using Screen Share

class AppDelegate: NSObject, UIApplicationDelegate, CCAIDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        // 1. Configure initialization options
        let options = InitOptions(
            key: "YOUR_COMPANY_KEY",
            urlHost: "your_subdomain.ccaiplatform.com",
            delegate: self,
            languageCode: "en",       // ISO 639 code (defaults to "en")
            cacheAuthToken: true       // Whether to cache the auth token (defaults to true)
        )

        // 2. Initialize the core SDK
        do {
            try CCAI.shared.initialize(options: options)
        } catch {
            print("Failed to initialize CCAI: \(error.localizedDescription)")
            return true
        }

        // 3. Initialize feature modules
        // Chat minimal (no options required)
        CCAI.shared.initializeChat()

        // Chat with optional configuration
        // let chatOptions = ChatOptions(
        //     delegate: webFormDelegate,           // Implement to intercept and render custom web forms within your own UI
        //     downloadTranscriptVisibility: .hideInPostChat, // Hide the post-chat download affordance
        //     greeting: "Hello! How can I help you?"
        // )
        // CCAI.shared.initializeChat(chatOptions)

        // Screen Share (optional)
        // let screenShareOptions = ScreenShareOptions(
        //     key: "YOUR_SCREEN_SHARE_KEY",
        //     domain: "your_domain.com"
        // )
        // CCAI.shared.initializeScreenShare(screenShareOptions)

        return true
    }

    // ... CCAIDelegate methods (Authentication) go here ...
}

Referensi konfigurasi InitOptions

public struct InitOptions {
    /// The company key used for authentication
    public let key: String

    /// The host URL for CCAI platform (for example, "my-unique-instance.uc1.ccaiplatform.com")
    public let urlHost: String

    /// The preferred language code for localization (defaults to "en")
    public var languageCode: String

    /// The delegate that receives SDK events and callbacks
    public weak var delegate: CCAIDelegate?

    /// Whether to cache the authentication token (defaults to true)
    public let cacheAuthToken: Bool
}

Layanan SDK yang tersedia

Setelah inisialisasi, Anda dapat mengakses berbagai layanan melalui singleton CCAI.shared:

let authService = CCAI.shared.authService
let companyService = CCAI.shared.companyService
let queueMenuService = CCAI.shared.queueMenuService
let optionsService = CCAI.shared.optionsService
let languageService = CCAI.shared.languageService
let pushNotificationService = CCAI.shared.pushNotificationService
let endUserService = CCAI.shared.endUserService
let chatService = CCAI.shared.chatService           // Only available after initializeChat()
let screenShareService = CCAI.shared.screenShareService // Only available after initializeScreenShare()
let rateService = CCAI.shared.rateService            // For CSAT ratings and survey submission
let smartActionService = CCAI.shared.smartActionService // Dedicated service for smart action lifecycle

Mengambil konfigurasi perusahaan

Setelah inisialisasi, ambil konfigurasi tingkat perusahaan menggunakan companyService. Hal ini berguna untuk mengisi pemilih bahasa, menampilkan nama perusahaan, atau membaca detail kontak dukungan sebelum pengguna masuk ke antrean.

do {
    let company = try await CCAI.shared.companyService?.get()
    print("Company: \(company?.displayName ?? "Unknown")")
} catch {
    print("Failed to get company info: \(error)")
}

Mengautentikasi pengguna akhir

Headless Mobile SDK menggunakan Token Web JSON (JWT) untuk mengautentikasi pengguna dan meneruskan informasi kontekstual ke CRM agen dengan aman.

Cara kerjanya

SDK menggunakan alur autentikasi asinkron dua langkah yang disederhanakan:

  1. SDK menentukan bahwa SDK perlu mengautentikasi pengguna.

  2. Fungsi ini memanggil metode CCAIDelegate Anda - ccaiShouldAuthenticate() - yang merupakan fungsi asinkron.

  3. Aplikasi Anda menandatangani JWT dari jarak jauh di server backend menggunakan kode rahasia perusahaan Anda.

  4. Kemudian, aplikasi Anda meneruskan JWT yang ditandatangani ke CCAI.shared.authService?.authenticate(jwt) untuk menukarnya dengan token otorisasi.

  5. Token autentikasi ditampilkan ke SDK untuk menyelesaikan koneksi.

Menerapkan CCAIDelegate untuk autentikasi

Aplikasi Anda harus menerapkan protokol CCAIDelegate. SDK memanggil metode delegasi asinkron tunggal saat memerlukan autentikasi.

Protokol CCAIDelegate

public protocol CCAIDelegate: AnyObject {
    /// Authenticates the end user and returns an auth token
    func ccaiShouldAuthenticate() async -> String?
}

Contoh penerapan (Swift)

class AppDelegate: CCAIDelegate {
    func ccaiShouldAuthenticate() async -> String? {
        // 1. Sign JWT remotely on your backend server
        guard let jwt = await signJWTRemotely() else { return nil }

        // 2. Authenticate JWT using authService to get an auth token
        return try? await CCAI.shared.authService?.authenticate(jwt)
    }
}

Contoh lengkap dengan penandatanganan JWT untuk referensi dan pengujian

class AuthController: CCAIDelegate {
    func ccaiShouldAuthenticate() async -> String? {
        var jwt = JWT(claims: claims)

        // First, sign JWT with company secret (do this on your backend in production)
        guard let secret = self.companySecret,
              let key = secret.data(using: .utf8) else { return nil }
        let signer = JWTSigner.hs384(key: key)
        guard let encodedJWT = try? jwt.sign(using: signer) else { return nil }

        // Then authenticate JWT using authService to get an auth token
        return try? await CCAI.shared.authService?.authenticate(encodedJWT)
    }
}

Meneruskan data kustom ke CRM

Jika Anda ingin meneruskan data kontekstual ke agen (misalnya, OS perangkat pengguna saat ini, lokasinya, atau tingkat akunnya), backend Anda harus menyisipkan objek custom_data ke payload JWT sebelum menandatanganinya.

Setiap bagian data kustom harus diformat sebagai objek JSON yang berisi label (apa yang dilihat agen), value, dan type.

Jenis data yang didukung

  • string: Teks standar (misalnya, "iPhone 14 Pro").

  • number: Bilangan bulat atau float (misalnya, 1234 atau 99,99).

  • date: Stempel waktu Unix UTC 13 digit termasuk milidetik (misalnya, 1537399655992).

  • url: Format URL HTTP/HTTPS standar.

  • boolean: Nilai benar atau salah standar.

Kunci CRM yang dicadangkan

Platform CCAI mendukung kunci khusus yang dicadangkan yang memicu perilaku bawaan di platform, seperti menandai pengguna sebagai VIP atau memperingatkan agen tentang pihak tidak bertanggung jawab. Parameter ini harus diformat sebagai jenis boolean dan hanya diterima jika payload ditandatangani menggunakan metode JWT yang aman.

  • reserved_verified_customer: Menunjukkan apakah pelanggan telah berhasil diautentikasi oleh sistem internal Anda.

  • reserved_bad_actor: Menandai pengguna ke agen sebagai calon spammer atau akun palsu.

  • reserved_repeat_customer: Menunjukkan apakah pelanggan ini sering menghubungi dukungan baru-baru ini.

Contoh payload dengan kunci yang dicadangkan

{
  "iat": 1537399656,
  "exp": 1537400256,
  "custom_data": {
    "reserved_verified_customer": {
      "label": "Verified Customer",
      "value": true,
      "type": "boolean"
    },
    "reserved_bad_actor": {
      "label": "Bad Actor",
      "value": false,
      "type": "boolean"
    },
    "reserved_repeat_customer": {
      "label": "Repeat Customer",
      "value": false,
      "type": "boolean"
    }
  }
}

Mengelola token autentikasi

SDK juga menyediakan metode untuk memperbarui atau menghapus token autentikasi yang di-cache secara manual:

// Set a new auth token
CCAI.shared.authService?.updateAuthToken("new_auth_token")

// Clear the current token (for example, on user logout)
CCAI.shared.authService?.updateAuthToken(nil)

Skema payload JWT data kustom

Saat backend Anda membuat payload akhir yang akan ditandatangani dengan kode rahasia perusahaan Anda, payload tersebut harus mengikuti skema ini secara ketat. Perhatikan stempel waktu iat (dikeluarkan pada) dan exp (masa berlaku) yang wajib ada.

{
  "iat": 1537399656,
  "exp": 1537400256,
  "custom_data": {
    "os_version": {
      "label": "OS Version",
      "value": "16.4",
      "type": "string"
    },
    "membership_tier": {
      "label": "Membership Tier",
      "value": "Platinum",
      "type": "string"
    },
    "ssn_last_four": {
      "label": "SSN",
      "value": "1234",
      "type": "string",
      "invisible_to_agent": true
    },
    "reserved_verified_customer": {
      "label": "Verified Customer",
      "value": true,
      "type": "boolean"
    }
  }
}

Mengaktifkan notifikasi push

SDK menggunakan notifikasi push untuk:

  • Panggilan masuk.

  • Tindakan smart dan peristiwa terkait panggilan tertentu.

  • Mempertahankan status saat aplikasi berada di latar belakang.

Mengonfigurasi sertifikat

CCAI Platform memerlukan dua jenis sertifikat push Apple yang berbeda untuk disimpan di portal administrator CCAI Platform:

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

  • Sertifikat layanan VoIP - digunakan untuk notifikasi panggilan masuk dan tindakan smart terkait panggilan tertentu.

Kedua sertifikat dibuat di portal Apple Developer, dikonversi ke format PEM, lalu diupload ke portal administrator CCAI Platform.

Membuat sertifikat SSL APNs

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

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

  2. Pilih tombol + untuk membuat sertifikat baru.

  3. Di bagian Services, pilih Apple Push Notification service SSL (Sandbox & Production).

  4. Pilih ID Aplikasi yang cocok dengan ID paket aplikasi Anda, lalu pilih Lanjutkan.

  5. 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 Alamat Email CA kosong, pilih Disimpan ke disk, lalu pilih Lanjutkan.

  6. Pilih Lanjutkan, lalu Download file .cer yang dihasilkan.

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

  8. Di Keychain Access, temukan sertifikat yang diinstal, klik kanan, lalu pilih Export… untuk menyimpannya sebagai file .p12. Anda akan diminta untuk menyetel sandi ekspor.

  9. Konversi 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 berprioritas 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.

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

  2. Pilih tombol + untuk membuat sertifikat baru.

  3. Di bagian Services, pilih VoIP Services Certificate.

  4. Pilih ID Aplikasi yang cocok dengan ID paket aplikasi Anda, lalu pilih Lanjutkan.

  5. Upload Permintaan Penandatanganan Sertifikat (CSR) yang sama dengan yang Anda buat untuk sertifikat SSL APNs (atau buat yang baru).

  6. Pilih Lanjutkan, lalu Download file .cer yang dihasilkan.

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

  8. Di Keychain Access, temukan sertifikat layanan VoIP yang diinstal, klik kanan, lalu pilih Export… untuk menyimpannya sebagai file .p12.

  9. Konversi 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 administrator CCAI Platform

  1. Login ke portal administrator CCAI Platform.

  2. Buka Setelan > Setelan Developer > Aplikasi Seluler.

  3. Upload sertifikat PEM APNs.

  4. Upload sertifikat PEM VoIP.

Meminta izin notifikasi push

SDK menyediakan metode praktis untuk meminta otorisasi notifikasi push (khusus iOS):

let options: UNAuthorizationOptions = [.alert, .sound]
try await CCAI.shared.pushNotificationService?.registerForPushNotifications(
    options: options
) { granted in
    if granted {
        print("Push notifications granted")
    } else {
        print("Push notifications denied")
    }
}

Mendaftar untuk notifikasi jarak jauh

Terapkan delegasi notifikasi push di AppDelegate. SDK menyediakan pushNotificationService untuk meneruskan token:

import CCAIKit

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        CCAI.shared.pushNotificationService?.updatePushToken(
            data: deviceToken,
            type: .apns
        )
    }

    func application(
        _ application: UIApplication,
        didFailToRegisterForRemoteNotificationsWithError error: Error
    ) {
        CCAI.shared.pushNotificationService?.updatePushToken(
            data: nil,
            type: .apns
        )
    }
}

Pastikan untuk mengaktifkan Capabilities > Push notifications dan Background modes untuk notifikasi jarak jauh dari tab Target > Signing & capabilities di Xcode.

Menangani notifikasi push masuk

Saat Anda menerima payload push, teruskan ke SDK untuk diproses:

func application(
    _ application: UIApplication,
    didReceiveRemoteNotification userInfo: [AnyHashable: Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
    // Let the SDK determine if this push relates to an incoming call,
    // session update, or another internal event
    CCAI.shared.pushNotificationService?.handlePushNotification(userInfo)
    completionHandler(.newData)
}

SDK menentukan apakah push terkait dengan panggilan masuk, update sesi, atau peristiwa internal lainnya, dan menanganinya dengan tepat.

Mendaftar untuk notifikasi push VoIP

Untuk panggilan masuk dan tindakan smart berbasis PSTN tertentu, SDK memerlukan token push VoIP selain token APNs standar. Notifikasi push VoIP dikirimkan dengan prioritas tinggi dan dapat mengaktifkan aplikasi Anda dari status dihentikan.

Impor PushKit dan buat PKPushRegistry di didFinishLaunchingWithOptions AppDelegate Anda

import PushKit

class AppDelegate: NSObject, UIApplicationDelegate, PKPushRegistryDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        // ... SDK initialization ...

        // Register for VoIP push notifications
        let voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [.voIP]

        return true
    }
}

Terapkan metode PKPushRegistryDelegate untuk meneruskan token dan payload VoIP ke SDK

// MARK: - PKPushRegistryDelegate

func pushRegistry(
    _ registry: PKPushRegistry,
    didUpdate credentials: PKPushCredentials,
    for type: PKPushType
) {
    // Forward the VoIP token to the SDK
    CCAI.shared.pushNotificationService?.updatePushToken(
        data: credentials.token,
        type: .voip
    )
}

func pushRegistry(
    _ registry: PKPushRegistry,
    didInvalidatePushTokenFor type: PKPushType
) {
    // Clear the VoIP token
    CCAI.shared.pushNotificationService?.updatePushToken(
        data: nil,
        type: .voip
    )
}

func pushRegistry(
    _ registry: PKPushRegistry,
    didReceiveIncomingPushWith payload: PKPushPayload,
    for type: PKPushType,
    completion: @escaping () -> Void
) {
    guard type == .voIP else {
        completion()
        return
    }

    // Forward the VoIP payload to the SDK using the `handleVoIPPush`
    // extension on `CCAI` (defined in the `CCAICall` module). The SDK
    // takes ownership of the call lifecycle; invoke PushKit's completion
    // handler in the trailing closure after the SDK has accepted the
    // payload.
    CCAI.shared.handleVoIPPush(payload: payload.dictionaryPayload) { completion() }
}