Das mobile SDK für die Contact Center AI Platform (CCAI Platform) für das Apple iOS-Betriebssystem bietet die Möglichkeit, die mobile CCAI Platform-Umgebung in mobile iOS-Anwendungen einzubetten.
Voraussetzungen
Für das iOS Mobile SDK gelten die folgenden Anforderungen:
- iOS 12.0 oder höher
Unternehmensanmeldedaten abrufen
Melden Sie sich mit Administratoranmeldedaten im Portal der Contact Center AI Platform (CCAI Platform) an.
Gehen Sie zu den Einstellungen > Entwicklereinstellungen.
Notieren Sie sich unter Company Key (Unternehmensschlüssel) und Secret Code (Geheimcode) den Unternehmensschlüssel und den Unternehmensgeheimcode.
Erste Schritte
Im Folgenden finden Sie eine Anleitung für den Einstieg in das mobile SDK für iOS für die CCAI Platform.
Installation
Um loszulegen, müssen Sie das iOS SDK installieren.
Beispiel-App herunterladen
Laden Sie die iOS-Beispiel-App herunter.
Rufen Sie den Ordner auf und installieren Sie die Abhängigkeiten mit CocoaPods:
$ pod install --project-directory=ExampleAppSo konfigurieren Sie Projekteinstellungen schnell:
$ ./setup.shAlternativ können Sie die Projekteinstellungen auch manuell bearbeiten. Gehen Sie dazu so vor:
Öffnen Sie
ExampleApp.xcworkspace.Ersetzen Sie die Werte
UJETCompanyKeyundUJETCompanySecretinInfo.plistdurch die Werte Unternehmensschlüssel und Geheimer Unternehmenscode auf der Seite Einstellungen > Entwicklereinstellungen im CCAI Platform-Portal.Ersetzen Sie den Wert
UJETSubdomaininInfo.plistdurch die Subdomain in der URL für Ihr CCAI Platform-Portal. Die Subdomain steht in der URL direkt vor.ujet.com, z. B.your-subdomaininhttps://your-subdomain.ujet.com/settings/developer-setting.
In Ihr Projekt einbinden
Die Einbindung des iOS SDK in Ihre Anwendung hängt von Ihrer Entwicklungsumgebung ab.
Swift Package Manager
Fügen Sie das Swift-Paket für das iOS SDK hinzu.
Fügen Sie in den Buildeinstellungen „-ObjC“ zu „Other Linker Flags“ (Weitere Linker-Flags) hinzu.
In der aktuellen Version von Xcode (derzeit 13.2) gibt es ein bekanntes Problem beim Verwenden von binären Frameworks, die über den Swift Package Manager verteilt werden. Die aktuelle Problemumgehung besteht darin, den Build-Phasen Ihres Xcode-Projekts eine Run Script-Phase hinzuzufügen. Diese Phase „Run Script“ sollte nach der Build-Phase „Embed Frameworks“ erfolgen. Diese neue Phase „Run Script“ sollte den folgenden Code enthalten:
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
Fügen Sie der Podfile die folgende Zeile hinzu:
pod 'UJET', :podspec => 'https://sdk.ujet.co/ios/x.y.z/ujet.podspec' #specific version x.y.zFühren Sie „pod install“ aus. Wenn das iOS SDK bereits integriert wurde, führen Sie stattdessen „pod update CCAI Platform“ aus.
Karthago
Google Cloud empfiehlt die Verwendung eines Abhängigkeitsmanagers oder die manuelle Integration, da eine CCAI Platform-Abhängigkeit Carthage nicht unterstützt. Fügen Sie dazu die folgenden Zeilen hinzu:
binary "https://sdk.ujet.co/ios/UJETKit.json
binary "https://sdk.ujet.co/ios/UJETFoundationKit.json
binary https://raw.githubusercontent.com/twilio/twilio-voice-ios/Releases/twilio-voice-ios.json
Manuelle Integration
Das wird nicht unterstützt: https://github.com/twilio/conversations-ios/issues/12.
binär https://raw.githubusercontent.com/twilio/conversations-ios/master/twilio-convo-ios.json
Führen Sie
carthage bootstrap --use-xcframeworksodercarthage update --use-xcframeworksaus (wenn Sie Abhängigkeiten aktualisieren).Laden Sie
UJETKit.xcframework,UJETFoundationKit.xcframework,UJETChatRedKit.xcframework,UJETChatBlueKit.xcframework,UJETTwilioCallKit.xcframeworkund alle AbhängigkeitenTwilioVoice.xcframeworkundTwilioConversationsClient.xcframeworkherunter.Fügen Sie das UJETKit.xcframework Ihrem Ziel hinzu, indem Sie es in den Bereich „Frameworks, Libraries, and Embedded Content“ (Frameworks, Bibliotheken und eingebettete Inhalte) ziehen.
Wiederholen Sie die Schritte 2 und 3 für alle Abhängigkeiten aus Schritt 1.
Setzen Sie in den Build-Einstellungen
-ObjCaufOther Linker Flags.Fügen Sie
libc++.tbdals Abhängigkeit imLinked Frameworks-Abschnitt des Ziels hinzu.
Wenn Sie das SDK manuell mit dem Beispielprojekt erstellen möchten, folgen Sie den Schritten im nächsten Abschnitt.
SDK manuell mit dem Beispielprojekt erstellen
Gehen Sie dazu so vor:
Laden Sie alle Frameworks herunter, einschließlich
UJETKit.xcframeworkund anderer Abhängigkeiten.Erstellen Sie im Projektstammordner den Ordner „CCAI Platform“ und entpacken Sie alle Frameworks.
Wählen Sie das Ziel
Objc-ManualoderSwift-Manualaus und erstellen Sie den Build.
Import-Framework
In den folgenden Abschnitten finden Sie eine Anleitung zum Importieren des Frameworks.
Objective-C-Projekt
@import UJETKit;
Swift-Projekt
swiftimport
UJETimport UJETKit
SDK initialisieren
CCAI Platform mit UJET_COMPANY_KEY und UJET_SUBDOMAIN initialisieren
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;
}
Sie können die Logebene von verbose in error ändern. Die Standard-Logebene ist UjetLogLevelInfo.
[UJET.setLogLevel:UjetLogLevelVerbose];
Endnutzerauthentifizierung
Über die iOS-App auf das iOS SDK zugreifen
Um sicherzustellen, dass der Endnutzer authentifiziert ist, führen wir den JWT-Signiermechanismus ein.
Das iOS SDK fordert an, die Nutzlast zu signieren, wenn eine Authentifizierung erforderlich ist. Wenn die Signierung erfolgreich ist, tauscht die Anwendung das signierte JWT gegen das Endnutzer-Authentifizierungstoken ein. Der Erfolgs- oder Fehlerblock muss aufgerufen werden, bevor der Delegat zurückgegeben wird.
Für anonyme Nutzer (Kennung = nil) erstellt die Anwendung eine UUID. Wenn der Nutzer später mit einer Kennung authentifiziert wird, versucht die Anwendung, die beiden Nutzer anhand der UUID zusammenzuführen.
In UJETObject.h aus dem Beispielprojekt:
@import UJETKit;
@interface UJETObject : NSObject <UJETDelegate>
Implementieren Sie signPayload: payloadType: success: failure: delegate method.
- (void)signPayload:(NSDictionary *)payload payloadType:(UjetPayloadType)payloadType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
if (payloadType == UjetPayloadAuthToken) {
[self signAuthTokenInLocal:payload success:success failure:failure];
}
}
- (void)signAuthTokenInLocal:(NSDictionary *)payload success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
NSMutableDictionary *payloadData = [payload mutableCopy];
NSDictionary *userData = [[NSUserDefaults standardUserDefaults] objectForKey:@"user-data"];
[payloadData addEntriesFromDictionary:userData];
payloadData[@"iat"] = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]; // required
payloadData[@"exp"] = [NSNumber numberWithDouble:([[NSDate date] timeIntervalSince1970] + 600)]; // required
NSString *signedToken = [self encodeJWT:payloadData];
if (signedToken.length > 0) {
success(signedToken);
} else {
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Failed to sign token" };
NSError *error = [NSError errorWithDomain:@"ExampleApp" code:0 userInfo:userInfo];
failure(error);
}
}
- (NSString *)encodeJWT:(NSDictionary *)payload {
id<JWTAlgorithm> algorithm = [JWTAlgorithmHSBase algorithm384];
NSString *secret = NSBundle.mainBundle.infoDictionary[@"UJETCompanySecret"];
return [JWTBuilder encodePayload:payload].secret().algorithm(algorithm).encode;
}
Wir empfehlen dringend, die Nutzlast von Ihrem Anwendungsserver und nicht vom Client aus zu signieren.
In diesem Beispiel wird die lokale Signierung zu Testzwecken verwendet. Siehe signDataInRemote: success: failure: in der Datei UJETObject.m.
Weitere Informationen finden Sie unter SDK-Endnutzerauthentifizierung.
Push-Benachrichtigungen einrichten
Die App sendet Push-Benachrichtigungen, um Smart Actions wie die Bestätigung und das Foto anzufordern und einen eingehenden Anruf zu melden. Für die Anwendung müssen zwei verschiedene Arten von Zertifikaten (VoIP und APNs) im Admin-Portal gespeichert werden.
Zertifikat für VoIP-Dienste vorbereiten
Referenzdokumentation für VoIP-Push-Benachrichtigungen von Apple
Erstellen und laden Sie das VoIP-Zertifikat von der Apple Developer-Website herunter.
Doppelklicken Sie auf das Zertifikat, um es dem Schlüsselbund hinzuzufügen.
Starten Sie auf Ihrem Mac die Schlüsselbundverwaltung.
Wählen Sie in der Seitenleiste links die Kategorie „Meine Zertifikate“ aus.
Klicken Sie mit der rechten Maustaste auf das Zertifikat „VoIP Services: your.app.id“.
Wählen Sie im Pop-up-Menü Exportieren aus.
Speichern Sie die Datei als „cert.p12“, ohne sie mit einem Passwort zu schützen. Lassen Sie das Passwortfeld dazu leer.
Führen Sie im Terminal den folgenden Befehl aus.
openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -debug -showcertDer obere Teil von „cert.pem“ ist das Zertifikat und der untere Teil ist der private Schlüssel.
Prüfen Sie, ob Ihr Zertifikat mit dem Push-Benachrichtigungsserver von Apple funktioniert.
openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -debug -showcertsBei Erfolg sollte Folgendes zurückgegeben werden:
--- New, TLSv1/SSLv3, Cipher is AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : AES256-SHA Session-ID: Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None Start Time: 1475785489 Timeout : 300 (sec) Verify return code: 0 (ok) ---Melden Sie sich mit Administratoranmeldedaten im CCAI Platform-Portal an und rufen Sie Einstellungen > Entwicklereinstellungen > Mobile App auf.
Füllen Sie das Zertifikat im Abschnitt „VoIP Services Certificate“ (VoIP-Dienstezertifikat) aus und speichern Sie es. Achten Sie darauf, dass sowohl das Zertifikat als auch der private Schlüssel durch Begrenzungen (
-----BEGIN-----und-----END-----) eingeschlossen sind.Klicken Sie das Kästchen „Sandbox“ an, wenn Sie eine App mit einem Entwicklungsprofil ausführen, z. B. beim Debuggen in Xcode. Wenn Ihre App für Ad-hoc- oder App-Store-Bereitstellung archiviert wird und ein Bereitstellungsprofil für die Verteilung verwendet, deaktivieren Sie das Kontrollkästchen „Sandbox“.
SSL für den Apple Push Notification Service vorbereiten
Der Vorgang ist ähnlich wie bei Zertifikaten für VoIP-Dienste. In diesem Fall wird das SSL-Zertifikat für den Apple Push Notification Service (Sandbox und Produktion) verwendet. Eine Anleitung zum Erstellen des Zertifikats finden Sie in der Dokumentation zum Apple-Server für Remote-Benachrichtigungen.
Push-Benachrichtigungen einbinden
In AppDelegate.m:
@import PushKit;
@interface AppDelegate() <PKPushRegistryDelegate>
In application:didFinishLaunchingWithOptions: method:
// Initialize CCAI Platform
[UJET] initialize:UJET_COMPANY_KEY subdomain:UJET_SUBDOMAIN delegate:self];
// Register for VoIP notifications on launch.
PKPushRegistry *voipRegistry = [[PKPushRegistry alloc] initWithQueue: dispatch_get_main_queue()];
voipRegistry.delegate = self;
voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
Fügen Sie die folgenden Delegatenmethoden in die Datei zur Implementierung des UIApplicationDelegate-Protokolls ein:
Drucken Sie Ihr Geräte-Token, um Push-Benachrichtigungen zu testen.
// PKPushRegistryDelegate
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type {
[UJET updatePushToken:credentials.token type:UjetPushTypeVoIP];
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
if (payload.dictionaryPayload[@"ujet"]) {
[UjetreceivedNotification:payload.dictionaryPayload completion:completion];
} else {
completion();
}
}
// UIApplicationDelegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[UjetupdatePushToken:deviceToken type:UjetPushTypeAPN];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
if (userInfo[@"ujet"]) {
[UJET receivedNotification:userInfo completion:nil];
}
}
// UserNotificationsDelegate overrides [UIApplicationDelegate didReceiveRemoteNotification:]
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
NSDictionary *userInfo = notification.request.content.userInfo;
if (userInfo[@"ujet"] != nil) {
[UJET receivedNotification:userInfo completion:nil];
}
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[@"ujet"] != nil) {
[UJET receivedNotification:userInfo completion:nil];
}
}
Push-Benachrichtigungen aktivieren
Wählen Sie Ihr Ziel aus und öffnen Sie den Tab Funktionen.
Aktivieren Sie den Schalter für Push-Benachrichtigungen.
Push-Benachrichtigungen testen
In den folgenden Abschnitten finden Sie eine Anleitung zum Testen der Push-Benachrichtigungen.
Bereich zur Fehlerbehebung für Push-Benachrichtigungen
Rufen Sie im Administratorportal die Einstellungen > Entwicklereinstellungen auf. Suchen Sie auf dieser Seite nach dem Abschnitt Push Notification Debug (Push-Benachrichtigungen debuggen):

