Carrot quest для iOS

Version

Содержание

Установка

На данный момент Carrot quest для iOS можно установить с помощью CocoaPod.

CocoaPods

Добавьте следующую строчку в pod файл:

pod 'CarrotquestSDK'

Инициализация

Для работы с Carrot quest для iOS вам понадобится API Key и User Auth Key. Вы можете найти эти ключи на вкладке "Настройки > Разработчикам": Разработчикам

Swift

Инициализация

Для инициализации Carrot quest вам нужно добавить следующий код в файл AppDelegate вашего приложения:

import CarrotSDK

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey:Any]?) -> Bool {
    ....
    Carrot.shared.setup(
        withApiKey: API-KEY,
        successHandler: {
                print("Carrotquest SDK connected")
        },
        errorHandler: { error in
            print("Carrotquest SDK error: " + error)
        })
    ....
}

Авторизация пользователей

Если в вашем приложении присутствует авторизация пользователей, вы можете передать ID пользователя в Carrot quest. Существует два способа авторизации.

  1. Напрямую передать userAuthKey
  2. Передать hash генерируемый у вас на бэке

  3. Вход через user auth key:

Carrot.shared.auth(
    withUserId: userId, 
    withUserAuthKey: userAuthKey,
        successHandler: {
                print("Carrotquest SDK user auth successed")
        },
        errorHandler: { error in
            print("Carrotquest SDK user auth error: " + error)
        })
  1. Вход через hash:
Carrot.shared.hashedAuth(
    withUserId: userId, 
    withHash: hash,
        successHandler: {
                print("Carrotquest SDK user auth successed")
        },
        errorHandler: { error in
            print("Carrotquest SDK user auth error: " + error)
        })

Для реализации функции выхода:

Carrot.shared.logout(
    successHandler: {
            print("Carrotquest SDK user logout successed")
    },
    errorHandler: { error in
        print("Carrotquest SDK user logout error: " + error)
    })

Свойства пользователей

Вы можете установить необходимые свойства пользователя с помощью:

Carrot.shared.setUserProperty(userProperties)

Где userProperties это объект типа [UserProperty].

Для описания свойств пользователя используйте класс UserProperty:

UserProperty(key: key, value: value)
UserProperty(key: key, value: value, operation: .updateOrCreate)

Более подробно про Operations можно прочитать в разделе «Свойства пользователя».

Внимание!

Поле key не может начинаться с символа $.

Для установки системных свойств реализовано 2 класса CarrotUserProperty и EcommerceUserProperty.

События

Для отслеживания событий используйте:

Carrot.shared.trackEvent(withName: name, withParams: params)

где params — дополнительные параметры для события в виде JSON-строки.

Чат с оператором

Вы можете дать пользователю мобильного приложения возможность перейти в чат с оператором из любого места. Это можно реализовать двумя разными путями - через плавающую кнопку, либо напрямую вызвав метод открытия чата в любое нужное время.

Плавающая кнопка (Floating Button)

Виджет предоставляющий быстрый доступ к чату. Добавить кнопку можно с помощью следующего метода:

Carrot.shared.showButton(in: view)

Для того чтобы скрыть кнопку возпльзуйтесь методом:

Carrot.shared.hideButton()

Открытие чата из произвольного места

Открыть чат можно также, вызвав из произвольного места (после инициализации) следующий код:

Carrot.shared.openChat()

Получение количества непрочтенных диалогов и сообщений

Для отслеживания количества непрочтенных диалогов:

Carrot.shared.getUnreadConversationsCount({ count in
    print("Carrotquest SDK dialogs count: \(count)")
})

и для количества непрочтенных сообщений:

Carrot.shared.getUnreadMessagesCount({ count in
    print("Carrotquest SDK messages count: \(count)")
})

Уведомления

Для работы с уведомлениями SDK использует сервис Firebase Cloud Messaging. В связи с этим необходимо получить ключ и отправить его в Carrot. Вы можете найти поле для ввода ключа на вкладке Настройки > Разработчикам. Процесс настройки сервиса Firebase Cloud Messaging описан здесь.

Далее, в делегате MessagingDelegate необходимо установить fcmToken для Carrot SDK:

