iOS SDK-Leitfaden

Das mobile SDK der 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

  1. Melden Sie sich mit Administratoranmeldedaten im Portal der Contact Center AI Platform (CCAI Platform) an.

  2. Gehen Sie zu Einstellungen > Entwicklereinstellungen.

  3. Notieren Sie sich unter Unternehmensschlüssel und Geheimer Code den Unternehmensschlüssel und den geheimen Code des Unternehmens.

Erste Schritte

Im Folgenden finden Sie eine Anleitung für die ersten Schritte mit dem CCAI Platform iOS Mobile SDK.

Installation

Zuerst müssen Sie das iOS SDK installieren.

Beispielanwendung herunterladen

  1. Laden Sie die iOS-Beispiel-App herunter.

  2. Rufen Sie den Ordner auf und installieren Sie die Abhängigkeiten mit CocoaPods:

    $ pod install --project-directory=ExampleApp
    
  3. Führen Sie ein Shell-Skript aus, um die Projekteinstellungen schnell zu konfigurieren:

    $ ./setup.sh
    

    Alternativ können Sie die Projekteinstellungen manuell bearbeiten. Gehen Sie dazu so vor:

    1. Öffnen Sie ExampleApp.xcworkspace.

    2. Ersetzen Sie die Werte UJETCompanyKey und UJETCompanySecret in Info.plist durch die Werte für Company Key und Company Secret Code von der Seite Settings > Developer Settings im CCAI Platform-Portal.

    3. Ersetzen Sie den Wert UJETSubdomain in Info.plist durch die Subdomain in der URL für Ihr CCAI Platform-Portal. Die Subdomain steht in der URL direkt vor .ujet.com, z. B. your-subdomain in https://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

  1. Fügen Sie das Swift-Paket für das iOS SDK von GitHub hinzu.

  2. Fügen Sie in den Build-Einstellungen „-ObjC“ zu „Other Linker Flags“ hinzu.

  3. Seit Xcode 13.2 gibt es ein bekanntes Problem bei der Verwendung 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 Skriptausführungsphase sollte nach der Build-Phase „Embed Frameworks“ erfolgen. Diese neue Run Script Phase 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

  1. Fügen Sie der Podfile-Datei die folgende Zeile hinzu:

    pod 'UJET', :podspec =>
    'https://sdk.ujet.co/ios/x.y.z/ujet.podspec' #specific version
    x.y.z
    
  2. Führen Sie „pod install“ aus. Wenn das iOS SDK bereits eingebunden wurde, führen Sie stattdessen „pod update CCAI Platform“ aus.

Carthage

Google Cloud empfiehlt die Verwendung eines Abhängigkeitsmanagers oder die manuelle Integration, da eine CCAI Platform-Abhängigkeit Carthage nicht unterstützt.

So verwenden Sie einen anderen Abhängigkeitsmanager:

  1. Fügen Sie die folgenden Zeilen hinzu:

    binary "https://sdk.ujet.co/ios/UJETKit.json"
    binary "https://sdk.ujet.co/ios/UJETFoundationKit.json"
    binary "https://sdk.ujet.co/ios/UJETCallRedKit.json"
    binary "https://sdk.ujet.co/ios/UJETChatRedKit.json"
    # optional
    # binary "https://sdk.ujet.co/ios/UJETChatBlueKit.json"
    binary "https://raw.githubusercontent.com/twilio/twilio-voice-ios/Releases/twilio-voice-ios.json"
    # this is not supported: https://github.com/twilio/conversations-ios/issues/12
    # binary "https://raw.githubusercontent.com/twilio/conversations-ios/master/twilio-convo-ios.json"
    
  2. Führen Sie carthage bootstrap --use-xcframeworks aus (oder carthage update --use-xcframeworks, wenn Sie Abhängigkeiten aktualisieren).

Manuelle Integration
  1. Laden Sie UJETKit.xcframework, UJETFoundationKit.xcframework, UJETChatRedKit.xcframework, UJETChatBlueKit.xcframework, UJETTwilioCallKit.xcframework und alle Abhängigkeiten TwilioVoice.xcframework und TwilioConversationsClient.xcframework herunter.

  2. Fügen Sie das UJETKit.xcframework Ihrem Ziel hinzu, indem Sie es in den Bereich „Frameworks, Libraries, and Embedded Content“ ziehen.

  3. Wiederholen Sie die Schritte 2 und 3 für alle Abhängigkeiten aus Schritt 1.

  4. Setzen Sie in den Build-Einstellungen -ObjC auf Other Linker Flags.

  5. Fügen Sie libc++.tbd als Abhängigkeit im Abschnitt Linked Frameworks des Ziels hinzu.

Wenn Sie das SDK manuell mit dem Beispielprojekt erstellen möchten, führen Sie die Schritte im folgenden Abschnitt aus.

SDK manuell mit dem Beispielprojekt erstellen

Gehen Sie so vor:

  1. Laden Sie alle Frameworks herunter, einschließlich UJETKit.xcframework und anderer Abhängigkeiten.

  2. Erstellen Sie im Stammverzeichnis des Projekts den Ordner „CCAI Platform“ und extrahieren Sie alle Frameworks.

  3. Wählen Sie das Ziel Objc-Manual oder Swift-Manual aus und erstellen Sie den Build.

Framework importieren

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

Greifen Sie über die iOS-App auf das iOS SDK zu.