Kopieren Sie das Gerätetoken und fügen Sie es in den richtigen Textbereich ein. Wählen Sie dann die richtige mobile App aus.
Gerätetoken abrufen
Ein Beispiel für einen Geräte-Token-String:
7db0bc0044c8a203ed87cdab86a597a2c43bf16d82dae70e8d560e88253364b7
Push-Benachrichtigungen werden in der Regel in der Klasse festgelegt, die dem UIApplicationDelegate- oder PKPushRegistryDelegate-Protokoll entspricht. Irgendwann ist das Geräte-Token für Sie verfügbar. Sie können es ausdrucken, bevor Sie es an das iOS SDK übergeben. Verwenden Sie das Code-Snippet, um Ihr Geräte-Token zu erhalten.
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]);
}
Ergebnis
Klicken Sie nach der Eingabe der Zertifikats-PEM-Datei und des Geräte-Tokens auf die Schaltfläche.
Wenn die Test-Push-Benachrichtigung erfolgreich zugestellt wurde, wird die Meldung Push-Benachrichtigung erfolgreich konfiguriert angezeigt.
Die Zustellung von Push-Benachrichtigungen ist nicht zu 100% garantiert und hängt von der Netzwerkverbindung des Geräts ab.
Projektkonfigurationen
In den folgenden Abschnitten werden die Änderungen beschrieben, die zum Konfigurieren des Projekts erforderlich sind.
Leistungsspektrum
Aktivieren Sie in den Zieleinstellungen die folgenden Funktionen:
Push-Benachrichtigungen
Hintergrundmodi (diese Elemente prüfen)
Audio und AirPlay
Voice over IP
Info.plist
Zum Schutz der Privatsphäre der Nutzer muss für jede iOS-App, die ab iOS 10.0 verlinkt wird und auf die Mikrofone, die Fotogalerie und die Kamera des Geräts zugreift, die Absicht dazu deklariert werden. Fügen Sie die folgenden Schlüssel mit einem Stringwert in die Info.plist-Datei Ihrer App ein und geben Sie einen Zweckstring für diesen Schlüssel an. Wenn Ihre App versucht, ohne entsprechenden Zweckstring auf die Mikrofone, die Fotogalerie und die Kamera des Geräts zuzugreifen, wird sie beendet.
NSMicrophoneUsageDescription: Ermöglicht den Zugriff auf das Mikrofon für Anrufe und Gespräche mit Support- oder Fehlerbehebungsteams sowie zum Senden von Videos mit Ton im Zusammenhang mit Produktanfragen.
NSCameraUsageDescription: Ermöglicht den Zugriff auf die Kamera, damit Kunden Fotos im Zusammenhang mit ihrer Kundensupportanfrage aufnehmen und senden können.
NSPhotoLibraryUsageDescription: Ermöglicht den Zugriff, damit Kunden Fotos im Zusammenhang mit ihrer Kundensupportanfrage senden können.
NSFaceIDUsageDescription: Ermöglicht den Zugriff auf die Überprüfung mit Face ID.
iOS SDK starten
Fügen Sie die folgende Zeile an der Stelle ein, an der Sie das iOS SDK starten möchten:
[UJET startWithOptions:nil];
Sie können das iOS SDK auch über einen Direct Access Point an einem bestimmten Punkt im Menü starten:
UJETStartOptions *option = [[UJETStartOptions alloc] initWithMenuKey:@"MENU_KEY"];
[UJET startWithOptions:option];
Die menuKey kann durch Erstellen eines Direct Access Point (DAP) erstellt werden. In den folgenden Schritten wird beschrieben, wie Sie ein Gerätezugriffsprofil erstellen:
Melden Sie sich mit Administratoranmeldedaten im CCAI Platform-Portal an.
Gehe zu Einstellungen > Warteschlange.
Wählen Sie eine beliebige Warteschlange aus der Menüstruktur aus.
Wählen Sie Direkten Zugriffspunkt erstellen aus.
Geben Sie den Schlüssel in das Textformular ein.
Klicken Sie auf Speichern.