import FirebaseMessaging
import CarrotSDK
extension AppDelegate: MessagingDelegate {  
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        if let fcmToken = fcmToken {
            CarrotNotificationService.shared.setToken(fcmToken)
        } else {
            print("Carrotquest SDK error: fcmToken not found")
        }
        ...
    }
}

Для отображения уведомлений, необходимо добавить код в UNUserNotificationCenterDelegate:

import CarrotSDK
extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let notificationService = CarrotNotificationService.shared
        if notificationService.canHandle(notification) {
            notificationService.show(notification, completionHandler: completionHandler)
        } else {
            // Логика для пользовательских уведомлений
        }
    }
}

Для обработки кликов на уведомления:

import CarrotSDK
extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void) {
        let notificationService = CarrotNotificationService.shared
        if notificationService.canHandle(response) {
            notificationService.clickNotification(notificationResponse: response)
        } else {
            // Логика для пользовательских уведомлений
        }
        completionHandler()
    }
}

Objective-C

Инициализация

Для инициализации Carrot quest вам нужно добавить следующий код в файл AppDelegate вашего приложения:

#import "CarrotSDK/CarrotSDK.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ....
    Carrot *carrot = [Carrot shared];
    [
        carrot
        setupWithApiKey: API-KEY
        successHandler: ^(){
            NSLog(@"Carrotquest SDK connected");
        }
        errorHandler: ^(NSString *error){
            NSLog(@"Carrotquest SDK error: %@", error);
    }];
    ....
    return YES;
}

Авторизация пользователей

Если в вашем приложении присутствует авторизация пользователей, вы можете передать ID пользователя в Carrot quest. Существует два способа авторизации.

  1. Напрямую передать userAuthKey
  2. Передать hash генерируемый у вас на бэке

  3. Вход через user auth key:

Carrot *carrot = [Carrot shared];
[
  carrot
  authWithUserId: userId
  withUserAuthKey: userAuthKey
  successHandler: ^(){
      NSLog(@"Carrotquest SDK user auth successed");
  }
  errorHandler: ^(NSString *error){
      NSLog(@"Carrotquest SDK user auth error: %@", error);
}];
  1. Вход через hash:
Carrot *carrot = [Carrot shared];
[
  carrot
  authWithUserId: userId
  withHash: hash
  successHandler: ^(){
      NSLog(@"Carrotquest SDK user auth successed");
  }
  errorHandler: ^(NSString *error){
      NSLog(@"Carrotquest SDK user auth error: %@", error);
}];

Для реализации функции выхода:

Carrot *carrot = [Carrot shared];
[
  carrot
  logoutWithSuccessHandler: ^(){
     NSLog(@"Carrotquest SDK user logout successed");
  } errorHandler: ^(NSString *error){
     NSLog(@"Carrotquest SDK user logout error: %@", error);
}];

Свойства пользователей

Вы можете установить необходимые свойства пользователя с помощью:

Carrot *carrot = [Carrot shared];
[
  carrot
  setUserProperty:userProperties
]

Где userProperties это объект типа [UserProperty].

Для описания свойств пользователя используйте класс UserProperty:

Carrot *carrot = [Carrot shared];
UserProperty *userProp = [[UserProperty alloc] initWithKey: key value: value];
UserProperty *userProp = [[UserProperty alloc] initWithKey: key value: value operation: @"updateOrCreate"];

Более подробно про Operations можно прочитать в разделе «Свойства пользователя».

Внимание!

Поле key не может начинаться с символа $.

Для установки системных свойств реализовано 2 класса CarrotUserProperty и EcommerceUserProperty.

События

Для отслеживания событий используйте:

Carrot *carrot = [Carrot shared];
[
  carrot
  trackEventWithName: name
  withParams: params
];

где params — дополнительные параметры для события в виде JSON-строки.

Чат с оператором

Вы можете дать пользователю мобильного приложения возможность перейти в чат с оператором из любого места. Это можно реализовать двумя разными путями - через плавающую кнопку, либо напрямую вызвав метод открытия чата в любое нужное время.

Плавающая кнопка (Floating Button)

Виджет предоставляющий быстрый доступ к чату. Добавить кнопку можно с помощью следующего метода:

Carrot *carrot = [Carrot shared];
[carrot showButtonIn: self.view];

Для того чтобы скрыть кнопку возпльзуйтесь методом:

Carrot *carrot = [Carrot shared];
[carrot hideButton];

Открытие чата из произвольного места