Um sicherzustellen, dass der Endnutzer authentifiziert ist, führen wir den JWT-Signaturmechanismus ein.

Das iOS SDK fordert Sie auf, die Nutzlast zu signieren, wenn eine Authentifizierung erforderlich ist. Wenn die Signierung erfolgreich ist, tauscht die Anwendung das signierte JWT gegen das Authentifizierungstoken des Endnutzers aus. Der Erfolgs- oder Fehlerblock muss aufgerufen werden, bevor der Delegate zurückgegeben wird.

Für anonyme Nutzer (Kennung = nil) erstellt die Anwendung eine UUID. Wenn der Nutzer zu einem späteren Zeitpunkt 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 die Delegatmethode signPayload: payloadType: success: failure:.

-   (void)signPayload:(NSDictionary *)payload payloadType:(UjetPayloadType)payloadType success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
  if (payloadType == UjetPayloadAuthToken) {
    [self signAuthTokenInLocal:payload success:success failure:failure];
  }
}

-   (void)signAuthTokenInLocal:(NSDictionary *)payload success:(void (^)(NSString *))success failure:(void (^)(NSError *))failure {
    NSMutableDictionary *payloadData = [payload mutableCopy];

    NSDictionary *userData = [[NSUserDefaults standardUserDefaults] objectForKey:@"user-data"];
    [payloadData addEntriesFromDictionary:userData];
    payloadData[@"iat"] = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]]; // required
    payloadData[@"exp"] = [NSNumber numberWithDouble:([[NSDate date] timeIntervalSince1970] + 600)]; // required

    NSString *signedToken = [self encodeJWT:payloadData];

    if (signedToken.length > 0) {
        success(signedToken);

    } else {
        NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Failed to sign token" };
        NSError *error = [NSError errorWithDomain:@"ExampleApp" code:0 userInfo:userInfo];
        failure(error);
    }
}

-   (NSString *)encodeJWT:(NSDictionary *)payload {
    id<JWTAlgorithm> algorithm = [JWTAlgorithmHSBase algorithm384];
    NSString *secret = NSBundle.mainBundle.infoDictionary[@"UJETCompanySecret"];
    return [JWTBuilder encodePayload:payload].secret().algorithm(algorithm).encode;
}

Wir empfehlen dringend, die Nutzlast auf dem Anwendungsserver und nicht auf dem Client zu signieren.

In diesem Beispiel wird zu Testzwecken die lokale Signierung verwendet. Siehe signDataInRemote: success: failure: in der Datei UJETObject.m.

Weitere Informationen finden Sie unter SDK-Endnutzerauthentifizierung.

Push-Benachrichtigungen einrichten

Die CCAI Platform sendet Push-Benachrichtigungen, um intelligente Aktionen wie die Bestätigung und das Senden von Fotos anzufordern und einen eingehenden Anruf zu melden. Wenn Ihre Chat-Warteschlangen die Funktion „Einchecken“ verwenden (erfordert iOS SDK 2.16.0 oder höher), sendet die CCAI Platform eine Push-Benachrichtigung, in der wartende Kunden aufgefordert werden, zum Chat zurückzukehren und zu bestätigen, dass sie bereit sind. Weitere Informationen finden Sie unter Check-in für Mobile SDK. Für die CCAI Platform müssen zwei verschiedene Arten von Zertifikaten (VoIP und APNs) im CCAI Platform-Admin-Portal gespeichert werden.

Zertifikate konfigurieren

Für die CCAI Platform müssen zwei verschiedene Arten von Apple-Push-Zertifikaten im CCAI Platform-Admin-Portal gespeichert werden:

  • Ein SSL-Zertifikat für den Apple Push Notification Service (APNs) – wird für standardmäßige Remote-Push-Benachrichtigungen verwendet.

  • Ein VoIP-Dienstzertifikat, das für Benachrichtigungen über eingehende Anrufe und bestimmte anrufbezogene intelligente Aktionen verwendet wird.

Beide Zertifikate werden im Apple-Entwicklerportal erstellt, in das PEM-Format konvertiert und dann in das CCAI Platform-Admin-Portal hochgeladen.

APNs-SSL-Zertifikat erstellen

Folgen Sie den nächsten Schritten, die auf der offiziellen Apple-Anleitung Zertifikatbasierte Verbindung zu APNs herstellen basieren, um ein APNs-SSL-Zertifikat zu erstellen.

  • Melden Sie sich unter developer.apple.com an und rufen Sie Certificates, identifiers & profiles (Zertifikate, Kennungen und Profile) auf.

  • Klicken Sie auf das Pluszeichen, um ein neues Zertifikat zu erstellen.

  • Wählen Sie unter Services (Dienste) die Option Apple push notification service SSL (Sandbox & production) (SSL für Apple Push Notification Service (Sandbox und Produktion)) aus.

  • Wählen Sie die App-ID aus, die mit dem Paket-Identifikator Ihrer Anwendung übereinstimmt, und klicken Sie dann auf Weiter.

  • Laden Sie eine Anfrage zur Zertifikatssignierung (Certificate Signing Request, CSR) hoch, die über den Schlüsselbund auf Ihrem Mac generiert wurde:

    • Öffnen Sie Schlüsselbundverwaltung > Zertifikatsassistent > Zertifikat von einer Zertifizierungsstelle anfordern.

    • Geben Sie Ihre E-Mail-Adresse ein, lassen Sie CA-E-Mail-Adresse leer, wählen Sie Auf Laufwerk gespeichert aus und klicken Sie auf Weiter.

  • Klicken Sie auf Weiter und dann auf Generierte .cer-Datei herunterladen.

  • Doppelklicken Sie auf die Datei .cer, um sie in Ihrem Schlüsselbund zu installieren.

  • Suchen Sie unter Schlüsselbundverwaltung das installierte Zertifikat, rechtsklicken Sie darauf und wählen Sie Exportieren… aus, um es als .p12-Datei zu speichern. Sie werden aufgefordert, ein Exportpasswort festzulegen.

  • Konvertieren Sie die .p12-Datei mit openssl in das PEM-Format:

# 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

VoIP-Dienstzertifikat erstellen

Mit VoIP-Dienstzertifikaten kann Ihre App Push-Benachrichtigungen mit hoher Priorität über das PushKit-Framework von Apple empfangen. Dadurch kann Ihre App aus einem beendeten Zustand aktiviert werden, um eingehende Anrufe zu verarbeiten. Die neuesten offiziellen Schritte finden Sie in der Apple-Entwicklerdokumentation unter VoIP-Dienstzertifikate erstellen.

  • Melden Sie sich unter developer.apple.com an und rufen Sie „Certificates, Identifiers & Profiles“ (Zertifikate, Kennungen und Profile) auf.

  • Klicken Sie auf das Pluszeichen, um ein neues Zertifikat zu erstellen.

  • Wählen Sie unter Dienste die Option VoIP-Dienstzertifikat aus.

  • Wählen Sie die App-ID aus, die mit dem Paket-Identifikator Ihrer Anwendung übereinstimmt, und klicken Sie dann auf Weiter.

  • Laden Sie dieselbe Anfrage zur Zertifikatssignierung (Certificate Signing Request, CSR) hoch, die Sie im vorherigen Abschnitt generiert haben, oder erstellen Sie eine neue.

  • Klicken Sie auf Weiter und dann auf Generierte .cer-Datei herunterladen.

  • Doppelklicken Sie auf die Datei .cer, um sie in Ihrem Schlüsselbund zu installieren.

  • Suchen Sie im Schlüsselbund das installierte VoIP-Dienstzertifikat, rechtsklicken Sie darauf und wählen Sie Exportieren… aus, um es als .p12-Datei zu speichern.

  • Konvertieren Sie die .p12-Datei mit openssl in das PEM-Format:

# 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

Zertifikate in das CCAI Platform-Admin-Portal hochladen

  • Melden Sie sich im CCAI Platform-Admin-Portal an.

  • Gehen Sie zu Einstellungen > Entwicklereinstellungen > Mobile App.

  • Laden Sie das APNs-PEM-Zertifikat hoch.

  • Laden Sie das VoIP-PEM-Zertifikat hoch.

Push-Benachrichtigungen aktivieren

  1. Wählen Sie Ihr Ziel aus und öffnen Sie den Tab Capabilities (Funktionen).

  2. Aktiviere den Schalter für Push-Benachrichtigungen.

Push-Benachrichtigungen testen

In den folgenden Abschnitten wird beschrieben, wie Sie die Push-Benachrichtigungen testen können.

Bereich zur Fehlerbehebung bei Push-Benachrichtigungen

Rufen Sie im Administratorportal Einstellungen > Entwicklereinstellungen auf. Suchen Sie auf dieser Seite nach dem Abschnitt Push notification debug (Push-Benachrichtigungen debuggen):

Kopieren Sie das Geräte-Token und fügen Sie es in das rechte Textfeld 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 normalerweise in der Klasse festgelegt, die dem Protokoll „UIApplicationDelegate“ oder „PKPushRegistryDelegate“ entspricht. Irgendwann ist das Geräte-Token für Sie verfügbar. Sie können ihn ausdrucken, bevor Sie ihn an das iOS SDK übergeben. Verwenden Sie das Code-Snippet, um Ihr Geräte-Token abzurufen.

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

Nachdem Sie die PEM-Datei des Zertifikats und das Geräte-Token eingegeben haben, klicken Sie auf den Button.

Wenn die Test-Push-Benachrichtigung erfolgreich zugestellt wurde, wird die Meldung Push-Benachrichtigung erfolgreich konfiguriert angezeigt.

Die Zustellung einer Push-Benachrichtigung ist nicht garantiert, da sie von der Netzwerkverbindung des Geräts abhängt.

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 (prüfen Sie diese Elemente)

  • Audio und AirPlay

  • Voice over IP

Info.plist

Zum Schutz der Privatsphäre der Nutzer muss jede iOS-App, die mit iOS 10.0 oder höher verknüpft ist und auf die Mikrofone, die Fotogalerie und die Kamera des Geräts zugreift, diese Absicht deklarieren. Fügen Sie die folgenden Schlüssel mit einem Stringwert in die Datei „Info.plist“ Ihrer App ein und geben Sie einen Zweck-String für diesen Schlüssel an. Wenn Ihre App versucht, ohne entsprechenden Zweckstring auf die Mikrofone, die Fotogalerie oder die Kamera des Geräts zuzugreifen, wird die App beendet.

  • NSMicrophoneUsageDescription: Ermöglicht den Zugriff auf das Mikrofon, um Support- oder Fehlerbehebungsteams anzurufen und mit ihnen zu sprechen, sowie um Videos mit Ton zu Produktanfragen zu senden.

  • NSCameraUsageDescription: Erlaubt den Zugriff auf die Kamera, damit der Kunde Fotos im Zusammenhang mit seiner Kundensupportanfrage aufnehmen und senden kann.

  • NSPhotoLibraryUsageDescription: Ermöglicht Kunden den Zugriff, um Fotos im Zusammenhang mit ihrer Kundensupportanfrage zu senden.

  • NSFaceIDUsageDescription: Ermöglicht den Zugriff auf die Bestätigung per 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 mit diesem Schlüssel auch über einen Direct Access Point an einem bestimmten Punkt im Menü starten:

UJETStartOptions *option = [[UJETStartOptions alloc] initWithMenuKey:@"MENU_KEY"];
[UJET startWithOptions:option];

Der menuKey kann durch Erstellen eines Direct Access Point (DAP) erstellt werden. In den folgenden Schritten wird beschrieben, wie Sie eine DAP erstellen:

  1. Melden Sie sich mit Administratoranmeldedaten im CCAI Platform-Portal an.

  2. Gehen Sie zu Einstellungen > Warteschlange.

  3. Wählen Sie eine beliebige Warteschlange aus der Menüstruktur aus.

  4. Wählen Sie Direkten Zugriffspunkt erstellen aus.

  5. Geben Sie den Schlüssel in das Textfeld ein.

  6. Klicken Sie auf Speichern.

Cache aus lokalem Speicher löschen, wenn Nutzerdaten aktualisiert wurden

Wir speichern das Authentifizierungstoken im Schlüsselbund, um es wiederzuverwenden und weniger häufig Anfragen zum Signieren von Nutzlasten von der Host-App zu stellen. Das SDK verwendet es, bis es abläuft oder durch den Aufruf „clearUserData“ widerrufen wird. Die Host-App ist dafür verantwortlich, diesen Cache zu widerrufen, wenn sich nutzerbezogene Daten geändert haben oder aktualisiert wurden, z. B. bei einer Abmeldung.

[UJET clearUserData];

Vor dem Starten der Contact Center AI Platform nach vorhandener Sitzung suchen

Prüfen Sie vor dem Starten einer Sitzung, ob bereits eine Sitzung aktiv ist. Das ist besonders wichtig, wenn sich die userId geändert hat.

[UJET getStatus];

Wenn eine Sitzung 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 Ihr Design 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 Name des Unternehmens wird aus dem Admin-Portal > Einstellungen > Supportcenter-Details > Anzeigename abgerufen.

So können Sie das Logobild anstelle des Unternehmensnamens festlegen:

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

Wenn das Bild zu groß ist, wird es an die Größe des Bereichs angepasst.

Strings

Sie können Strings auch anpassen, indem Sie den Wert überschreiben. Fügen Sie beispielsweise diesen Schlüssel/Wert-Paar in Ihre 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 eine Farbtönung für den dunklen Modus angeben, um die Lesbarkeit von Schriftarten zu verbessern.

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

Wenn Sie das Attribut nicht festlegen, wird UJETGlobalTheme.tintColor für den dunklen Modus verwendet. Wir empfehlen, diese Property festzulegen, wenn Ihre App den dunklen Modus unterstützt. In den folgenden Apple-Artikeln finden Sie Informationen dazu, wie Sie die richtige Farbtonfarbe für den dunklen Modus auswählen:

Chatdesign

Wenn Sie den Chatbildschirm anpassen möchten, können Sie einen JSON-String oder die einzelnen Designklassen verwenden.

Sehen Sie sich als Referenz die Beispiel-App an und entfernen Sie die Auskommentierung der Methode customizeChatTheme.

func customizeChatTheme() throws {
  guard let file = Bundle.main.path(forResource: "chat-theme-custom", ofType: "json") else { return }
  let json = try String.init(contentsOfFile: file, encoding: .utf8)

  let chatTheme = UJETChatTheme.init(jsonString: json)

  let quickReplyTheme = UJETChatQuickReplyButtonTheme()
  quickReplyTheme.style = .individual
  quickReplyTheme.alignment = .right
  quickReplyTheme.backgroundColor = UJETColorRef(assetName: "white_color")
  quickReplyTheme.backgroundColorForHighlightedState = UJETColorRef(assetName: "quick_reply_color")
  quickReplyTheme.textColor = UJETColorRef(assetName: "quick_reply_color")
  quickReplyTheme.textColorForHighlightedState = UJETColorRef(assetName: "white_color")

  let fontTheme = UJETFontTheme()
  fontTheme.family = "Arial Rounded MT Bold"
  fontTheme.size = 14
  quickReplyTheme.font = fontTheme

  chatTheme?.quickReplyButtonTheme = quickReplyTheme

  let globalTheme = UJETGlobalTheme()
  globalTheme.chatTheme = chatTheme
  globalTheme.defaultAgentImage = UIImage(named: "agent_avatar_image")
  globalTheme.font = UIFont(name: "Arial Rounded MT Bold", size: 14)

  UJET.setGlobalTheme(globalTheme)
}

Content cards theme

Sie können die Anpassung für Inhaltskarten zusammen mit der Chatanpassung hinzufügen. Dazu können Sie entweder die JSON-Datei (siehe Attribut content_card) oder die Klasse UJETChatContentCardTheme verwenden.

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 Formularkarte

Sie können Anpassungen für Formularkarten zusammen mit Chatanpassungen 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