Lokalen Cache leeren, wenn Nutzerdaten aktualisiert wurden
Wir speichern das Authentifizierungstoken im Schlüsselbund, um es wiederzuverwenden und weniger häufig Anfragen zum Signieren der Nutzlast von der Host-App zu senden. Das SDK verwendet es, bis es abläuft oder durch den Aufruf von „clearUserData“ widerrufen wird. Die Host-App ist dafür verantwortlich, diesen Cache zu widerrufen, wenn sich nutzerbezogene Daten geändert oder aktualisiert haben, z. B. bei einer Abmeldung.
[UJET clearUserData];
Vor dem Starten von Contact Center AI Platform nach einer vorhandenen Sitzung suchen
Prüfen Sie vor dem Start einer Sitzung, ob bereits eine Sitzung läuft. Das ist besonders wichtig, wenn sich die userId geändert hat.
[UJET getStatus];
Wenn eine Sitzung bereits vorhanden ist, sollten wir den Nutzer auffordern, die Sitzung fortzusetzen oder die Aktion abzubrechen:
if ([UJET getStatus] != UjetStatusNone) {
// Display alert to cancel login or resume existing session
}
Anpassen
In UJETGlobalTheme.h sind mehrere Optionen für das SDK-Design aufgeführt.
Legen Sie das Thema nach [UJET initialize] fest, z. B.:
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];

Der Unternehmensname wird aus dem Admin Portal> Einstellungen > Supportcenter-Details > Anzeigename abgerufen.
So können Sie das Logo anstelle des Unternehmensnamens festlegen:
theme.companyImage = [UIImage imageNamed:@"logo"];

Wenn das Bild zu groß ist, wird seine Größe angepasst, damit es in den Bereich passt.
Strings
Sie können Strings auch anpassen, indem Sie den Wert überschreiben. Fügen Sie beispielsweise diesen Schlüssel-Wert in Ihre Datei „Localizable.strings“ ein:
"ujet_greeting_title" = "Title";
"ujet_greeting_description" = "Description";

