SDK headless para dispositivos móveis para iOS: como começar

Este documento explica como começar a usar o SDK Headless Mobile para iOS.

O SDK Headless Mobile para iOS permite adicionar suporte da plataforma CCAI diretamente à sua experiência integrada do iOS sem usar uma interface pré-criada da plataforma CCAI.

Em vez de apresentar um widget com a marca da plataforma CCAI, você:

  • Integre o SDK do CCAI para iOS ao seu app.

  • Crie suas próprias telas, navegação e design visual.

  • Use o SDK para:

    • Iniciar e gerenciar sessões de chat e de voz.

    • Ofereça opções de e-mail, ligações programadas e redirecionamento.

    • Suporte a ações inteligentes, anexos e fluxos pós-sessão (CSAT, pesquisas, agente virtual).

A CCAI Platform processa a lógica da central de atendimento (roteamento, filas, canais, configuração, relatórios). Você é o proprietário da experiência completa do app (UI, fluxos e branding).

Se você preferir uma interface configurável pré-criada em vez de criar a sua própria, use o SDK para dispositivos móveis padrão.

Requisitos

Estes são os requisitos para integrar o SDK headless para dispositivos móveis para iOS.

Requisitos da plataforma iOS

  • Versão mínima do iOS: iOS 16.6 ou mais recente

  • Linguagem: Swift

  • IDE: versão estável mais recente do Xcode compatível com seu app

  • Arquiteturas: arquiteturas padrão do iOS compatíveis com sua cadeia de ferramentas atual do Xcode.

Permissões do app

Como o app integrado processa a UI das ações inteligentes (captura de fotos, gravação de vídeos ou verificação de identidade), você precisa declarar as permissões de privacidade obrigatórias da Apple.

Adicione as seguintes chaves ao Info.plist com uma descrição de como o app usa os dados:

  • NSCameraUsageDescription: necessário para que os usuários tirem e enviem fotos/vídeos ou para ações inteligentes solicitadas pelo agente.

  • NSMicrophoneUsageDescription: necessário para chamadas de voz instantâneas e para gravar vídeos com som.

  • NSPhotoLibraryUsageDescription: necessário para que os usuários façam upload de fotos ou vídeos do rolo da câmera.

  • NSFaceIDUsageDescription: obrigatório se você oferecer suporte a ações inteligentes de verificação biométrica.

Requisitos da instância da plataforma CCAI

Você precisa acessar as Configurações do desenvolvedor da instância da plataforma CCAI para obter os seguintes detalhes:

  • Chave da empresa

  • Código secreto da empresa

  • URL do host: o nome do host da plataforma CCAI (por exemplo, your_subdomain.ccaiplatform.com)

Esses valores são usados para:

  • Chave da empresa + URL do host: no seu app iOS para inicializar o SDK.

  • Código secreto da empresa: no seu back-end para assinar JSON Web Tokens (JWT) usados para autenticar usuários.

Notificações push

Para fazer ligações e usar algumas ações inteligentes, você precisa do seguinte:

  • Configuração do serviço de notificação push da Apple (APNs) para notificações push padrão.

  • Um certificado de serviços de VoIP para oferecer suporte a chamadas recebidas e notificações específicas relacionadas a chamadas.

Você vai:

  • Configure as credenciais do APNs e do VoIP no portal do desenvolvedor da Apple.

  • Faça upload dos certificados convertidos no portal do administrador da plataforma CCAI em Configurações > Configurações do desenvolvedor > App móvel.

  • Registre seu app para receber notificações remotas e pushs de VoIP.

  • Encaminhe os tokens de dispositivo adequados para o SDK.

  • Em Target > Signing & capabilities, ative o seguinte:

    • Recurso de notificações push.

    • Recurso Modos em segundo plano com estes itens marcados:

      • Voz sobre IP: necessário para notificações push de VoIP (chamadas recebidas, ações inteligentes usando PSTN).

      • Áudio, AirPlay e picture-in-picture: necessários para que o áudio da ligação continue quando o app estiver em segundo plano.

      • Notificações remotas: necessárias para a entrega push padrão do APNs.