Wenn Sie die Webformularfunktion konfigurieren möchten, implementieren Sie die Methode ujetWebFormDidReceive des Protokolls UJETDelegate. Diese Methode empfängt ein Ereignis (ein FormMessageReceivedEvent-Wörterbuch) als Parameter, der formularbezogene Informationen enthält. Das Ereignis-Dictionary (FormMessageReceivedEvent) enthält die folgende JSON-Struktur:

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

So verarbeiten Sie das Ereignis:

  1. Extrahieren Sie die relevanten Informationen aus dem Ereigniswörterbuch (smart_action_id, external_form_id und signature).

  2. Generieren Sie einen Formular-URI und eine Signatur für die Formulardaten.

  3. Übergeben Sie die Formulardaten mit completion closure als FormDataEvent-Wörterbuch an das SDK.

  4. Wenn bei der URI-/Signaturgenerierung ein Fehler auftritt, rufen Sie den Callback mit callback.onError() und dem Error auf.

Das an das SDK übergebene Wörterbuch (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 der Daten müssen vor dem Generieren von Signaturen alphabetisch sortiert werden. Außerdem muss derselbe data an das SDK gesendet werden.

Übertragung nach der Sitzung

Sie können die Anpassung für den virtuellen Kundenservicemitarbeiter nach der Sitzung zusammen mit der Chatanpassung hinzufügen. Dies kann entweder über die JSON-Datei (siehe Attribut post_session) oder über die Klasse UJETChatPostSessionVaTheme erfolgen. Die Rahmenbreite kann nur 0 oder 1 sein. Wenn Sie die Darstellung des virtuellen Agenten nach der Sitzung nicht unterscheiden möchten, können Sie containerColor auf „Weiß“ und die Rahmenbreite 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ü für Chat-Aktionen

Sie können das Menü für Chataktionen zusammen mit der Chatanpassung anpassen. Dies kann entweder über die JSON-Datei (siehe Attribut form_card) 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 Darstellungen 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 aufgeführt.

Wenn Sie eine neue CCAI Platform-Support-Sitzung über die Anrufliste starten möchten, fügen Sie den folgenden Block in Ihre AppDelegate.m ein:

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 Ihren Xcassets ein Bild mit dem Namen „icon-call-kit“ ein.

SDK konfigurieren

Sie können vor dem Start des SDK mehrere Optionen festlegen.

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 Menü mit den Chatoptionen und auf dem Bildschirm nach dem Chat angezeigt 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 in mehreren Situationen ein PSTN-Fallback:

  • Das Mobilfunknetz ist offline.

  • Das Anwendungs-Backend ist nicht erreichbar.

  • VoIP ist nicht verfügbar

    • Die Netzwerkverbindung ist nicht gut genug, um eine Verbindung herzustellen. Weitere Informationen finden Sie unter der Property „UJETGlobalOptions.pstnFallbackSensitivity“.

    • Aufgrund der Firewallkonfiguration oder eines Anbieterproblems ist ein Fehler bei der Verbindung aufgetreten.

Wir empfehlen, die IVR-Nummer Ihres Unternehmens in UJETGlobalOptions.fallbackPhoneNumber festzulegen. Das empfohlene Format ist „+“, gefolgt von der Ländervorwahl und der Telefonnummer, z. B. +18001112222.

PSTN-Fallback-Empfindlichkeit

Sie können die Empfindlichkeit der Prüfung des Netzwerkzustands für den PSTN-Fallback anpassen.

@property (nonatomic, assign) float pstnFallbackSensitivity;

Der Wert muss im Bereich von 0,0 bis 1,0 liegen. Wenn der Wert auf „1“ gesetzt ist, wird der Anruf immer über das Telefonnetz und nicht über VoIP verbunden. Die maximale Latenz und der minimale Bandbreitenschwellenwert betragen 10.000 ms bzw. 10 KB/s für den Wert 0. Ein Wert von 0, 5 bedeutet beispielsweise, dass die Mindestlatenz und die Mindestbandbreite 5.000 ms bzw. 15 KB/s betragen.

Dieser Wert kann so konfiguriert werden:

  1. Melden Sie sich als Administrator im CCAI Platform-Portal an.

  2. Gehen Sie zu Einstellungen > Entwicklereinstellungen > Mobile Apps.

  3. Suchen Sie den Abschnitt Grenzwert für Fallback-Telefonnummer. Der Standardwert ist 0,85.

  4. Geben Sie den neuen Schwellenwert an.

  5. Klicken Sie auf Speichern.

Push-Benachrichtigungen auf globaler Ebene deaktivieren

Sie können Push-Benachrichtigungen auf globaler Ebene deaktivieren. Wenn Sie das folgende Attribut auf false setzen, werden alle Push-Benachrichtigungsabhängigkeiten umgangen und Push-Benachrichtigungen werden nicht an Endnutzer gesendet:

@property (nonatomic, assign) BOOL allowsPushNotifications;

Dunklen Modus ignorieren

Sie können den dunklen Modus im CCAI Platform SDK mit dieser Property ignorieren:

@property (nonatomic, assign) BOOL ignoreDarkMode;

Statusleiste ausblenden

Mit dieser Property können Sie die Sichtbarkeit der Statusleiste steuern:

  @property (nonatomic, assign) BOOL hideStatusBar;

Standardmäßig ist hideStatusBar auf false und visible festgelegt.

CSAT-Umfrage überspringen

Sie können eine Schaltfläche hinzufügen, mit der der Nutzer die CSAT-Umfrage überspringen kann. Das folgende Codebeispiel zeigt, wie die Schaltfläche hinzugefügt wird:

let options = UJETGlobalOptions()
options.skipCsat = true

Aktivitätsanzeige anpassen

Sie können dem SDK eine eigene Ladeanimation (in einem UIView) hinzufügen und die Standardanimation UIActivityIndicatorView überschreiben. Implementieren Sie die Methode ujet_activityIndicator aus UJETDelegate und geben Sie die benutzerdefinierte 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 UIUserInterfaceStyle in der Info.plist-Datei Ihrer App bereits auf „Light“ festgelegt haben, um den dunklen Modus vollständig zu deaktivieren, können Sie diese Property ignorieren.

Bevorzugte Sprache

Das CCAI Platform SDK verwendet die folgende Prioritätsreihenfolge, um die bevorzugte Sprache zu bestimmen.

  1. Die Sprache, die auf dem Splash Screen in der App ausgewählt wurde.

  2. Standardsprache aus UJETGlobalOptions ausgewählt. Sie können die Standardsprache mit dem Attribut preferredLanguage festlegen. Die unterstützten Sprachcodes finden Sie in der Datei UJETGlobalOptions.h.

  3. Die auf dem Gerät ausgewählte Gerätesprache (unter Einstellungen > Allgemein > Sprache & Region) wird verwendet, wenn sie von der App unterstützt wird.

  4. 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 auf dem Gerät die Sprache „Spanisch (Kuba)“ ausgewählt hat und die App „Spanisch (Kuba)“ nicht unterstützt, aber den übergeordneten Dialekt „Spanisch“, wird die Sprache „Spanisch“ verwendet.

  5. Wenn die Gerätesprache von der App nicht unterstützt wird, wird Englisch verwendet.

Symbole für externe Weiterleitungslinks 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 des 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. In diesem Artikel erfährst du, wie du Bilder zum Asset-Katalog hinzufügst.

Benutzerdefinierte Daten an Ihr CRM-System senden

Sie können benutzerdefinierte Daten an das CRM-Ticket senden.

Es gibt zwei Methoden, um benutzerdefinierte Daten zu senden:

  1. Sichere Methode: vordefinierte Datensignierung mit JWT.

  2. Nicht sichere Methode: vordefinierte Daten mit einfachem JSON (nicht empfohlen).

Sichere Methode zum Senden benutzerdefinierter Daten verwenden

Sie müssen eine Signaturmethode 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 Format 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];
    }
}