Die verfügbaren anpassbaren Strings sind in der Datei „ujet.strings“ aufgeführt.
Dunkler Modus
Sie können einen Farbton für den dunklen Modus festlegen, um die Lesbarkeit von Schriftarten zu verbessern.
@property (nonatomic, strong) UIColor \*tintColorForDarkMode;
Wenn Sie die Eigenschaft nicht festlegen, wird UJETGlobalTheme.tintColor für den Dark Mode verwendet. Wir empfehlen, diese Property festzulegen, wenn Ihre App den dunklen Modus unterstützt. In den folgenden Apple-Artikeln erfährst du, wie du die richtige Tönungsfarbe für den Dark Mode auswählst:
Chat-Thema
Wenn Sie den Chatbildschirm anpassen möchten, können Sie einen JSON-String oder jede Themenklasse verwenden.
Als Referenz können Sie sich die Beispiel-App ansehen und die Methode customizeChatTheme auskommentieren.
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)
}

Design von Inhaltskarten
Sie können die Anpassung von Inhaltskarten zusammen mit der Chatanpassung hinzufügen.
Sie können dies entweder über die JSON-Datei (siehe Attribut content_card) oder über die Klasse UJETChatContentCardTheme tun.
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)
}

Design der Formularübersichtskarte
Sie können die Anpassung von Formular-Karten zusammen mit der Chatanpassung hinzufügen. Verwenden Sie dazu entweder die JSON-Datei (siehe form_card property) oder die Klasse 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)
}
Webformular konfigurieren
Implementieren Sie die Methode ujetWebFormDidReceive des Protokolls UJETDelegate, um die Webformularfunktion zu konfigurieren. Diese Methode empfängt ein Ereignis (ein FormMessageReceivedEvent-Wörterbuch) als Parameter, das formularbezogene Informationen enthält. Das Ereigniswörterbuch (FormMessageReceivedEvent) enthält die folgende JSON-Struktur:
{
"type": "form_message_received",
"smart_action_id": 1,
"external_form_id": "external_foobar"
"signature": "4868a7e1dcb5..."
}
So gehen Sie mit dem Ereignis um:
Extrahieren Sie die relevanten Informationen aus dem Ereignis-Dictionary (
smart_action_id,external_form_idundsignature).Generieren Sie einen Formular-URI und eine Signatur für die Formulardaten.
Übergeben Sie die Formulardaten als
FormDataEvent-Dictionary mitcompletion closurean das SDK.Wenn bei der URI-/Signaturgenerierung ein Fehler auftritt, rufen Sie den Callback mit
callback.onError()undErrorauf.
Das an das SDK übergebene Dictionary (FormDataEvent) sollte die folgende Struktur haben:
{
"type": "form_data",
"signature": "4868a7e1dcb5...",
"data": {
"smart_action_id":1,
"external_form_id": "form_id",
"uri":"foobar"
}
}
Die Signatur (HMAC-SHA:256) muss mit dem data generiert und mit dem gemeinsamen geheimen Schlüssel signiert werden. Die Objektschlüssel von Daten müssen vor dem Generieren von Signaturen alphabetisch sortiert werden und derselbe data muss an das SDK gesendet werden.
Übertragung nach dem Training
Sie können die Anpassung für die Nachsitzungs-VA zusammen mit der Chatanpassung hinzufügen.
Dies kann entweder über die JSON-Datei (siehe Attribut post_session) oder über die Klasse UJETChatPostSessionVaTheme erfolgen. Die Rahmenlinienbreite kann nur 0 oder 1 sein. Wenn Sie die Nutzerfreundlichkeit nach der Sitzung nicht unterscheiden möchten, können Sie containerColor auf „white“ (weiß) und den Rahmen auf 0 setzen.
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)
}
Menü „Chat-Aktionen“
Sie können das Menü für Chataktionen zusammen mit der Chatanpassung anpassen. Dies kann entweder über die JSON-Datei (siehe form_card-Property) oder über die Klasse „UJETChatActionMenuTheme“ erfolgen.
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)
}
Weitere Auftritte
Sie können auch andere Aspekte wie Schriftgröße und Hintergrundfarbe anpassen.
theme.supportTitleLabelFontSize = 30;
theme.supportDescriptionLabelFontSize = 20;
theme.supportPickerViewFontSize = 30;
theme.staticFontSizeInSupportPickerView = YES;
theme.backgroundColor = UIColor.darkGrayColor;
theme.backgroundColorForDarkMode = UIColor.lightGrayColor;