Открыть чат можно также, вызвав из произвольного места (после инициализации) следующий код:

Carrot *carrot = [Carrot shared];
[carrot openChat];

Получение количества непрочтенных диалогов и сообщений

Для отслеживания количества непрочтенных диалогов:

Carrot *carrot = [Carrot shared];
[
  carrot
  getUnreadConversationsCount:^(NSInteger count){
        NSLog(@"Carrotquest SDK dialogs count: %ld", (long)count);
}];

и для количества непрочтенных сообщений:

Carrot.shared.getUnreadMessagesCount({ count in
    print("Carrotquest SDK messages count: \(count)")
})
Carrot *carrot = [Carrot shared];
[
  carrot
  getUnreadMessagesCount:^(NSInteger count){
        NSLog(@"Carrotquest SDK dialogs count: %ld", (long)count);
}];

Уведомления

Для работы с уведомлениями SDK использует сервис Firebase Cloud Messaging. В связи с этим необходимо получить ключ и отправить его в Carrot. Вы можете найти поле для ввода ключа на вкладке Настройки > Разработчикам. Процесс настройки сервиса Firebase Cloud Messaging описан здесь.

Далее, в делегате MessagingDelegate необходимо установить fcmToken для Carrot SDK:

#import "CarrotSDK/CarrotSDK.h"
#import <Firebase.h>

- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
    CarrotNotificationService *service = [CarrotNotificationService shared];
    [service setToken: fcmToken];
}

Для отображения уведомлений, необходимо добавить код в AppDelegate:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    CarrotNotificationService *service = [CarrotNotificationService shared];
    if ([service canHandle:notification]) {
        [service show:notification appGroudDomain:nil completionHandler:completionHandler];
    } else {
        // Логика для пользовательских уведомлений
    }
}

Для обработки кликов на уведомления:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void(^)(void))completionHandler {
    CarrotNotificationService *service = [CarrotNotificationService shared];
    if ([service canHandleWithResponse:response]) {
        [service clickNotificationWithNotificationResponse:response appGroudDomain:nil];
    } else {
        // Логика для пользовательских уведомлений
    }
}

Дублирование уведомлений и статистика доставленных пушей

Мы используем 2 канала доставки сообщений, поэтому в некоторых случаях уведомления могут дублироваться. Например: при выходе из приложения, или при очень быстром удалении уведомления, возможно получение повтороного уведомления. Для предотвращения такого поведения нужно создать Notification Service Extension. В Xcode, в списке файлов выберите свой проект, а затем File/New/Target/Notification Service Extension.

После чего необходимо зарегистрировать AppGroup в Apple Developer Portal. Identifier App Group должен быть уникальным, и начинаться на "group." иначе Xcode его не примет.

Теперь необходимо добавить Identifier в Xcode:

AppGroup

1) В списке файлов выберите свой проект.

2) В списке targets выберете пункт с именем вашего проекта.

3) Во вкладке "Singing & Capabitities" нажмите на "+ Capability".

4) В выпадающем списке найдите найдите и выберите App Group.

5) На вкладке появится пустой список для идентификаторов App Group. Добавте туда Identifier, который зарегистрировали в Apple Developer Portal ранее.

6) Вернитесь к списку Targets. Аналогичным образом добавте App Group к вашему Notification Service Extension.

Внесите изменения в метод инициализирующий библиотеку:

   Carrot.shared.setup(
   ...
       withAppGroup: <group_id>,
   ...
   )

Теперь нужно добавить логику в ваш Notification Service Extension. В списке файлов, должна была появиться новая папка с именем вашего Notification Service Extension. Добавте код в файл NotificationService.swift:

import UserNotifications
import CarrotSDK

class NotificationService: CarrotNotificationServiceExtension {
    override func setup() {
        self.apiKey = <api_key>
        self.domainIdentifier = <group_id>
    }
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        <ваша логика>
        super.didReceive(request, withContentHandler: contentHandler) 
    }
}

Обновите ваш pod файл, добавьте:

   target 'NotificationService' do
     inherit! :search_paths
     pod 'CarrotquestSDK'
   end

И напоследок, нужно передать Identifier зарегистрированный в Apple Developer Portal ранее в метод show в UNUserNotificationCenterDelegate:

