{"id":25138452,"url":"https://github.com/carrotquest/ios-sdk","last_synced_at":"2025-04-24T03:08:17.067Z","repository":{"id":41175547,"uuid":"168132361","full_name":"carrotquest/ios-sdk","owner":"carrotquest","description":"Conversational platform for business. iOS sdk.","archived":false,"fork":false,"pushed_at":"2025-04-23T11:15:35.000Z","size":9767034,"stargazers_count":4,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-24T03:08:07.448Z","etag":null,"topics":["chatbot","conversion-rate-optimization","customer-engagement","customer-service","inbox","integration","ios","lead-generation","livechat","mobile-app-updates","settings","swift","triggered-messages"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/carrotquest.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-01-29T10:01:15.000Z","updated_at":"2025-04-17T09:56:24.000Z","dependencies_parsed_at":"2023-09-28T13:42:11.972Z","dependency_job_id":"b21ee8d9-5d95-454f-88f8-728468aedd4e","html_url":"https://github.com/carrotquest/ios-sdk","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carrotquest%2Fios-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carrotquest%2Fios-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carrotquest%2Fios-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carrotquest%2Fios-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/carrotquest","download_url":"https://codeload.github.com/carrotquest/ios-sdk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250552074,"owners_count":21449164,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatbot","conversion-rate-optimization","customer-engagement","customer-service","inbox","integration","ios","lead-generation","livechat","mobile-app-updates","settings","swift","triggered-messages"],"created_at":"2025-02-08T17:16:37.958Z","updated_at":"2025-04-24T03:08:17.054Z","avatar_url":"https://github.com/carrotquest.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"## Carrot quest для iOS\n\n![Version](https://img.shields.io/static/v1?label=Version\u0026message=2.13.1\u0026color=brightgreen)[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg)](https://swift.org/package-manager/)\n\n## Содержание\n\n- [Установка](#setup_pods)\n- [Swift](#swift)\n  - [Инициализация](#init_swift)\n  - [Авторизация пользователей](#auth_swift)\n  - [Свойства пользователей](#prop_swift)\n  - [События](#event_swift)\n  - [Трекинг навигации](#tracking_swift)\n  - [Чат с оператором](#chat_swift)\n  - [Открытие ссылок вручную](#custom_url_opener_swift)\n  - [Уведомления](#notif_swift)\n- [Objective-C](#init_objc)\n  - [Инициализация](#init_objc)\n  - [Авторизация пользователей](#auth_objc)\n  - [Свойства пользователей](#prop_objc)\n  - [События](#event_objc)\n  - [Трекинг навигации](#tracking_objc)\n  - [Чат с оператором](#chat_objc)\n  - [Открытие ссылок вручную](#custom_url_opener_objc)\n  - [Уведомления](#notif_objc)\n- [Важная информация о Push уведомлениях](#important_push)\n- [Дублирование уведомлений и статистика доставленных пушей](#notif_extension)\n- [Метод отписки от пушей](#notifications_unsubscribe)\n- [Локализация](#localization)\n- [Xcode 15](#xcode15)\n- [Использование ссылок в пушах](#Push+link) \n- [Отлючение дебажных логов](#TurnOffLogs)\n\n\u003ca name=\"setup_pods\"\u003e\u003c/a\u003e\n\n## Установка\n\nНа данный момент Carrot quest для iOS можно установить с помощью CocoaPod и Swift Package Manager.\n\n## CocoaPods\nДобавьте следующую строчку в pod файл:\n```swift\npod 'CarrotquestSDK'\n```\n\n## Swift Package Manager\n\nВ Xcode нажмите File-\u003eAdd Package Dependencies...\n\nЗатем в появившемся окне в поле \"Search or Enter Package URL\" вставте ссылку на SwiftPM репозиторий:\n\n```url\nhttps://github.com/carrotquest/carrotquest-ios-spm.git\n```\n\n## Инициализация\n\nДля работы с Carrot quest для iOS вам понадобится API Key и User Auth Key. Вы можете найти эти ключи на вкладке \"Настройки \u003e Разработчикам\":\n![Разработчикам](https://raw.githubusercontent.com/carrotquest/ios-sdk/master/assets/ApiKeys.png)\n\n\u003ca name=\"swift\"\u003e\u003c/a\u003e\n\n# Swift\n\n\u003ca name=\"init_swift\"\u003e\u003c/a\u003e\n\n## Инициализация\n\nДля инициализации Carrot quest вам нужно добавить следующий код в файл AppDelegate вашего приложения:\n\n```Swift\nimport CarrotSDK\n\nfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey:Any]?) -\u003e Bool {\n    ....\n    Carrot.shared.setup(\n        withApiKey: API-KEY,\n        successHandler: {\n                print(\"Carrotquest SDK connected\")\n        },\n        errorHandler: { error in\n            print(\"Carrotquest SDK error: \" + error)\n        })\n    ....\n}\n```\n\n\u003ca name=\"auth_swift\"\u003e\u003c/a\u003e\n\n## Авторизация пользователей\n\nЕсли в вашем приложении присутствует авторизация пользователей, вы можете передать ID пользователя в Carrot quest. Существует два способа авторизации: напрямую передать userAuthKey, передать hash генерируемый у вас на бэке.\n\n1. Вход через user auth key:\n\n```Swift\nCarrot.shared.auth(\n    withUserId: userId, \n    withUserAuthKey: userAuthKey,\n        successHandler: { carrotId in\n                print(\"Carrotquest SDK user auth successed, CarrotId = \\(carrotId)\")\n        },\n        errorHandler: { error in\n            print(\"Carrotquest SDK user auth error: \" + error)\n        })\n```\n\n2. Вход через hash:\n\n```Swift\nCarrot.shared.hashedAuth(\n    withUserId: userId, \n    withHash: hash,\n        successHandler: { carrotId in\n                print(\"Carrotquest SDK user auth successed, CarrotId = \\(carrotId)\")\n        },\n        errorHandler: { error in\n            print(\"Carrotquest SDK user auth error: \" + error)\n        })\n```\n\nДля реализации функции выхода:\n\n```Swift\nCarrot.shared.logout(\n    successHandler: {\n            print(\"Carrotquest SDK user logout successed\")\n    },\n    errorHandler: { error in\n        print(\"Carrotquest SDK user logout error: \" + error)\n    })\n```\n\n\u003ca name=\"prop_swift\"\u003e\u003c/a\u003e\n\n## Свойства пользователей\n\nВы можете установить необходимые свойства пользователя с помощью:\n```Swift\nCarrot.shared.setUserProperty(userProperties)\n```\nГде `userProperties` это объект типа `[UserProperty]`.\n\nДля описания свойств пользователя используйте класс `UserProperty`:\n```Swift\nUserProperty(key: key, value: value)\nUserProperty(key: key, value: value, operation: .updateOrCreate)\n```\nБолее подробно про `Operations` можно прочитать в разделе [«Свойства пользователя»](https://developers.carrotquest.io/props/#_3).\n\n`Внимание!`\n\nПоле `key` не может начинаться с символа `$`.\n\n\nДля установки [системных свойств](https://developers.carrotquest.io/props/#_4) реализовано 2 класса `CarrotUserProperty` и `EcommerceUserProperty`.\n\n\u003ca name=\"event_swift\"\u003e\u003c/a\u003e\n\n## События\n\nДля отслеживания событий используйте:\n```Swift\nCarrot.shared.trackEvent(withName: name, withParams: params)\n```\nгде `params` \u0026mdash; дополнительные параметры для события в виде JSON-строки.\n\n\u003ca name=\"tracking_swift\"\u003e\u003c/a\u003e\n\n## Трекинг навигации\n\nB SDK есть возможность трекинга навигации внутри приложения для того, чтобы при необходимости запускать различные триггерные сообщения на определенных экранах. Для этого используйте метод:\n\n```Swift\nlet name: String = \"screenName\"\nCarrot.shared.trackScreen(name)\n```\n\n\u003ca name=\"chat_swift\"\u003e\u003c/a\u003e\n\n## Чат с оператором\n\nВы можете дать пользователю мобильного приложения возможность перейти в чат с оператором из любого места. Это можно реализовать двумя разными путями - через плавающую кнопку, либо напрямую вызвав метод открытия чата в любое нужное время.\n\n### Плавающая кнопка (Floating Button)\nВиджет предоставляющий быстрый доступ к чату. Добавить кнопку можно с помощью следующего метода:\n\n```Swift\nCarrot.shared.showButton(in: view)\n```\n\nДля того чтобы скрыть кнопку возпльзуйтесь методом:\n```Swift\nCarrot.shared.hideButton()\n```\n\n### Открытие чата из произвольного места\nОткрыть чат можно также, вызвав из произвольного места (после инициализации) следующий код:\n```swift\nCarrot.shared.openChat()\n```\n\n### Получение количества непрочтенных диалогов и сообщений\nДля отслеживания количества непрочтенных диалогов:\n```swift\nCarrot.shared.getUnreadConversationsCount({ count in\n    print(\"Carrotquest SDK dialogs count: \\(count)\")\n})\n```\n\nи для количества непрочтенных сообщений:\n```swift\nCarrot.shared.getUnreadMessagesCount({ count in\n    print(\"Carrotquest SDK messages count: \\(count)\")\n})\n```\n\n\u003ca name=\"custom_url_opener_swift\"\u003e\u003c/a\u003e\n\n## Открытие ссылок вручную\n\nДля того, чтобы при клике на ссылку внутри SDK правильно работали диплинки (universal link) существует специальный метод ручного управления методом открытия ссылок. Его можно вызвать где угодно, но лучше всего где-то в вашем AppDeletage/SceneDelegate рядом с инициализацией SDK:\n\n```swift\nimport CarrotSDK\n\nCustomUrlOpener.shared.set(for: .chat, customLogic: { url in\n      // Любая кастомная логика по открытию ссылок\n})\n```\n\nКак вы можете заметить, первый аргумент, который имеет label `for` на 4 доступных варианта:\n\n- push - изменяет логику при клике на ссылку в пуше\n- chat - изменяет логику при клике на ссылку в чате\n- popup - изменяет логику при клике на ссылку в попапе\n- all - изменяет логику при клике на ссылку во всех 3 местах\n\nТаким образом, если вы хотите обработать клики на диплинк (universal link) во всех местах SDK, можно написать какой-то такой код:\n\n```swift\nimport CarrotSDK\n\nCustomUrlOpener.shared.set(for: .all) { url in\n    if url.host?.contains(\"ВАШ ДОМЕН\") ?? false {\n        CustomUrlOpener.shared.openUniversalLink(url)\n    } else {\n        CustomUrlOpener.shared.openBrowserLink(url)\n    }\n}\n```\n\nЕсли что, ошибки тут нет. Актуальные версии swift позволяют не указывать label последего замыкания в вызове функции. \n\n\u003ca name=\"notif_swift\"\u003e\u003c/a\u003e\n\n## Уведомления\n\nДля работы с уведомлениями SDK использует сервис Firebase Cloud Messaging. В связи с этим необходимо получить ключ и отправить его в Carrot. Вы можете найти поле для ввода ключа на вкладке Настройки \u003e Разработчикам. Процесс настройки сервиса Firebase Cloud Messaging описан [здесь](https://firebase.google.com/docs/cloud-messaging/ios/client).\n\nДалее, в делегате MessagingDelegate необходимо установить fcmToken для Carrot SDK:\n\n```swift\nimport FirebaseMessaging\nimport CarrotSDK\nextension AppDelegate: MessagingDelegate {  \n    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {\n        if let fcmToken = fcmToken {\n            CarrotNotificationService.shared.setToken(fcmToken)\n        } else {\n            print(\"Carrotquest SDK error: fcmToken not found\")\n        }\n        ...\n    }\n}\n```\n\nДля отображения уведомлений, необходимо добавить код в UNUserNotificationCenterDelegate:\n\n```swift\nimport CarrotSDK\nextension AppDelegate: UNUserNotificationCenterDelegate {\n    func userNotificationCenter(\n        _ center: UNUserNotificationCenter,\n        willPresent notification: UNNotification,\n        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -\u003e Void) {\n        let notificationService = CarrotNotificationService.shared\n        if notificationService.canHandle(notification) {\n            notificationService.show(notification, completionHandler: completionHandler)\n        } else {\n            // Логика для пользовательских уведомлений\n        }\n    }\n}\n```\n\nДля обработки кликов на уведомления:\n\n```swift\nimport CarrotSDK\nextension AppDelegate: UNUserNotificationCenterDelegate {\n    func userNotificationCenter(\n        _ center: UNUserNotificationCenter,\n        didReceive response: UNNotificationResponse,\n        withCompletionHandler completionHandler: @escaping () -\u003e Void) {\n        let notificationService = CarrotNotificationService.shared\n        if notificationService.canHandle(response) {\n            notificationService.clickNotification(notificationResponse: response)\n        } else {\n            // Логика для пользовательских уведомлений\n        }\n        completionHandler()\n    }\n}\n```\n\n# Objective-C\n\n\u003ca name=\"init_objc\"\u003e\u003c/a\u003e\n\n## Инициализация\n\nДля инициализации Carrot quest вам нужно добавить следующий код в файл AppDelegate вашего приложения:\n\n```objective-c\n#import \"CarrotSDK/CarrotSDK.h\"\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n  \t....\n    Carrot *carrot = [Carrot shared];\n    [\n        carrot\n        setupWithApiKey: API-KEY\n        successHandler: ^(){\n            NSLog(@\"Carrotquest SDK connected\");\n        }\n        errorHandler: ^(NSString *error){\n            NSLog(@\"Carrotquest SDK error: %@\", error);\n    }];\n  \t....\n    return YES;\n}\n```\n\n\u003ca name=\"auth_objc\"\u003e\u003c/a\u003e\n\n## Авторизация пользователей\n\nЕсли в вашем приложении присутствует авторизация пользователей, вы можете передать ID пользователя в Carrot quest. Существует два способа авторизации: напрямую передать userAuthKey, передать hash генерируемый у вас на бэке.\n\n1. Вход через user auth key:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  authWithUserId: userId\n  withUserAuthKey: userAuthKey\n  successHandler: ^(NSString *carrotId){\n      NSLog(@\"Carrotquest SDK user auth successed, CarrotId: %@\", carrotId);\n  }\n  errorHandler: ^(NSString *error){\n      NSLog(@\"Carrotquest SDK user auth error: %@\", error);\n}];\n```\n\n2. Вход через hash:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  authWithUserId: userId\n  withHash: hash\n  successHandler: ^(NSString *carrotId){\n      NSLog(@\"Carrotquest SDK user auth successed, CarrotId: %@\", carrotId);\n  }\n  errorHandler: ^(NSString *error){\n      NSLog(@\"Carrotquest SDK user auth error: %@\", error);\n}];\n```\n\nДля реализации функции выхода:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  logoutWithSuccessHandler: ^(){\n     NSLog(@\"Carrotquest SDK user logout successed\");\n  } errorHandler: ^(NSString *error){\n     NSLog(@\"Carrotquest SDK user logout error: %@\", error);\n}];\n```\n\n\u003ca name=\"prop_objc\"\u003e\u003c/a\u003e\n\n## Свойства пользователей\n\nВы можете установить необходимые свойства пользователя с помощью:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  setUserProperty:userProperties\n]\n```\n\nГде `userProperties` это объект типа `[UserProperty]`.\n\nДля описания свойств пользователя используйте класс `UserProperty`:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\nUserProperty *userProp = [[UserProperty alloc] initWithKey: key value: value];\nUserProperty *userProp = [[UserProperty alloc] initWithKey: key value: value operation: @\"updateOrCreate\"];\n```\n\nБолее подробно про `Operations` можно прочитать в разделе [«Свойства пользователя»](https://developers.carrotquest.io/props/#_3).\n\n`Внимание!`\n\nПоле `key` не может начинаться с символа `$`.\n\n\nДля установки [системных свойств](https://developers.carrotquest.io/props/#_4) реализовано 2 класса `CarrotUserProperty` и `EcommerceUserProperty`.\n\n\u003ca name=\"event_objc\"\u003e\u003c/a\u003e\n\n## События\n\nДля отслеживания событий используйте:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  trackEventWithName: name\n  withParams: params\n];\n```\n\nгде `params` \u0026mdash; дополнительные параметры для события в виде JSON-строки.\n\n\u003ca name=\"tracking_objc\"\u003e\u003c/a\u003e\n\n## Трекинг навигации\n\nB SDK есть возможность трекинга навигации внутри приложения для того, чтобы при необходимости запускать различные триггерные сообщения на определенных экранах. Для этого используйте метод:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[carrot trackScreen:@\"screenName\"];\n```\n\n\u003ca name=\"chat_objc\"\u003e\u003c/a\u003e\n\n## Чат с оператором\n\nВы можете дать пользователю мобильного приложения возможность перейти в чат с оператором из любого места. Это можно реализовать двумя разными путями - через плавающую кнопку, либо напрямую вызвав метод открытия чата в любое нужное время.\n\n### Плавающая кнопка (Floating Button)\n\nВиджет предоставляющий быстрый доступ к чату. Добавить кнопку можно с помощью следующего метода:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[carrot showButtonIn: self.view];\n```\n\nДля того чтобы скрыть кнопку возпльзуйтесь методом:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[carrot hideButton];\n```\n\n### Открытие чата из произвольного места\n\nОткрыть чат можно также, вызвав из произвольного места (после инициализации) следующий код:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[carrot openChat];\n```\n\n### Получение количества непрочтенных диалогов и сообщений\n\nДля отслеживания количества непрочтенных диалогов:\n\n```objective-c\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  getUnreadConversationsCount:^(NSInteger count){\n\t\tNSLog(@\"Carrotquest SDK dialogs count: %ld\", (long)count);\n}];\n```\n\nи для количества непрочтенных сообщений:\n\n```objective-c\nCarrot.shared.getUnreadMessagesCount({ count in\n    print(\"Carrotquest SDK messages count: \\(count)\")\n})\nCarrot *carrot = [Carrot shared];\n[\n  carrot\n  getUnreadMessagesCount:^(NSInteger count){\n\t\tNSLog(@\"Carrotquest SDK dialogs count: %ld\", (long)count);\n}];\n```\n\n\u003ca name=\"custom_url_opener_objc\"\u003e\u003c/a\u003e\n\n## Открытие ссылок вручную\n\nДля того, чтобы при клике на ссылку внутри SDK правильно работали диплинки (universal link) существует специальный метод ручного управления методом открытия ссылок. Его можно вызвать где угодно, но лучше всего где-то в вашем AppDeletage/SceneDelegate рядом с инициализацией SDK:\n\n```objective-c\nCustomUrlOpener *opener = [CustomUrlOpener shared];\n\n[\n  opener\n  for: 1\n  customLogic: ^(NSURL *url){\n       // Любая кастомная логика по открытию ссылок\n   }\n];\n```\n\nКак вы можете заметить, первый аргумент, который имеет label `for` на 4 доступных варианта:\n\n- push - изменяет логику при клике на ссылку в пуше\n- chat - изменяет логику при клике на ссылку в чате\n- popup - изменяет логику при клике на ссылку в попапе\n- all - изменяет логику при клике на ссылку во всех 3 местах\n\nТаким образом, если вы хотите обработать клики на диплинк (universal link) во всех местах SDK, можно написать какой-то такой код:\n\n```objective-c\nCustomUrlOpener *opener = [CustomUrlOpener shared];\n\n[\n  opener\n  for: 3\n  customLogic: ^(NSURL *url){\n       if ([[url host] containsString:@\"ВАШ ДОМЕН\"]) {\n            [[CustomUrlOpener shared] openUniversalLink:url];\n        } else {\n            [[CustomUrlOpener shared] openBrowserLink:url];\n        }\n   }\n];\n```\n\n\u003ca name=\"notif_objc\"\u003e\u003c/a\u003e\n\n## Уведомления\n\nДля работы с уведомлениями SDK использует сервис Firebase Cloud Messaging. В связи с этим необходимо получить ключ и отправить его в Carrot. Вы можете найти поле для ввода ключа на вкладке Настройки \u003e Разработчикам. Процесс настройки сервиса Firebase Cloud Messaging описан [здесь](https://firebase.google.com/docs/cloud-messaging/ios/client).\n\nДалее, в делегате MessagingDelegate необходимо установить fcmToken для Carrot SDK:\n\n```objective-c\n#import \"CarrotSDK/CarrotSDK.h\"\n#import \u003cFirebase.h\u003e\n\n- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {\n    CarrotNotificationService *service = [CarrotNotificationService shared];\n    [service setToken: fcmToken];\n}\n```\n\nДля отображения уведомлений, необходимо добавить код в AppDelegate:\n\n```objective-c\n#import \u003cUserNotifications/UserNotifications.h\u003e\n\n- (void)userNotificationCenter:(UNUserNotificationCenter *)center\n       willPresentNotification:(UNNotification *)notification\n         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {\n    CarrotNotificationService *service = [CarrotNotificationService shared];\n    if ([service canHandle:notification]) {\n        [service show:notification appGroudDomain:nil completionHandler:completionHandler];\n    } else {\n        // Логика для пользовательских уведомлений\n    }\n}\n```\n\nДля обработки кликов на уведомления:\n\n```objective-c\n#import \u003cUserNotifications/UserNotifications.h\u003e\n\n- (void)userNotificationCenter:(UNUserNotificationCenter *)center\ndidReceiveNotificationResponse:(UNNotificationResponse *)response\n         withCompletionHandler:(void(^)(void))completionHandler {\n    CarrotNotificationService *service = [CarrotNotificationService shared];\n    if ([service canHandleWithResponse:response]) {\n        [service clickNotificationWithNotificationResponse:response appGroudDomain:nil openLink:true];\n    } else {\n        // Логика для пользовательских уведомлений\n    }\n}\n```\n\nПодробнее о том, зачем нужен пункт appGroudDomain можно почитать [тут](#notif_extension). \n\nПодробнее о том, зачем нужен пункт openLink можно почитать [тут](#Push+link).\n\n\u003ca name=\"important_push\"\u003e\u003c/a\u003e\n\n## Важная информация о Push уведомлениях\n\nНеобходимо добавить в info.plist вашего проекта параметр:\n\n```xml\n\u003ckey\u003eFirebaseAppDelegateProxyEnabled\u003c/key\u003e\n\u003cstring\u003e0\u003c/string\u003e\n```\n\nИ обязательно, убедиться, что поле имеет значение string. Если кратко, то это переключает управление уведолмениями в ручной режим и позволяет SDK правильно функционировать. Подробнее можете почитать [тут](https://firebase.google.com/docs/cloud-messaging/ios/client?hl=ru).\n\n\u003ca name=\"notif_extension\"\u003e\u003c/a\u003e\n\n## Дублирование уведомлений и статистика доставленных пушей\n\nМы используем 2 канала доставки сообщений, поэтому в некоторых случаях уведомления могут дублироваться. Например: при выходе из приложения, или при очень быстром удалении уведомления, возможно получение повтороного уведомления. Для предотвращения такого поведения нужно создать Notification Service Extension. В Xcode, в списке файлов выберите свой проект, а затем File/New/Target/Notification Service Extension.\n\nПосле чего необходимо зарегистрировать AppGroup в [Apple Developer Portal](https://developer.apple.com/account/resources/identifiers/list/applicationGroup). Identifier App Group должен быть уникальным, и начинаться на \"group.\" иначе Xcode его не примет. \n\nТеперь необходимо добавить Identifier в Xcode:\n\n![AppGroup](https://raw.githubusercontent.com/carrotquest/ios-sdk/dashly/assets/AppGroup.png)\n\n1) В списке файлов выберите свой проект. \n\n2) В списке targets выберете пункт с именем вашего проекта. \n\n3) Во вкладке \"Singing \u0026 Capabitities\" нажмите на \"+ Capability\". \n\n4) В выпадающем списке найдите найдите и выберите App Group.\n\n5) На вкладке появится пустой список для идентификаторов App Group. Добавте туда Identifier, который зарегистрировали в Apple Developer Portal ранее. \n\n6) Вернитесь к списку Targets. Аналогичным образом добавте App Group к вашему Notification Service Extension. \n\n\nВнесите изменения в метод инициализирующий библиотеку:\n```\n   Carrot.shared.setup(\n   ...\n       withAppGroup: \u003cgroup_id\u003e,\n   ...\n   )\n```\n\nТеперь нужно добавить логику в ваш Notification Service Extension. В списке файлов, должна была появиться новая папка с именем вашего Notification Service Extension. Добавте код в файл NotificationService.swift:\n\n```swift\nimport UserNotifications\nimport CarrotSDK\n\nclass NotificationService: CarrotNotificationServiceExtension {\n    override func setup() {\n        self.apiKey = \u003capi_key\u003e\n        self.domainIdentifier = \u003cgroup_id\u003e\n    }\n    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -\u003e Void) {\n        \u003cваша логика\u003e\n        super.didReceive(request, withContentHandler: contentHandler) \n    }\n}\n```\n\nОбновите ваш pod файл, добавьте:\n```\n   target 'NotificationService' do\n     inherit! :search_paths\n     pod 'CarrotquestSDK'\n   end\n```\n\nИ напоследок, нужно передать Identifier зарегистрированный в Apple Developer Portal ранее в метод show в UNUserNotificationCenterDelegate:\n\n```swift\nlet domain = \"Identifier зарегистрированный в Apple Developer Portal ранее\"\nnotificationService.show(notification, appGroudDomain: domain, completionHandler: completionHandler)\n```\n\n\u003ca name=\"notifications_unsubscribe\"\u003e\u003c/a\u003e\n\n## Метод отписки от пушей\n\nСуществуют методы отписать конкретного пользователя от пушей и от всех рассылок в принципе. \n\nМетод для отписки от пушей:\n\n```swift\nimport CarrotSDK\n\nCarrotNotificationService.shared.pushNotificationsUnsubscribe()\n```\n\nМетод для отписки от всех рассылок:\n\n```swift\nimport CarrotSDK\n\nCarrotNotificationService.shared.pushCampaignsUnsubscribe()\n```\n\n\u003ca name=\"localization\"\u003e\u003c/a\u003e\n\n## Локализация\n\nДля того, чтобы SDK автоматически подтягивал и русскую локализацию, кроме стандартной, английской, необходимо убедиться, что в Xcode проекте такая локализация включена. \n\n![Локализация](https://raw.githubusercontent.com/carrotquest/ios-sdk/master/assets/Localozations.png)\n\n\u003ca name=\"xcode15\"\u003e\u003c/a\u003e\n\n## Xcode 15\n\nЕсли вы используете Xcode 15 и выше, и CocoaPods 1.12.1 и ниже, то у вас возникнет ошибка директорий, вроде такой:\n\n![Локализация](https://raw.githubusercontent.com/carrotquest/ios-sdk/master/assets/ErrorXcode15.png)\n\nЧтобы исправить это, добавьте следующий код в конец своего podfile:\n\n```ruby\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    target.build_configurations.each do |config|\n      if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference\n        xcconfig_path = config.base_configuration_reference.real_path\n        IO.write(xcconfig_path, IO.read(xcconfig_path).gsub(\"DT_TOOLCHAIN_DIR\", \"TOOLCHAIN_DIR\"))\n      end\n    end\n  end\nend\n```\n\nВозможно, в будущем, CocoaPods обновится, и этот код придется удалить, но в данный момент, он необходим. \n\n\u003ca name=\"Push+link\"\u003e\u003c/a\u003e\n\n## Использование ссылок в пушах\n\nНебольшой словарь терминов, перед тем как мы начнем:\n\nUniversal link (еще его называют Deeplink, но это не терминология Apple):\n\n```html\nhttps://example.com/section\n```\n\nURL scheme:\n\n```html\nexample://section\n```\n\nИтак, вы можете приложить ссылку к пушу. \n\n![PushLink](https://raw.githubusercontent.com/carrotquest/ios-sdk/master/assets/Push1.png)\n\nОднако, не все так просто. Внутри обработчика пуша лежит функция:\n\n```swift\nif let clickActionUrl = URL(string: \"Ваша ссылка\") {\n\t\tUIApplication.shared.open(clickActionUrl, options: [:])\n}\n```\n\nПростейшая логика. Однако, по какой-то причине, функция iOS для открытия ссылок, указанная выше, не распознает универсальную ссылку приложения, если она вызывается из этого же приложения. Это отправит пользователя прямо в браузер.\n\nПоэтому, есть два возможных варианта решения проблемы:\n\n1. URL Scheme\n2. Ручная обработка Universal link\n\n-----\n\n1. URL Scheme\n\nЕсли в вашем приложении настроены URL Scheme то все уже готово. Просто приложите нужную схему к пушу. \n\nДалее прикладываю небольшой туториал по настройке URL Scheme.\n\nURL Scheme - это более простой и надежный способ открыть нужную страницу в приложении, в отличии от Universal Link. Однако, они не выглядят как ссылка из интернета:\n\n```html\ndeeplink://test\n```\n\nПерейдем к настройке. Выберите цель в настройках проекта Xcode и перейдите на вкладку «Информация». Внизу страницы вы найдете раздел «URL Types».\n\n![URL_scheme](https://raw.githubusercontent.com/carrotquest/ios-sdk/master/assets/Push2.png)\n\nНажав `+`, мы можем создать новый тип. В качестве идентификатора люди часто повторно используют пакет приложения. Для схем URL-адресов мы рекомендуем использовать название приложения (или сокращенное название), чтобы оно было как можно более кратким. В нем не должно быть никаких специальных символов. Мы будем использовать `deeplink` в качестве примера.\n\nВаше приложение готово распознать URL схему, теперь нам нужно обработать его, когда мы его получим.\n\nПриложение фиксирует открытие следующим образом в более ранних приложениях, в которых есть только `AppDelegate`.\n\n```swift\nextension AppDelegate {\n\n    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -\u003e Bool {\n\n        print(url)\n        return true\n    }\n}\n```\n\nДля новых приложений, включающих SceneDelegate, необходимо добавить обработчик еще и туда. Важно отметить, что метод AppDelegateне будет вызван, даже если вы его реализуете.\n\n```swift\nextension SceneDelegate {\n    func scene(_ scene: UIScene, openURLContexts URLContexts: Set\u003cUIOpenURLContext\u003e) {\n        guard let firstUrl = URLContexts.first?.url else {\n            return\n        }\n\n        print(firstUrl.absoluteString)\n    }\n}\n```\n\nЕсли хотите проверить ссылку, введите ее в браузере Safari. Так же, доступен вариант для быстрой проверки на симуляторе. Вот команда для терминала: \n\n```bash\nxcrun simctl openurl booted \"deeplink://test\"\n```\n\n2. Ручная обработка Universal link\n\nВернитесь к обработчику кликов на пуши, и передайте аргумент false в параметр openLink:\n\n```swift\nCarrotNotificationService.shared.clickNotification(\n\t\tnotificationResponse: response,\n\t\topenLink: false\n)\n```\n\nЗатем, нужно достать ссылку из объекта response, который пришел в пуше. Мы заранее подготовили для этого функцию:\n\n```swift\nlet link: String? = CarrotNotificationService.shared.getLink(from: response)\n```\n\nОбратите внимание, что функция возвращает опционал, потому что пуш не всегда содержит ссылку.\n\nТаким образом, в методе обработки кликов на пуши, у вас получится что-то такое:\n\n```swift\nimport CarrotSDK\nextension AppDelegate: UNUserNotificationCenterDelegate {\n    func userNotificationCenter(\n        _ center: UNUserNotificationCenter,\n        didReceive response: UNNotificationResponse,\n        withCompletionHandler completionHandler: @escaping () -\u003e Void) {\n        let notificationService = CarrotNotificationService.shared\n        if notificationService.canHandle(response) {\n            notificationService.clickNotification(notificationResponse: response, openLink: false)\n\t\t\t\t\t\tif let link = CarrotNotificationService.shared.getLink(from: response) {\n\t\t\t\t\t\t\t\tprint(link)\n\t\t\t\t\t\t\t\t// Обработчик открытия Universal link\n        }\n        completionHandler()\n    }\n}\n```\n\n\u003ca name=\"TurnOffLogs\"\u003e\u003c/a\u003e\n\n## Отлючение дебажных логов\n\nДля отключения дебажных логов от встроенного в SDK moya, и от самого SDK, необходимо добавить специальный ключ в info.plist вашего проекта. \n\n```XML (Plist)\n\u003ckey\u003emoyaLog\u003c/key\u003e\n\u003cstring\u003e0\u003c/string\u003e\n```\n\n0 - логи выключены\n\n1 - логи включены\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarrotquest%2Fios-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcarrotquest%2Fios-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarrotquest%2Fios-sdk/lists"}