Unsichere Methode zum Senden benutzerdefinierter Daten

Diese Methode wird nicht empfohlen, da sie eine potenzielle Sicherheitslücke schafft, die Ihre Anwendung für einen Man-in-the-Middle-Angriff anfällig machen könnte. Wenn Sie diese Methode verwenden, sind wir nicht für die Sicherheitsrisiken und potenziellen Schäden verantwortlich, die auftreten können. Wir empfehlen Ihnen, die zuvor beschriebene sichere Methode zu verwenden, um benutzerdefinierte Daten in Ihrer Anwendung zu senden. Sie können das iOS SDK aber auch einfach mit der Instanz UJETCustomData starten. In diesem Fall sollte der signPayload-Delegat 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 Chatprotokolls verwenden

Sie können das Chatprotokoll 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 oder 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: Wörterbuch

    • name: String

    • avatar: String [URL des Agenten-Avatars, optional]

  • transcript: Array

    • sender: String [end_user oder agent]

    • timestamp: String [z. B. 2021-03-15 12:00:00Z]

    • content: Array

      • type: String [entweder text oder media]

      • text: String [erforderlich für Texttyp]

      • media: Wörterbuch [für Medientyp erforderlich]

        • type: String [entweder „image“ oder „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

In diesem Abschnitt finden Sie ein Beispiel für benutzerdefinierte Daten.

JSON-codiert 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"
    }
  }
}

Jedes Datenelement ä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
  • date

    • UTC-Unix-Zeitstempelformat mit 13 Ziffern. (enthält Millisekunden)
  • URL

    • HTTP-URL-Format
CRM-Beispiel

Hier ein Beispiel für ein CRM.

Standort

Verwenden Sie das CoreLocation-Framework. 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 Property invisible_to_agent mit einem benutzerdefinierten Datenobjekt verwenden, um zu verhindern, dass signierte oder unsignierte 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 das Attribut "invisible_to_agent" : true in ein benutzerdefiniertes Datenobjekt einfügen, können Sie Folgendes erwarten:

  • Die benutzerdefinierten Daten sind in der Sitzungsmetadatendatei enthalten.
  • Die benutzerdefinierten Daten sind nicht in CRM-Datensätzen enthalten.

Weitere Informationen finden Sie unter Sitzungsdaten im Agent-Adapter ansehen.

Reservierte Dateneigenschaften

Sie können reservierte Datenattribute 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": false,
        "type": "boolean"
      },
      "reserved_bad_actor": {
        "label": "Bad Actor",
        "value": false,
        "type": "boolean"
      },
      "reserved_repeat_customer": {
        "label": "Repeat Customer",
        "value": false,
        "type": "boolean"
      }
    }
  }
  

Legen Sie für jeden Wert true oder false fest.

  • reserved_verified_customer: true, wenn Sie diesen Endnutzer als legitimen Kunden betrachten.
  • reserved_bad_actor: true, wenn Sie diesen Endnutzer als potenziellen böswilligen Akteur betrachten.
  • reserved_repeat_customer: true, wenn Sie festgestellt haben, dass dieser Endnutzer Ihr Contact Center schon einmal kontaktiert hat.