let domain = "Identifier зарегистрированный в Apple Developer Portal ранее"
notificationService.show(notification, appGroudDomain: domain, completionHandler: completionHandler)

Локализация

Для того, чтобы SDK автоматически подтягивал и русскую локализацию, кроме стандартной, английской, необходимо убедиться, что в Xcode проекте такая локализация включена.

Локализация

Xcode 15

Если вы используете Xcode 15 и выше, и CocoaPods 1.12.1 и ниже, то у вас возникнет ошибка директорий, вроде такой:

Локализация

Чтобы исправить это, добавьте следующий код в конец своего podfile:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference
        xcconfig_path = config.base_configuration_reference.real_path
        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub("DT_TOOLCHAIN_DIR", "TOOLCHAIN_DIR"))
      end
    end
  end
end

Возможно, в будущем, CocoaPods обновится, и этот код придется удалить, но в данный момент, он необходим.

Использование ссылок в пушах

Небольшой словарь терминов, перед тем как мы начнем:

Universal link (еще его называют Deeplink, но это не терминология Apple):

https://example.com/section

URL scheme:

example://section

Итак, вы можете приложить ссылку к пушу.

PushLink

Однако, не все так просто. Внутри обработчика пуша лежит функция:

if let clickActionUrl = URL(string: "Ваша ссылка") {
        UIApplication.shared.open(clickActionUrl, options: [:])
}

Простейшая логика. Однако, по какой-то причине, функция iOS для открытия ссылок, указанная выше, не распознает универсальную ссылку приложения, если она вызывается из этого же приложения. Это отправит пользователя прямо в браузер.

Поэтому, есть два возможных варианта решения проблемы:

  1. URL Scheme
  2. Ручная обработка Universal link

  1. URL Scheme

Если в вашем приложении настроены URL Scheme то все уже готово. Просто приложите нужную схему к пушу.

Далее прикладываю небольшой туториал по настройке URL Scheme.

URL Scheme - это более простой и надежный способ открыть нужную страницу в приложении, в отличии от Universal Link. Однако, они не выглядят как ссылка из интернета:

deeplink://test

Перейдем к настройке. Выберите цель в настройках проекта Xcode и перейдите на вкладку «Информация». Внизу страницы вы найдете раздел «URL Types».

URL_scheme

Нажав +, мы можем создать новый тип. В качестве идентификатора люди часто повторно используют пакет приложения. Для схем URL-адресов мы рекомендуем использовать название приложения (или сокращенное название), чтобы оно было как можно более кратким. В нем не должно быть никаких специальных символов. Мы будем использовать deeplink в качестве примера.

Ваше приложение готово распознать URL схему, теперь нам нужно обработать его, когда мы его получим.

Приложение фиксирует открытие следующим образом в более ранних приложениях, в которых есть только AppDelegate.

extension AppDelegate {

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {

        print(url)
        return true
    }
}

Для новых приложений, включающих SceneDelegate, необходимо добавить обработчик еще и туда. Важно отметить, что метод AppDelegateне будет вызван, даже если вы его реализуете.

extension SceneDelegate {
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        guard let firstUrl = URLContexts.first?.url else {
            return
        }

        print(firstUrl.absoluteString)
    }
}

Если хотите проверить ссылку, введите ее в браузере Safari. Так же, доступен вариант для быстрой проверки на симуляторе. Вот команда для терминала:

xcrun simctl openurl booted "deeplink://test"
  1. Ручная обработка Universal link

Вернитесь к обработчику кликов на пуши, и передайте аргумент false в параметр openLink:

CarrotNotificationService.shared.clickNotification(
        notificationResponse: response,
        openLink: false
)

Затем, нужно достать ссылку из объекта response, который пришел в пуше. Мы заранее подготовили для этого функцию:

let link: String? = CarrotNotificationService.shared.getLink(from: response)

Обратите внимание, что функция возвращает опционал, потому что пуш не всегда содержит ссылку.

Таким образом, в методе обработки кликов на пуши, у вас получится что-то такое:

import CarrotSDK
extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void) {
        let notificationService = CarrotNotificationService.shared
        if notificationService.canHandle(response) {
            notificationService.clickNotification(notificationResponse: response, openLink: false)
                        if let link = CarrotNotificationService.shared.getLink(from: response) {
                                print(link)
                                // Обработчик открытия Universal link
        }
        completionHandler()
    }
}