Como o SDK headless do iOS se encaixa no seu app

O SDK Headless Mobile para iOS pode ser visto como três camadas:

Plataforma e SDK da CCAI Platform

O SDK interage com segurança com a plataforma CCAI Platform e oferece:

  • Autenticação com JSON Web Tokens (JWT).

  • Metadados de roteamento de fila e canal (chat, voz, ligação programada, e-mail, links de redirecionamento externo).

  • Gerenciamento de estado de sessão em tempo real.

  • O pipeline de transporte seguro para ações inteligentes, anexos de arquivos e compartilhamento de tela.

  • Lógica de evasão e avaliação de hierarquia pós-sessão.

Seu app iOS (UI e a lógica são processadas por você)

Você controla toda a experiência visual e de navegação:

  • Pontos de entrada: por exemplo, uma guia Ajuda ou um botão Entre em contato.

  • Menus: como você mostra as filas (por exemplo, Faturamento, Suporte técnico).

  • Interface na sessão: balões de chat, telas de chamada e controles personalizados.

  • O que o app faz: chama APIs do SDK para iniciar e encerrar sessões, ouve eventos do SDK e direciona a navegação do controlador de visualização.

Configuração do portal do administrador da plataforma CCAI

Os administradores da Plataforma CCAI configuram as regras de engajamento (horário de funcionamento, canais disponíveis, limites de tempo de espera e pesquisas). O SDK lê essa configuração e a expõe ao app como dados e eventos brutos. Você decide como desenhar essa configuração na tela.

Recuperar credenciais da empresa

Antes de integrar o SDK, extraia as credenciais da sua instância da plataforma CCAI:

  1. Faça login no portal de administradores da plataforma CCAI com uma conta de administrador.

  2. Acesse Configurações > Configurações do desenvolvedor.

  3. Em Chave da empresa e código secreto, copie:

    • Chave da empresa

    • Código secreto da empresa

  4. Anote o URL do host:o nome do host da plataforma CCAI (por exemplo, your_subdomain.ccaiplatform.com).

Você usará:

  • No seu app iOS: chave da empresa + URL do host.

  • No seu servidor de back-end: código secreto da empresa para assinar JWTs para:

    • Autenticação de usuário final.

    • Dados ou contexto personalizados opcionais usados pela plataforma CCAI.

Adicionar o SDK ao app iOS

O SDK Headless é criado usando uma arquitetura modular. Você instala o CCAIKit principal junto com os módulos de recursos específicos que o app exige (por exemplo, CCAIChat ou CCAIScreenShare).

Para integrar o SDK do iOS no seu app, siga a próxima sequência de etapas.

  1. Adicione a instrução a seguir ao seu arquivo Package.swift:

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

    import CCAIKit
    
  3. Se o projeto for SwiftUI, declare @UIApplicationDelegateAdaptor no struct App:

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

Inicializar o SDK sem interface gráfica

Inicialize o SDK durante a inicialização do app. Devido à arquitetura modular do SDK, é necessário inicializar primeiro o sistema principal da CCAI e depois registrar os módulos de serviço específicos (como chat ou compartilhamento de tela).

Inicialização básica

O SDK usa uma struct InitOptions que agrupa toda a configuração necessária:

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

Referência de configuração do 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
}

Serviços de SDK disponíveis

Depois da inicialização, você pode acessar vários serviços pelo 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

Buscar configuração da empresa

Após a inicialização, busque a configuração no nível da empresa usando companyService. Isso é útil para preencher seletores de idioma, mostrar o nome da empresa ou ler os detalhes de contato do suporte antes que o usuário entre em uma fila.

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

Autenticar usuários finais

O SDK Headless Mobile usa JSON Web Tokens (JWT) para autenticar usuários e transmitir informações contextuais com segurança para o CRM do agente.