Flow anpassen

In diesem Abschnitt wird beschrieben, wie Sie den Ablauf 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 Anruf oder Chat der CCAI Platform verschieben

Implementieren Sie eine Delegatmethode für die Verarbeitung eingehender Ereignisse:

-   (BOOL)shouldConnectUjetIncoming:(NSString *)identifier forType:(UjetIncomingType)type {
  if (weDoingSomething) {
    // save identifier and type
    return NO; // postpone
  } else {
    return YES;
  }
}
Verschobenes Ereignis verbinden
[UJET connect:identifier forType:UjetIncomingTypeCall];

Deeplink einrichten

So können Kundenservicemitarbeiter bei PSTN-Anrufen intelligente Aktionen per SMS verwenden, unabhängig davon, ob der Endnutzer die App hat oder nicht.

Rufen Sie im CCAI Platform-Portal Einstellungen > Betriebsverwaltung > SMS zum Herunterladen der App senden aktivieren auf.

Sie können die App-URL mit Ihrer Webseite (z. B. https://your-company.com/support) festlegen, nachdem Sie einen universellen Link oder ein benutzerdefiniertes URL-Schema konfiguriert haben. Sie können beide Optionen auswählen.

Implementieren Sie die Delegatmethode, um den Deeplink zu verarbeiten.

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 einen Ihrer Links ohne Suchparameter unter „App-URL“ im Admin-Portal ein. Geben Sie beispielsweise your-company://support ein, wenn Sie ein benutzerdefiniertes URL-Schema verwenden.

Achten Sie darauf, dass Sie in der Delegatmethode [UJET start] nur dann aufrufen, wenn die URL-Pfade und Parameter im universellen Link oder in der benutzerdefinierten URL spezifisch für die CCAI Platform 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 in den Beispielcodes aus der Datei UJETObject+DeepLink.

CCAI Platform-Ereignis beobachten

Wir posten die folgenden Ereignisse über NSNotificationCenter.defaultCenter. Sie können sie abhören und Ihren Ablauf je nach Anwendungsfall anpassen, z.B. mit einem benutzerdefinierten Tastaturlayout.

  • UJETEventEmailDidClick

    • Daten zum Warteschlangenmenü
  • UJETEventEmailDidSubmit

    • Daten zum Warteschlangenmenü

    • has_attachment: (NSNumber) @YES, @NO

  • UJETEventSessionViewDidAppear

    • Typ: @"call", @"chat"

    • timestamp: (NSString) ISO 8601

  • UJETEventSessionViewDidDisappear

    • Typ: @"call", @"chat"

    • timestamp: (NSString) ISO 8601

  • UJETEventSessionDidCreate

    • Sitzungsdaten
  • UJETEventSessionDidEnd

    • Sitzungsdaten

    • agent_name: (NSString) null, wenn der Agent 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

Menüdaten in die Warteschlange stellen

Metadaten

  • menu_id: NSString

  • menu_key: NSString, nullable

  • menu_name: NSString

  • menu_path : NSString

Sitzungsdaten

Metadaten

  • session_id: NSString

  • type: @"call", @"chat"

  • end_user_identifier: NSString

Bildschirmfreigabe einrichten

Wenn Sie die Bildschirmfreigabe verwenden möchten, binden Sie UJETCobrowseKit.xcframework ein.

CocoaPods

Fügen Sie diese Subspec dem Ziel Ihrer App hinzu:

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

Bildschirmfreigabe mit Carthage einrichten

Fügen Sie der Cartfile-Datei diese 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 den Wert von UJETGlobalOptions.cobrowseKey auf den Cobrowsing-Schlüssel Ihres Unternehmens fest.

swift
let options = UJETGlobalOptions()
options.cobrowseKey = cobrowseKey

UJET.setGlobalOptions(options)

Freigabe des gesamten Gerätebildschirms (optional)

Die vollständige Bildschirmfreigabe des Geräts ermöglicht es Ihren Support-Mitarbeitern, Bildschirme von Anwendungen außerhalb Ihrer eigenen anzuzeigen. Das ist oft nützlich, wenn Kundenservicemitarbeiter 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.

Wenn Sie das Dialogfeld zur Einholung von Einwilligungen für die Bildschirmfreigabe anpassen möchten, müssen Sie das Protokoll UJETCobrowseAlertProvider in Ihrer Anbieterklasse implementieren. In dieser Implementierung wird ein benutzerdefiniertes UIViewController oder ein anderes Objekt zurückgegeben, das über die entsprechende Protokollmethode von UIViewController übernommen wurde. UIViewController sollte zwei Schaltflächen haben, eine zum Akzeptieren und eine zum Ablehnen.

Nachdem Sie die Einwilligung erhalten haben, übergeben Sie sie an unser SDK, indem Sie den Closure consentStatus aufrufen. UIViewController von cobrowseFullDeviceRequestAlert. Der Bevollmächtigte sollte die RPSystemBroadcastPickerView mit Titel enthalten (siehe Beispielcode unten) und eine weitere Schaltfläche zum Ablehnen haben. Rufen Sie die Schließung auf, wenn auf den Button „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 Ansichts-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 Ansichts-Controller für die Benachrichtigung zur Anfrage für das gesamte Gerät sollte RPSystemBroadcastPickerView und einen Closure enthalten, 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 diese Funktion muss eine Broadcast-Erweiterung hinzugefügt werden.

  1. Öffnen Sie Ihr Xcode-Projekt.

  2. Klicken Sie auf Datei > Ziel.

  3. Wähle Broadcast Upload Extension aus.

  4. Geben Sie einen Namen für das Ziel ein.

  5. Entfernen Sie das Häkchen aus dem Kästchen UI-Erweiterung einschließen.

  6. Erstellen Sie das Ziel und notieren Sie sich die Paket-ID.

  7. Ändern Sie das Ziel-SDK Ihrer Broadcast-Erweiterung in iOS 12.0 oder höher.

SDK einbinden

CocoaPods: Fügen Sie dem Ziel Ihrer Erweiterung die 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 Produkt UJETCobrowseExtension 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 teilen. Dazu verwenden sie ihre eigene Schlüsselbundgruppe, sodass sie vom Rest des Schlüsselbunds Ihrer Apps isoliert sind.

Wählen Sie in Xcode sowohl das App-Ziel als auch das Erweiterungsziel aus. Fügen Sie eine Berechtigung zur Schlüsselbundfreigabe für die Schlüsselbundgruppe io.cobrowse hinzu.

Paket-ID zur PLIST-Datei hinzufügen

Nehmen Sie die Paket-ID der zuvor erstellten Erweiterung und fügen Sie diesen Eintrag in die Info.plist-Datei Ihrer App ein.

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

Erweiterung implementieren

Xcode hat die Dateien SampleHandler.m und SampleHandler.h (oder SampleHandler.swift) als Teil des zuvor erstellten Ziels hinzugefügt. Ersetzen Sie den Inhalt der Dateien durch Folgendes:

Swift:

Wählen Sie das Produkt UJETCobrowseExtension aus und fügen Sie es Ihrem 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 jetzt Ihre App 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. dem Klicken auf eine Inhaltskarte, zurück zu Ihrer App leiten möchten. Wenn Sie das SDK minimieren und den Nutzer zurück zu Ihrer App leiten möchten, 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
}

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 Bewertungsbildschirm nicht verfügbar ist.