CallKit
Unter iOS 10.0 und höher ist CallKit für alle Anrufe aktiviert.
Mit CallKit wird ein eingehender In-App-Anruf mit dem Anrufbildschirm angezeigt und der Anruf wird in der Anrufliste des Smartphones angezeigt.
Wenn Sie eine neue CCAI Platform-Support-Sitzung über den Anrufverlauf starten möchten, fügen Sie den folgenden Block zu Ihrer AppDelegate.m-Datei hinzu:
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;
}
Mit CallKit kann ein 40 × 40-Symbol auf dem Sperrbildschirm angezeigt werden, wenn ein Anruf eingeht, während das Gerät gesperrt ist. Fügen Sie in Ihrem Xcassets ein Bild mit dem Namen „icon-call-kit“ ein.
SDK konfigurieren
Sie können mehrere Optionen festlegen, bevor Sie das SDK starten.
Weitere Informationen finden Sie in der Klasse UJETGlobalOptions.
UJETGlobalOptions *options = [UJETGlobalOptions new];
options.fallbackPhoneNumber = @"+18001112222";
options.preferredLanguage = @"en";
[UJET setGlobalOptions:options];
Schaltfläche zum Herunterladen des Transkripts ein- oder ausblenden
Sie können das SDK so konfigurieren, dass die Schaltfläche zum Herunterladen des Transkripts im Chat-Optionsmenü und auf dem Bildschirm nach dem Chat ein- oder ausgeblendet wird.
Der folgende Code zeigt, wie die Schaltfläche zum Herunterladen des Transkripts konfiguriert wird:
typedef NS_OPTIONS(NSUInteger, UJETChatDownloadTranscriptVisibilityOptions) {
UJETChatDownloadTranscriptVisibilityOptionsShowAll = 0,
UJETChatDownloadTranscriptVisibilityOptionsHideFromOptionsMenu = 1 << 0,
UJETChatDownloadTranscriptVisibilityOptionsHideFromPostChatScreen = 1 << 1,
UJETChatDownloadTranscriptVisibilityOptionsHideAll = UJETChatDownloadTranscriptVisibilityOptionsHideFromOptionsMenu | UJETChatDownloadTranscriptVisibilityOptionsHideFromPostChatScreen
};
@property (nonatomic, assign) UJETChatDownloadTranscriptVisibilityOptions transcriptVisibilityOptions;
PSTN-Fallback
Wir bieten PSTN-Fallback für verschiedene Situationen an:
Das Mobilfunknetz ist offline.
Das Anwendungs-Backend ist nicht erreichbar.
VoIP ist nicht verfügbar
Die Netzwerkbedingungen sind nicht gut genug, um eine Verbindung herzustellen. Weitere Informationen finden Sie unter UJETGlobalOptions.pstnFallbackSensitivity.
Bei der Verbindung ist aufgrund der Firewallkonfiguration oder eines Problems mit dem Anbieter ein Fehler aufgetreten.
Wir empfehlen, die IVR-Nummer Ihres Unternehmens in UJETGlobalOptions.fallbackPhoneNumber festzulegen. Das empfohlene Format ist + gefolgt von Ländercode und Telefonnummer, z. B. +18001112222.
PSTN-Fallback-Empfindlichkeit
Sie können die Empfindlichkeitsstufe für die Prüfung des Netzwerkzustands für die PSTN-Fallback-Funktion anpassen.
@property (nonatomic, assign) float pstnFallbackSensitivity;
Der Wert muss zwischen 0,0 und 1,0 liegen. Wenn der Wert auf 1 festgelegt ist, wird die Verbindung immer über das PSTN und nicht über VoIP hergestellt. Die maximale Latenz und der Mindestbandbreitenschwellenwert betragen bei einem Wert von 0 jeweils 10.000 ms und 10 KB/s. Ein Wert von 0, 5 bedeutet beispielsweise, dass die Mindestlatenz 5.000 ms und die Mindestbandbreite 15 KB/s beträgt.
Dieser Wert kann so konfiguriert werden:
Melden Sie sich als Administrator im CCAI Platform-Portal an.
Gehen Sie zu Einstellungen > Entwicklereinstellungen > Mobile Apps.
Suchen Sie den Abschnitt Grenzwert für Ersatztelefonnummer. Der Standardwert ist 0,85.
Geben Sie den neuen Grenzwert an.
Klicken Sie auf Speichern.
Push-Benachrichtigungen global deaktivieren
Sie können Push-Benachrichtigungen global deaktivieren. Wenn Sie die folgende Eigenschaft auf false festlegen, werden alle Abhängigkeiten von Push-Benachrichtigungen umgangen und Push-Benachrichtigungen erreichen keine Endnutzer:
@property (nonatomic, assign) BOOL allowsPushNotifications;
Dunklen Modus ignorieren
Sie können den Dark Mode im CCAI Platform SDK mit dieser Property ignorieren:
@property (nonatomic, assign) BOOL ignoreDarkMode;
Statusleiste ausblenden
Mit dieser Eigenschaft können Sie die Sichtbarkeit der Statusleiste steuern:
@property (nonatomic, assign) BOOL hideStatusBar;
Standardmäßig ist hideStatusBar auf false und visible festgelegt.
Kundenzufriedenheitsumfrage überspringen
Sie können einen Button hinzufügen, über den der Nutzer die Umfrage zur Kundenzufriedenheit überspringen kann. Das folgende Codebeispiel zeigt, wie Sie die Schaltfläche hinzufügen:
let options = UJETGlobalOptions()
options.skipCsat = true
Aktivitätsanzeige anpassen
Sie können dem SDK eine eigene Ladeanimation (innerhalb eines UIView) hinzufügen und das Standard-UIActivityIndicatorView überschreiben. Implementieren Sie die Methode ujet_activityIndicator aus UJETDelegate und geben Sie die angepasste Ansicht zurück.
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
}
Wenn Sie in der Info.plist Ihrer App bereits „UIUserInterfaceStyle“ als „Light“ festgelegt haben, um den Dark Mode vollständig zu deaktivieren, können Sie diese Property ignorieren.
Ausgewählte Sprache
Das CCAI Platform SDK verwendet die folgende Prioritätsreihenfolge, um die bevorzugte Sprache zu ermitteln.
Die Sprache wird auf dem Splash-Screen in der App ausgewählt.
Standardsprache ausgewählt aus
UJETGlobalOptions. Sie können die Standardsprache mit dem AttributpreferredLanguagefestlegen. Die unterstützten Sprachcodes finden Sie in der DateiUJETGlobalOptions.h.Die auf dem Gerät ausgewählte Gerätesprache (über Einstellungen> „Allgemein“ > „Sprache & Region“) wird verwendet, sofern sie von der App unterstützt wird.
Der nächstgelegene Dialekt der Gerätesprache wird verwendet, wenn die Anwendung die Gerätesprache nicht unterstützt, aber den nächstgelegenen übergeordneten Dialekt. Wenn der Nutzer beispielsweise Spanisch (Kuba) als Sprache auf dem Gerät ausgewählt hat und die App Spanisch (Kuba) nicht, aber die übergeordnete Sprache Spanisch unterstützt, wird Spanisch verwendet.
Wenn die Gerätesprache von der App nicht unterstützt wird, wird Englisch verwendet.
Symbole für externe Umleitungslinks konfigurieren
Sie können das Symbol im Kanal für externe Weiterleitungslinks anpassen, indem Sie ein Symbol in den Asset-Katalog Ihrer App hochladen. Achten Sie darauf, dass Sie beim Erstellen eines externen Weiterleitungslinks im Admin-Portal unter „Einstellungen“ > „Chat“ > „Externe Weiterleitungslinks“ > „Links ansehen“ > „Weiterleitungslink hinzufügen“ denselben Symbolnamen verwenden. Wenn der Symbolname im Admin-Portal nicht mit dem in die App hochgeladenen Symbol übereinstimmt, verwendet das SDK das Standardsymbol. Hier finden Sie Informationen zum Hinzufügen von Bildern zum Asset-Katalog.