Como funciona

O SDK usa um fluxo de autenticação assíncrona simplificado em duas etapas:

  1. O SDK determina que precisa autenticar o usuário.

  2. Ele chama o método CCAIDelegate, ccaiShouldAuthenticate(), que é uma função assíncrona.

  3. Seu app assina um JWT remotamente no servidor de back-end usando o código secreto da empresa.

  4. Em seguida, o app transmite o JWT assinado para CCAI.shared.authService?.authenticate(jwt) e o troca por um token de autenticação.

  5. O token de autenticação é retornado ao SDK para concluir a conexão.

Implementar o CCAIDelegate para autenticação

O app precisa implementar o protocolo CCAIDelegate. O SDK chama o único método delegado assíncrono quando precisa de autenticação.

Protocolo CCAIDelegate

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

Exemplo de implementação (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)
    }
}

Exemplo completo com assinatura JWT para referência e teste

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)
    }
}

Transmitir dados personalizados ao CRM

Se você quiser transmitir dados contextuais ao agente (por exemplo, o SO do dispositivo atual do usuário, a localização ou o nível da conta), seu back-end precisará injetar um objeto custom_data no payload do JWT antes de assiná-lo.

Cada parte de dados personalizados precisa ser formatada como um objeto JSON que contenha um label (o que o agente vê), um value e um type.

Tipos de dados compatíveis

  • string: texto padrão (por exemplo, "iPhone 14 Pro").

  • number: números inteiros ou de ponto flutuante (por exemplo, 1234 ou 99,99).

  • date: um carimbo de data/hora Unix UTC de 13 dígitos, incluindo milissegundos (por exemplo, 1537399655992).

  • url: formato padrão de URL HTTP/HTTPS.

  • boolean: valor padrão verdadeiro ou falso.

Chaves de CRM reservadas

A plataforma CCAI é compatível com chaves reservadas específicas que acionam comportamentos integrados na plataforma, como sinalizar um usuário como VIP ou avisar um agente sobre um usuário de má-fé. Eles precisam ser formatados como tipos booleanos e só serão aceitos se o payload for assinado usando o método JWT seguro.

  • reserved_verified_customer: indica se um cliente foi autenticado com sucesso pelos seus sistemas internos.

  • reserved_bad_actor: sinaliza o usuário para o agente como um possível spammer ou conta fraudulenta.

  • reserved_repeat_customer: indica se o cliente entrou em contato com o suporte com frequência recentemente.

Exemplo de payload com chaves reservadas

{
  "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"
    }
  }
}

Gerenciar tokens de autenticação

O SDK também oferece métodos para atualizar ou limpar manualmente o token de autenticação em cache:

// 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)

Esquema de payload JWT de dados personalizados

Quando o back-end cria o payload final para ser assinado com o código secreto da empresa, ele precisa seguir estritamente este esquema. Observe os carimbos de data/hora obrigatórios iat (emitido em) e exp (validade).

{
  "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"
    }
  }
}

Ativar notificações push

O SDK usa notificações push para:

  • Ligações recebidas.

  • Algumas ações inteligentes e eventos relacionados a chamadas.

  • Manter o estado quando o app está em segundo plano.

Configurar certificados

A plataforma CCAI exige que dois tipos diferentes de certificados push da Apple sejam salvos no portal do administrador da plataforma CCAI:

  • Um certificado SSL do serviço de notificação push da Apple (APNs), usado para notificações push remotas padrão.

  • Um certificado de serviços de VoIP, usado para notificações de chamadas recebidas e algumas ações inteligentes relacionadas a chamadas.

Os dois certificados são criados no portal Apple Developer, convertidos para o formato PEM e enviados ao portal do administrador da CCAI Platform.

Criar um certificado SSL do APNs