authenticationError 100 Während 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 von einem VoIP-SDK-Callback verarbeitet.
voipLibraryNotFound 1001 Das System erwartet, dass ein Anruf über einen VoIP-Anbieter verbunden wird, kann aber keinen finden. Das kann passieren, wenn Sie das falsche SDK einbinden oder Ihren Abhängigkeiten keine VoIP-Anbieterbibliothek hinzufügen.
chatLibraryNotFound 1100 Tritt auf, wenn das System die Chatbibliothek nicht finden kann. Dies kann passieren, wenn Sie das falsche SDK einbinden oder keine Twilio-Chatbibliothek zu Ihren Abhängigkeiten hinzugefügt haben.

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

Fehlerbehebung

In diesem Abschnitt finden Sie Informationen zur Problembehebung häufiger Probleme.

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 das SDK zu groß ist und sich auf GitHub nur schwer verfolgen lässt

In diesem Artikel werden zwei Optionen angeboten. Es wird empfohlen, Git LFS zu verwenden.

Wenn Sie Bitcode nicht verwenden, können Sie den Bitcode auch aus der Binärdatei entfernen. Führen Sie diesen Befehl im Ordner „UJETKit.xcframework“ aus.

xcrun bitcode_strip -r UJET -o UJET

dyld: Fehler „Bibliothek nicht geladen“

Fügen Sie @executable_path/Frameworks unter „Runpath Search Paths“ (Suchpfade für Laufzeitpfade) hinzu. Gehen Sie dazu zu Target> Build Settings (Build-Einstellungen) > Linking (Verknüpfung).

App-Einreichung bei iTunes Connect

Apple stellt möglicherweise während des Überprüfungsprozesses die folgende Frage, da der Voice-over-IP-Hintergrundmodus aktiviert ist:

Können Nutzer in Ihrer App VoIP-Anrufe empfangen?

Beantworten Sie die Frage mit Yes.

Die Benachrichtigung ist beim Starten des SDK nicht verfügbar.

Prüfen Sie Folgendes:

  • Verwenden Sie ein echtes Gerät, keinen Simulator.

  • Aktivieren Sie Push-Benachrichtigungen und Hintergrundmodi > Voice over IP-Funktion.

Wenn das nicht hilft, versuchen Sie, mit einem Bereitstellungsprofil für die Verteilung (Ad-hoc oder Apple Store) zu erstellen.

Push-Benachrichtigung mit Ihrer Test-App testen

Halten Sie Ihr VoIP-Zertifikat und das Geräte-Token Ihres Geräts bereit.

Rufen Sie im CCAI Platform-Portal den Abschnitt Push-Benachrichtigungen debuggen im Menü Einstellungen > Entwicklereinstellungen auf.

Wenn Sie das Zertifikat für APNS bereits festgelegt haben, müssen Sie es nicht noch einmal eingeben.

Gib dein Zertifikat ein (optional) und prüfe, ob es sich um eine Sandbox handelt (optional). Gib dann das Geräte-Token für Push-Benachrichtigungen deiner Test-App ein.

Das Starten eines neuen Chats hat länger als 30 Sekunden gedauert

Prüfen Sie, ob Sie auf eine Delegatmethode für benutzerdefinierte Daten antworten. Du solltest auf 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)
    }
}