Contact Center AI Platform (CCAI Platform) oferece integração com aplicativos para dispositivos móveis usando vários métodos, incluindo o React. Este documento explica como integrar o React Native para iOS.
Antes de seguir estas instruções específicas do Android, conclua as instruções em SDK do React Native para dispositivos móveis.
Integrar o SDK usando o CocoaPods
Para integrar o SDK para dispositivos móveis usando o CocoaPods, abra o Podfile e adicione as seguintes dependências ao destino:
UJETPodspec = { :podspec => 'https://sdk.ujet.co/ios/UJET.podspec' } pod 'UJET', UJETPodspec pod 'UJET/Cobrowse', UJETPodspecInstale as dependências executando o comando
pod-installna pasta ios ou npx pod-install na pasta do app.
Configurar notificações push
Para configurar notificações push no SDK para dispositivos móveis, siga estas etapas:
Abra o projeto do Xcode.
Abra o arquivo que está em conformidade com
RCTAppDelegatee adicione o seguinte código:#import <UJETKit/UJETKit.h> #import <PushKit/PushKit.h> @interface AppDelegate() <PKPushRegistryDelegate> @end - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { PKPushRegistry *voipRegistry = [[PKPushRegistry alloc] initWithQueue: dispatch_get_main_queue()]; voipRegistry.delegate = self; voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; } #pragma mark PushKit - (NSString *)tokenFromData:(NSData *)data { const void *bytes = [data bytes]; const unsigned char *d = (const unsigned char *)bytes; NSMutableString *token = [NSMutableString string]; for (NSUInteger i = 0; i < [data length]; ++i) { [token appendFormat:@"%02X", d[i]]; } return [token lowercaseString]; } - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type { NSLog(@"voip token: %@", [self tokenFromData:credentials.token]); if ([type isEqual:PKPushTypeVoIP]) { [UJET updatePushToken:credentials.token type:UjetPushTypeVoIP]; } } - (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type { if ([type isEqual:PKPushTypeVoIP]) { [UJET updatePushToken:nil type:UjetPushTypeVoIP]; } } - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { if ([type isEqual:PKPushTypeVoIP] && payload.dictionaryPayload[@"ujet"]) { [UJET receivedNotification:payload.dictionaryPayload completion:completion]; } else { completion(); } } #pragma mark APNS - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSLog(@"apns token: %@", [self tokenFromData:deviceToken]); [UJET updatePushToken:deviceToken type:UjetPushTypeAPN]; } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(nonnull NSError *)error { [UJET updatePushToken:nil type:UjetPushTypeAPN]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { if (userInfo[@"ujet"]) { [UJET receivedNotification:userInfo completion:nil]; } else { // handle your notifications } }Para Swift:
import UJETKit import PushKit func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let voipRegistry = PKPushRegistry(queue: DispatchQueue.main) voipRegistry.desiredPushTypes = Set([PKPushType.voIP]) voipRegistry.delegate = self } // MARK: Push Notifications extension AppDelegate { 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)) UJET.updatePushToken(deviceToken, type: .APN) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { UJET.updatePushToken(nil, type: .APN) } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { if userInfo["ujet"] != nil { UJET.receivedNotification(userInfo, completion: nil) } else { // handle your notifications } } } // MARK: PushKit extension AppDelegate: PKPushRegistryDelegate { func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { print("voip token: ", tokenFromData(data: credentials.token)) if type == .voIP { UJET.updatePushToken(credentials.token, type: .voIP) } } func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) { if type == .voIP { UJET.updatePushToken(nil, type: .voIP) } } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { if type == .voIP && payload.dictionaryPayload["ujet"] != nil { UJET.receivedNotification(payload.dictionaryPayload, completion: completion) } else { completion() } } }Selecione o .xcodeproj e o destino do app. Adicione PushKit.framework na seção "Frameworks, Libraries, and Embedded Content".
Configurar links diretos
Para oferecer suporte a links diretos no seu aplicativo para dispositivos móveis, use o seguinte código:
#pragma mark Deep Link
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
if ([url.scheme isEqualToString:@"ujet"]) {
return [self handleRouting:url];
}
return NO;
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
// Universal links
if ([NSUserActivityTypeBrowsingWeb isEqualToString:userActivity.activityType]) {
return [self handleRouting:userActivity.webpageURL];
} else if ([userActivity.activityType isEqualToString:@"INStartAudioCallIntent"]) {
// Open app from Call history
[UJET startWithOptions:nil];
return YES;
}
return NO;
}
- (BOOL)handleRouting:(NSURL *)url {
NSArray *availableSchema = @[
@"ujetrn", // TODO: Change to your custom URL scheme. Config from Portal > Developer Settings > Mobile App > Enable Send SMS to Download App > iOS App > URL
@"https" // TODO: or your universal link
];
NSArray *availableHostAndPath = @[
@"call", // custom URL scheme
@"ujet.cx/app" // universal link
];
if (![availableSchema containsObject:url.scheme]) {
return NO;
}
NSString *hostAndPath = [NSString stringWithFormat:@"%@%@", url.host, url.path];
if (![availableHostAndPath containsObject:hostAndPath]) {
return NO;
}
// ujetrn://call?call_id={call_id}&nonce={nonce}
// https://ujet.co/app?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];
return YES;
}
- (NSString *)valueForKey:(NSString *)key fromQueryItems:(NSArray *)queryItems {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name=%@", key];
NSURLQueryItem *queryItem = [[queryItems
filteredArrayUsingPredicate:predicate]
firstObject];
return queryItem.value;
}
- (BOOL)isValidCallId:(NSString *)callId {
if (callId.length == 0) {
return NO;
}
NSCharacterSet *nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSRange r = [callId rangeOfCharacterFromSet: nonNumbers];
return r.location == NSNotFound;
}
Para Swift:
// MARK: Deep Link
extension AppDelegate {
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
print("Open app with url: \(url.absoluteString)")
return self.handleRouting(url)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Universal links
if NSUserActivityTypeBrowsingWeb == userActivity.activityType {
return self.handleRouting(userActivity.webpageURL!)
} else if userActivity.activityType == "INStartAudioCallIntent" {
// Open app from Call history
let model = DataController.shared.startOptions()
let startOptions = StartOptionsController().convert(model)
UJET.start(with: startOptions)
return true
}
return false
}
func handleRouting(_ url: URL) -> Bool {
let availableSchema = [
"ujetrn", // TODO: Change to your custom URL scheme. Config from Portal > Developer Settings > Mobile App > Enable Send SMS to Download App > iOS App > URL
"https" // universal link
]
let availableHostAndPath = [
"call", // custom URL scheme
"ujet.cx/app", // universal link,
]
if !(availableSchema.contains(url.scheme ?? "")) {
return false
}
let hostAndPath = String.init(format: "%@%@", url.host ?? "", url.path)
if !(availableHostAndPath.contains(hostAndPath)) {
return false
}
// ujet://call?call_id={call_id}&nonce={nonce}
// https://ujet.co/app?call_id={call_id}&nonce={nonce}
let urlComponents: URLComponents? = URLComponents(url: url, resolvingAgainstBaseURL: false)
let queryItems = urlComponents?.queryItems
let callId = value(forKey: "call_id", fromQueryItems: queryItems)
// validate call ID
if !isValidCallId(callId) {
return false
}
guard let nonce = value(forKey: "nonce", fromQueryItems: queryItems) else {
return false
}
let options = UJETStartOptions.init(callId: callId!, nonce: nonce)
UJET.start(with: options)
return true
}
func value(forKey key: String?, fromQueryItems queryItems: [URLQueryItem]?) -> String? {
let predicate = NSPredicate(format: "name=%@", key ?? "")
let filtered = (queryItems as NSArray?)?.filtered(using: predicate) as? [URLQueryItem]
let queryItem: URLQueryItem? = filtered?.first
return queryItem?.value
}
func isValidCallId(_ callId: String?) -> Bool {
if (callId ?? "").isEmpty {
return false
}
let nonNumbers = CharacterSet.decimalDigits.inverted
let r = callId?.rangeOfCharacter(from: nonNumbers)
return r == nil
}
}
Configurações de destino
Esta seção mostra os recursos e as informações adicionais necessárias para a configuração de destino.
Recursos
Notificações push
Modos de segundo plano (marque os itens abaixo):
Áudio e AirPlay
Voz sobre IP (VoIP)
Informações
Adicione as seguintes chaves com descrição:
NSMicrophoneUsageDescription
NSCameraUsageDescription
NSPhotoLibraryUsageDescription
NSFaceIDUsageDescription