Siga estas etapas, com base no guia oficial da Apple Como estabelecer uma conexão baseada em certificado com APNs, para criar um certificado SSL do APNs.

  1. Faça login em developer.apple.com e navegue até Certificates, Identifiers & Profiles.

  2. Selecione o botão + para criar um certificado.

  3. Em "Serviços", selecione SSL do serviço de notificação push da Apple (sandbox e Production).

  4. Escolha o ID do app que corresponde ao identificador do pacote do aplicativo e selecione Continuar.

  5. Faça upload de uma solicitação de assinatura de certificado (CSR) gerada pelo Acesso às Chaves no Mac:

    • Abra Acesso às Chaves > Assistente de Certificados > Solicitar um certificado de uma autoridade certificadora…

    • Digite seu endereço de e-mail, deixe o campo "Endereço de e-mail da CA" vazio, selecione Salvo em disco e clique em Continuar.

  6. Selecione Continuar e Baixar o arquivo .cer gerado.

  7. Clique duas vezes no arquivo .cer para instalá-lo no Keychain.

  8. No Keychain Access, localize o certificado instalado, clique com o botão direito do mouse nele e selecione Exportar… para salvar como um arquivo .p12. Você vai receber uma solicitação para definir uma senha de exportação.

  9. Converta o arquivo .p12 para o formato PEM usando 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
    

Criar um certificado de serviços de VoIP

Os certificados de serviços VoIP permitem que seu app receba notificações push de alta prioridade pelo framework PushKit da Apple, que pode ativar o app de um estado encerrado para atender chamadas recebidas. Para conferir as etapas oficiais mais recentes, consulte Criar certificados de serviços VoIP na documentação para desenvolvedores da Apple.

  1. Faça login em developer.apple.com e navegue até Certificates, Identifiers & Profiles.

  2. Selecione o botão + para criar um certificado.

  3. Em "Serviços", selecione Certificado de serviços de VoIP.

  4. Escolha o ID do app que corresponde ao identificador do pacote do aplicativo e selecione Continuar.

  5. Faça upload da mesma solicitação de assinatura de certificado (CSR) gerada para seu certificado SSL do APNs ou crie uma nova.

  6. Selecione Continuar e Baixar o arquivo .cer gerado.

  7. Clique duas vezes no arquivo .cer para instalá-lo no Keychain.

  8. No Keychain Access, localize o certificado de serviços VoIP instalados, clique com o botão direito do mouse nele e selecione Exportar… para salvar como um arquivo .p12.

  9. Converta o arquivo .p12 para o formato PEM usando 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
    

Fazer upload de certificados para o portal do administrador da plataforma CCAI

  1. Faça login no portal do administrador da Plataforma CCAI.

  2. Acesse Configurações > Configurações do desenvolvedor > App móvel.

  3. Faça upload do certificado PEM das APNs.

  4. Faça upload do certificado PEM de VoIP.

Solicitar permissões de notificações push

O SDK oferece um método conveniente para solicitar autorização de notificação push (somente 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")
    }
}

Registrar o app para receber notificações remotas

Implemente os delegados de notificação push no seu AppDelegate. O SDK fornece pushNotificationService para encaminhar tokens:

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
        )
    }
}

Não se esqueça de ativar Capabilities > Push notifications e Background modes para notificações remotas na guia Target > Signing & capabilities no Xcode.

Gerenciar notificações push recebidas

Quando você receber um payload de push, encaminhe-o ao SDK para processamento:

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)
}

O SDK determina se o push está relacionado a uma chamada recebida, uma atualização de sessão ou outro evento interno e o processa de acordo.

Registrar para receber notificações push de VoIP

Para chamadas recebidas e determinadas ações inteligentes baseadas em PSTN, o SDK exige um token de push VoIP além do token APNs padrão. As notificações push de VoIP são entregues com alta prioridade e podem despertar o app de um estado encerrado.

Importe PushKit e crie um PKPushRegistry no didFinishLaunchingWithOptions do AppDelegate

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

Implemente os métodos PKPushRegistryDelegate para encaminhar tokens e payloads de VoIP ao 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() }
}