Fallback
Sie können die Funktion didHandleUjetError für den Fallback unerwarteter Fehler verwenden. Wenn Sie diese Funktion nicht verwenden oder sie false zurückgibt, wird der Fehler vom iOS SDK verarbeitet.
In der folgenden Tabelle sind die Fehler aufgeführt, auf die die Funktion didHandleUjetError reagiert:
| Fehlertyp | Fehlercode | Beschreibung |
|---|---|---|
networkError |
1 | Das Netzwerk ist nicht verfügbar. Hinweis:Dieser Fehler wird nicht ausgelöst, wenn das Netzwerk während einer Chat- oder Anrufsitzung oder auf einem Bildschirm zur Ratenbegrenzung nicht verfügbar ist. |
authenticationError |
100 | Bei der Authentifizierung ist ein unerwarteter Fehler aufgetreten. |
authenticationJwtError |
101 | Bei der JWT-Validierung ist ein unerwarteter Fehler aufgetreten, z. B. ein Parsing-Fehler. |
voipConnectionError |
1000 | Es konnte keine Verbindung zum VoIP-Anbieter hergestellt werden. Dies wird durch einen VoIP-SDK-Callback behandelt. |
voipLibraryNotFound |
1001 | Das System erwartet, dass eine Verbindung über einen VoIP-Anbieter hergestellt wird, kann aber keinen finden. Das kann passieren, wenn Sie das falsche SDK einbinden oder Ihren Abhängigkeiten keine VoIP-Anbieterbibliothek hinzufügen. |
chatLibraryNotFound |
1.100 | Tritt auf, wenn das System die Chat-Bibliothek nicht finden kann. Dies kann passieren, wenn Sie das falsche SDK einbinden oder Ihren Abhängigkeiten keine Twilio-Chatbibliothek hinzufügen. |
Das folgende Codebeispiel zeigt, wie die Funktion didHandleUjetError verwendet wird:
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
}
}
Benutzerdefinierte Daten an Ihr CRM senden
Sie können benutzerdefinierte Daten an das CRM-Ticket senden.
Es gibt zwei Methoden zum Senden benutzerdefinierter Daten:
Sichere Methode: Vordefinierte Datensignierung mit JWT.
Nicht sichere Methode: vordefinierte Daten mit einfachem JSON (nicht empfohlen).
Benutzerdefinierte Daten mit der sicheren Methode senden
Sie müssen die Signiermethode implementieren. Zuerst können Sie Ihre benutzerdefinierten Daten auf der Clientseite platzieren und zum Signieren an Ihren Server senden. Auf Ihrem Server können Sie zusätzliche Daten in einem definierten Formular hinzufügen, mit Ihrem „company.secret“ signieren und per JWT zurückgeben.
- (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];
}
}
Benutzerdefinierte Daten mit einer unsicheren Methode senden
Diese Methode wird nicht empfohlen, da sie eine potenzielle Sicherheitslücke schafft, die Ihre Anwendung für Man-in-the-Middle-Angriffe anfällig machen könnte. Wenn Sie sich für diese Methode entscheiden, sind wir nicht für die Sicherheitsrisiken und potenziellen Schäden verantwortlich, die dadurch entstehen können. Wir empfehlen Ihnen, die oben beschriebene sichere Methode zum Senden benutzerdefinierter Daten in Ihrer Anwendung zu verwenden. Alternativ können Sie das iOS SDK auch nur mit der UJETCustomData-Instanz starten. In diesem Fall sollte der signPayload-Delegate für UJETPayloadCustomData einfach success(nil); aufrufen.
- (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];
Nicht signierte benutzerdefinierte Daten zum Senden eines externen Chat-Transkripts verwenden
Sie können das Chat-Transkript an das SDK senden, wenn es mit nicht signierten benutzerdefinierten Daten gestartet wird. Rufen Sie dazu die Methode „setExternalChatTransfer:“ oder „setExternalChatTransferWithDictionary:“ auf, um JSON-Daten mit NSString bzw. NSDictionary festzulegen.
UJETCustomData *customData = [UJETCustomData new];
[customData setExternalChatTransfer:jsonString];
UJETStartOptions *options = [UJETStartOptions new];
options.unsignedCustomData = customData;
[UJET startWithOptions:options];
JSON-Format:
greeting_override: string
agent: dictionary
name: string
avatar: string [URL des Agent-Avatars, optional]
transcript: array
sender: string ["end_user" or "agent"]
Zeitstempel: String [z. B. „2021-03-15 12:00:00Z“]
content: array
Typ: String [einer von „text“, „media“]
text: string [für Texttyp erforderlich]
media: dictionary [für Medientyp erforderlich]
type: string [one of image, video]
url: string [öffentliche URL, die auf die Mediendatei verweist]
JSON-Beispiel:
{
"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"
}
]
}
]
}
Sie können Markdown für den Texttyp verwenden. Die unterstützte Syntax umfasst kursiv, fett, Aufzählungsliste, Hyperlink und unterstrichen (--text--).
Beispiel für benutzerdefinierte Daten { :#example-of-custom-data }
JSON-Codierung in JWT
Die JSON-Datei sollte das JWT validieren. Das Objekt der benutzerdefinierten Daten ist der Wert des Schlüssels „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"
}
}
}
Jeder Datensatz ähnelt dem JSON-Objektformat und sollte den Schlüssel, den Wert, den Typ und das Label enthalten.
Der Schlüssel ist die eindeutige Kennung für die Daten. Das Label ist der Anzeigename auf der CRM-Seite. Der Typ ist der Typ des Werts.
String
- JSON-String
Zahl
- Ganzzahl, Gleitkommazahl
Datum
- UTC-Unix-Zeitstempelformat mit 13 Ziffern. (enthält Millisekunden)
URL
- HTTP-URL-Format
CRM-Beispiel

Standort
CoreLocation-Framework verwenden Weitere Informationen finden Sie unter AppDelegate.m.
Betriebssystemversion des Geräts
[customData set:@"os_version" label:@"OS Version" stringValue:[[UIDevice currentDevice] systemVersion]];
Anzeige benutzerdefinierter Daten verhindern
Sie können die Eigenschaft invisible_to_agent mit einem benutzerdefinierten Datenobjekt verwenden, um zu verhindern, dass signierte oder nicht signierte benutzerdefinierte Daten im Agent-Adapter angezeigt werden. Im vorherigen Beispiel wird die Sozialversicherungsnummer des Endnutzers nicht im Agent-Adapter angezeigt, da "invisible_to_agent" : true im Objekt ssn enthalten ist.
Wenn Sie die Property "invisible_to_agent" : true in ein benutzerdefiniertes Datenobjekt einfügen, können Sie mit dem folgenden Verhalten rechnen:
- Die benutzerdefinierten Daten sind in der Datei mit Sitzungsmetadaten enthalten.
- Die benutzerdefinierten Daten sind nicht in CRM-Datensätzen enthalten.
Weitere Informationen finden Sie unter Sitzungsdaten im Agent-Adapter ansehen.
Reservierte Daten-Properties
Sie können reservierte Dateneigenschaften als signierte benutzerdefinierte Daten an die Contact Center AI Platform (CCAI Platform) senden, wenn eine Sitzung beginnt. Weitere Informationen finden Sie unter Reservierte Datenattribute senden.
Im Folgenden finden Sie ein Beispiel für reservierte Datenattribute in benutzerdefinierten Daten:
{
"custom_data": {
"reserved_verified_customer": {
"label": "Verified Customer",
"value": "VERIFIED_CUSTOMER_BOOLEAN": ,
"type": "boolean"
},
"reserved_bad_actor": {
"label": "Bad Actor",
"value": "VERIFIED_BAD_ACTOR_BOOLEAN": ,
"type": "boolean"
},
"reserved_repeat_customer": {
"label": "Repeat Customer",
"value": "REPEAT_CUSTOMER_BOOLEAN": ,
"type": "boolean"
}
}
}
Ersetzen Sie Folgendes:
VERIFIED_CUSTOMER_BOOLEAN: „True“, wenn Sie diesen Endnutzer als legitimen Kunden betrachten.VERIFIED_BAD_ACTOR_BOOLEAN: „True“, wenn Sie diesen Endnutzer als potenziell böswilligen Akteur betrachten.REPEAT_CUSTOMER_BOOLEAN: „True“, wenn Sie festgestellt haben, dass dieser Endnutzer Ihr Contact Center bereits kontaktiert hat.
Flow anpassen
CCAI Platform für die Verarbeitung von Host-App-Ereignissen trennen
// CCAI Platform is connected
...
// An event has come
[UJET disconnect:^{
// Handle an event
}];
Eingehenden CCAI Platform-Anruf oder ‑Chat verschieben
Delegatenmethode zum Verarbeiten eingehender Ereignisse implementieren
- (BOOL)shouldConnectUjetIncoming:(NSString *)identifier forType:(UjetIncomingType)type {
if (weDoingSomething) {
// save identifier and type
return NO; // postpone
} else {
return YES;
}
}
Verschobenes Event verbinden
[UJET connect:identifier forType:UjetIncomingTypeCall];
Deeplink einrichten
So können Kundenservicemitarbeiter bei PSTN-Anrufen Smart Actions per SMS verwenden, unabhängig davon, ob der Endnutzer die App hat oder nicht.
Gehen Sie im CCAI Platform-Portal zu Einstellungen > Betriebsmanagement > SMS zum Herunterladen der App senden aktivieren.
Sie können die App-URL mit Ihrer Webseite festlegen (z. B. https://your-company.com/support), nachdem Sie Universal Link oder benutzerdefiniertes URL-Schema konfiguriert haben. Sie können eine der beiden Optionen auswählen.
Delegatenmethode zum Verarbeiten von Deeplinks implementieren
Der universelle Link und die benutzerdefinierte URL sehen so aus:
https://your-company.com/support?call_id=x&nonce=y und
your-company://support?call_id=x&nonce=y. Fügen Sie im Admin-Portal unter „App-URL“ einen Ihrer Links ohne Suchparameter ein. Geben Sie beispielsweise your-company://support ein, wenn Sie ein benutzerdefiniertes URL-Schema verwenden.
Achten Sie darauf, in der Delegatenmethode [UJET start] nur dann aufzurufen, wenn die URL-Pfade und Parameter im universellen Link oder in der benutzerdefinierten URL spezifisch für die CCAI-Plattform sind.
- (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];
}
...
}
Wenn Ihre App UIWindowSceneDelegate verwendet, fügen Sie dieses Code-Snippet hinzu:
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: [:])
}
}
Weitere Informationen finden Sie im Beispielcode in der Datei UJETObject+DeepLink.
CCAI Platform-Ereignis beobachten
Wir senden die folgenden Ereignisse über NSNotificationCenter.defaultCenter. Sie können sie anhören und Ihren Ablauf je nach Anwendungsfall anpassen, z.B. ein benutzerdefiniertes Tastaturlayout.
UJETEventEmailDidClick
- Daten zum Warteschlangenmenü
UJETEventEmailDidSubmit
Daten zum Warteschlangenmenü
has_attachment: (NSNumber) @YES, @NO
UJETEventSessionViewDidAppear
type: @"call", @"chat"
timestamp: (NSString) ISO 8601
UJETEventSessionViewDidDisappear
type: @"call", @"chat"
timestamp: (NSString) ISO 8601
UJETEventSessionDidCreate
- Sitzungsdaten
UJETEventSessionDidEnd
Sitzungsdaten
agent_name: (NSString) null, wenn der Kundenservicemitarbeiter nicht beigetreten ist
duration: (NSNumber) nur für Anrufe
ended_by: (NSString)
type=call: @"agent", @"end_user"
type=chat: @"agent", @"end_user", @"timeout", @"dismissed"
UJETEventSdkDidTerminate
UJETEventPostSessionOptInDidSelected
- opt_in_selected: (NSString) @"Yes", @"No"
Ereignisdaten
Metadaten
application: @"iOS"
app_id: (NSString) Paket-ID
app_version: (NSString)
company: (NSString) subdomain
device_model: (NSString)
device_version: (NSString)
sdk_version: (NSString)
timestamp: (NSString) ISO 8601
Wiedergabelistendaten
Metadaten
menu_id: NSString
menu_key: NSString, nullable
menu_name: NSString
menu_path : NSString
Sitzungsdaten
Daten zum Warteschlangenmenü
session_id: NSString
type: @"call", @"chat"
end_user_identifier: NSString
Bildschirmfreigabe einrichten
Wenn Sie die Bildschirmfreigabe verwenden möchten, müssen Sie UJETCobrowseKit.xcframework einbinden.
CocoaPods:Fügen Sie Ihrem App-Ziel das folgende Subspec hinzu.
ruby
target 'MyApp' do
pod 'UJET'
pod 'UJET/Cobrowse'
end
Carthage:Fügen Sie dem Cartfile die folgende Zeile hinzu:
binary "https://sdk.ujet.co/ios/UJETKit.json"
SwiftPM:Wählen Sie UJET- und UJETCobrowse-Produkte aus und fügen Sie sie Ihrem App-Ziel hinzu.
Legen Sie das Attribut UJETGlobalOptions.cobrowseKey fest.
swift
let options = UJETGlobal
Options()options.cobrowseKey = cobrowseKey
UJET.setGlobalOptions(options)
Bildschirmfreigabe für das gesamte Gerät (optional)
Mit der Bildschirmfreigabe für das gesamte Gerät können Ihre Kundenservicemitarbeiter Bildschirme von Anwendungen außerhalb Ihrer eigenen sehen. Das ist oft nützlich, wenn Supportmitarbeiter den Status von Systemeinstellungen prüfen oder sehen müssen, wie der Nutzer zwischen mehreren Anwendungen wechselt. Wenn Sie diese Funktion nicht nutzen möchten, können Sie diesen Abschnitt überspringen.
Einwilligungsdialog für die Bildschirmfreigabe anpassen
Wenn Sie das Dialogfeld zur Einwilligung für die Bildschirmfreigabe anpassen möchten, müssen Sie das UJETCobrowseAlertProvider-Protokoll in Ihrer Anbieterklasse implementieren. Geben Sie in dieser Implementierung ein benutzerdefiniertes UIViewController oder ein anderes Objekt zurück, das UIViewController über die entsprechende Protokollmethode erbt. UIViewController
sollte zwei Schaltflächen haben: eine zum Annehmen und eine zum Ablehnen.
Nachdem Sie die Einwilligung eingeholt haben, übergeben Sie sie an unser SDK, indem Sie den Abschluss consentStatus aufrufen. UIViewController von cobrowseFullDeviceRequestAlert. Der Delegate sollte RPSystemBroadcastPickerView mit Titel (siehe Beispielcode unten) und einen weiteren Ablehnen-Button enthalten. Rufen Sie den geschlossenen Bereich auf, wenn auf die Schaltfläche „Ablehnen“ geklickt wird.
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
}
}
Der benutzerdefinierte View-Controller sollte einen Closure haben, um den Einwilligungsstatus an das SDK zu übergeben.
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)
}
}
}
Der benutzerdefinierte View-Controller für die Benachrichtigung über die Anfrage für das gesamte Gerät sollte RPSystemBroadcastPickerView und einen Closure haben, um den dismiss-Status an das SDK zu übergeben.
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?()
}
}
}
Vergessen Sie nicht, diesen Anbieter über die folgende API an unser SDK zu übergeben:
let provider = CobrowseAlertProvider()
UJET.setCobrowseAlertProvider(provider)
Broadcast-Erweiterung
Für die Funktion muss eine Broadcast-Erweiterung hinzugefügt werden.
Öffnen Sie Ihr Xcode-Projekt.
Klicken Sie auf Datei > Ziel.
Wähle Broadcast Upload Extension (Erweiterung zum Hochladen von Übertragungen) aus.
Geben Sie einen Namen für das Ziel ein.
Deaktivieren Sie UI-Erweiterung einbeziehen.
Erstellen Sie das Ziel und notieren Sie sich die Bundle-ID.
Ändere das Ziel-SDK deiner Broadcast Extension zu iOS 12.0 oder höher.
SDK einbinden
CocoaPods:Fügen Sie Ihrem Erweiterungsziel das folgende Subspec hinzu:
target 'MyApp' do
pod 'UJET'
pod 'UJET/Cobrowse'
end
target 'MyAppExtension' do
pod 'UJET/CobrowseExtension'
end
Wenn Sie SwiftPM verwenden, wählen Sie das UJETCobrowseExtension-Produkt aus und fügen Sie es Ihrem Erweiterungsziel hinzu.
Schlüsselbundfreigabe einrichten
Ihre App und die zuvor erstellte App-Erweiterung müssen einige Secrets über den iOS-Schlüsselbund gemeinsam nutzen. Dazu verwenden sie ihre eigene Schlüsselbundgruppe, sodass sie vom Schlüsselbund der anderen Apps isoliert sind.
Fügen Sie sowohl Ihrem App-Ziel als auch Ihrem Erweiterungsziel eine Keychain-Sharing-Berechtigung für die io.cobrowse-Keychain-Gruppe hinzu.
Bundle-ID zur plist-Datei hinzufügen
Nehmen Sie die Bundle-ID der zuvor erstellten Erweiterung und fügen Sie den folgenden Eintrag in die Info.plist-Datei Ihrer App ein (nicht in die Info.plist-Datei der Erweiterung). Ersetzen Sie die folgende Bundle-ID durch Ihre eigene:
xml
<key>CBIOBroadcastExtension</key>
<string>your.app.extension.bundle.ID.here</string>
Erweiterung implementieren
Xcode hat die Dateien SampleHandler.m und SampleHandler.h (oder SampleHander.swift) als Teil des zuvor erstellten Ziels hinzugefügt. Ersetzen Sie den Inhalt der Dateien durch Folgendes:
Swift:Wählen Sie das UJETCobrowseExtension-Produkt aus und fügen Sie es dem Erweiterungsziel hinzu:
import CobrowseIOAppExtension
class SampleHandler: CobrowseIOReplayKitExtension {
}
ObjC
objc// SampleHandler.h
@import CobrowseIOAppExtension;
@interface SampleHandler : CobrowseIOReplayKitExtension
@end// SampleHandler.m
#import "SampleHandler.h"
@implementation SampleHandler
@end
Anwendung erstellen und ausführen
Sie können Ihre App jetzt erstellen und ausführen. Die vollständige Gerätefunktion ist nur auf physischen Geräten verfügbar und funktioniert nicht im iOS-Simulator.
SDK minimieren
Das Contact Center AI Platform SDK kann minimiert werden, wenn eine Chatsitzung oder ein Anruf läuft. Das kann nützlich sein, wenn Sie den Nutzer nach dem Empfang eines SDK-Ereignisses, z. B. nach dem Klicken auf eine Inhaltskarte, zurück zu Ihrer App leiten möchten. Um das SDK zu minimieren und Nutzer zurück zu Ihrer App zu leiten, können Sie Folgendes verwenden:
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
}
Fehlerbehebung
Ablehnung der App-Einreichung
Die App-Einreichung wird abgelehnt, weil das CallKit-Framework in China enthalten ist.
Wenn Ihre App aus diesem Grund von Apple abgelehnt wird, hinterlassen Sie einfach einen Kommentar, da das System so konzipiert ist, dass das CallKit-Framework für die Region China bei VoIP-Anrufen deaktiviert wird. Dies gilt ab SDK-Version 0.31.1.
SDK ist zu groß
Wenn die SDK-Größe zu groß ist und sich auf GitHub nur schwer nachvollziehen lässt
In diesem Artikel werden zwei Optionen angeboten. Es wird empfohlen, Git LFS zu verwenden.
Wenn Sie Bitcode nicht verwenden, kann das Entfernen von Bitcode aus dem Binärcode eine weitere Option sein. Führen Sie diesen Befehl im Ordner „UJETKit.xcframework“ aus.
xcrun bitcode_strip -r UJET -o UJET
dyld: Library not loaded-Fehler
Fügen Sie @executable_path/Frameworks in den Runpath Search Paths (Suchpfade für Runpath) unter Target > Build Settings > Linking (Ziel > Build-Einstellungen > Verknüpfen) hinzu.
App-Einreichung in iTunes Connect
Apple stellt möglicherweise die folgende Frage während des Überprüfungsprozesses, weil der Voice over IP-Hintergrundmodus aktiviert ist:
Können Nutzer VoIP-Anrufe in Ihrer App empfangen?
Beantworten Sie die Frage mit Ja.
Die Benachrichtigung ist beim Starten des SDK nicht verfügbar.
Prüfen Sie Folgendes:
Verwenden Sie ein echtes Gerät und keinen Simulator.
Aktivieren Sie Push-Benachrichtigungen und Hintergrundmodi > VoIP-Funktion.
Wenn das nicht hilft, versuchen Sie, mit einem Bereitstellungsprofil für die Verteilung (Ad-hoc oder Apple Store) zu entwickeln.
Push-Benachrichtigung mit Ihrer Test-App testen
VoIP-Zertifikat und Geräte-Token des Geräts vorbereiten
Sehen Sie im CCAI Platform-Portal im Menü Einstellungen > Entwicklereinstellungen im Abschnitt Push-Benachrichtigungen debuggen nach.
Wenn Sie das Zertifikat für APNS bereits festgelegt haben, müssen Sie es nicht noch einmal eingeben.
Geben Sie Ihr Zertifikat ein (optional) und prüfen Sie, ob es sich um eine Sandbox handelt (optional). Geben Sie dann das Geräte-Token für Push-Benachrichtigungen Ihrer Test-App ein.
Das Starten eines neuen Chats hat länger als 30 Sekunden gedauert
Prüfen Sie, ob Sie auf eine Delegatenmethode benutzerdefinierter Daten reagieren. Sie sollten bei einer Anfrage gültige benutzerdefinierte Daten zurückgeben oder einfach „nil“ im Erfolgsblock zurückgeben.
Verwenden Sie dieses Code-Snippet als Beispielkonfiguration:
public func signPayload(_ payload: [AnyHashable: Any]?, payloadType: UjetPayloadType, success: (String?) -> Void, failure: (Error?) -> Void)
{
if payloadType == .customData {
success(nil)
}
}