SmartCaptcha Yandex на iOS: инструкция по внедрению

от автора

Привет! Меня зовут Александр, я iOS-разработчик в IT-компании SimbirSoft. В этой статье я расскажу, как интегрировать Yandex SmartCaptcha в iOS-приложение — от подготовки до решения возможных трудностей.

Настройка Yandex SmartCaptcha на первый взгляд может показаться простой задачей, но на практике она требует внимательности, точной настройки и понимания архитектуры приложения. Я поделюсь личным опытом внедрения этого инструмента, объясню, какие нюансы стоит учесть, а также как избежать ошибок.

Материал предназначен для iOS-разработчиков, у которых уже есть базовые знания мобильной разработки, и кто хочет быстро и корректно внедрить капчу от Яндекса в свое iOS-приложение.

В первой части мы с вами рассмотрим, как настроить визуализацию капчи на web-стороне, а во второй — как интегрировать данный инструмент в ваше iOS-приложение.

Содержание

  1. Настройка визуализации капчи на web-стороне

  2. Интеграция в iOS приложение

Пример реализации

Заключение

Настройка визуализации капчи на web-стороне

Чтобы работать с капчей, для этого нужно в личном кабинете получить ключ. Он выглядит примерно так: ysc1_ADJdjadjkandanjkdakjDHkakdahkdkda

Также нужно создать капчу, подробное описание есть в документации, останавливаться не буду.

Yandex SmartCaptcha состоит из двух блоков:

Первый блок Yandex SmartCaptcha

Первый блок Yandex SmartCaptcha

Механика требует нажатия на галочку для проверки, также есть на выбор другой блок в виде слайдера.

Первый срабатывает в 90% случаев, в 10% открывается второй блок:

Второй блок Yandex SmartCaptcha

Второй блок Yandex SmartCaptcha

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

Можно настроить цвет и вид блоков:

Image

Интеграция в iOS приложение

1. Настройка JS части

Создадим константу и заполним body во viewModel (можно сделать отдельным JSON-файлом):

   let body = """         <html>         <head>             <meta charset=«UTF-8"> // Настраиваем внешний вид капчи для мобильных устройств. Если этого не сделать, капча будет растянута, так как по умолчанию она оптимизирована для веб-версии.             <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">             <script> // Подписываемся на готовность капчи к представлению function onSmartCaptchaReady(widgetId) {             if (!window.smartCaptcha) {             throw new Error("SmartCaptcha is not present");         }          // Подписываемся на показ капчи         window.smartCaptcha.subscribe(             widgetId,             "challenge-visible",             handleChallengeVisible         );          // Подписываемся на скрытие капчу         window.smartCaptcha.subscribe(           widgetId,           "challenge-hidden",           handleChallengeHidden         );   // Подписываемся на успешный event показа капчи         window.smartCaptcha.subscribe(widgetId, "success", handleSuccess);         }         // У капчи есть жизненный цикл:  // captchaDidFinish — когда капча успешно завершилась         function handleSuccess(token) {             sendIos("captchaDidFinish", token);         }          // challengeDidAppear — когда пользователь смахнул вниз второй блок(bottom sheet)         function handleChallengeVisible() {             sendIos("challengeDidAppear");         }           // challengeDidDisappear — капча находиться в не пройденном состоянии         function handleChallengeHidden() {             sendIos("challengeDidDisappear");         }           // Метод для взаимодействия с IOS-частью function sendIos(...args) {             if (args.length == 0) {                   return;             }                      const message = {                 method: args[0],                 data: args[1] !== undefined ? args[1] : ""             };                      if (window.webkit) {                 window.webkit.messageHandlers.NativeClient.postMessage(message);                 }             }     // Загрузка body капчи             </script>               <script src="https://smartcaptcha.yandexcloud.net/captcha.js?render=onload&onload=onloadFunction" defer></script>         </head>         <body>             <div                 id="captcha-container"                 class="smart-captcha"                 data-sitekey=«Ваш ключ"                 data-hl="ru"                 data-callback="callback">                <script>         function onloadFunction() {             if (window.smartCaptcha) {               const container = document.getElementById('captcha-container');                        const widgetId = window.smartCaptcha.render(container, {                 sitekey: «Ваш ключ",                 hl: "ru",               });               onSmartCaptchaReady(widgetId)             }           }         </script>             </div>         </body>         </html>         """   }

2. Настройка нативной части

1. Создаем:

  private lazy var webView: WKWebView = {         let configuration = WKWebViewConfiguration()  // Регистрируем конфигурацию         configuration.userContentController.add(self, name: "NativeClient")         let webView = WKWebView(frame: .zero, configuration: configuration)         return webView     }()

2. Расставляем констрейты под наши нужды

3. Cоздаем enum с жизненным циклом капчи:

enum CaptchaState: String {     case captchaDidFinish     case challengeDidAppear     case challengeDidDisappear }

4.  Загружаем loadCaptchaBody во ViewDidLoad:

// Создаем url во viewModel  var url = Foundation.URL(string: “Ваша ссылка”)      private func loadCaptchaBody() {         if let baseURL = viewModel.url { // Загружаем наш JS код             webView.loadHTMLString(viewModel.body, baseURL: baseURL)         } else {             print("Invalid urlAuth")         }     }

5.  Подписываемся под делегат WKScriptMessageHandler и используем метод userContentController:

extension AuthorizationViewController: WKScriptMessageHandler {     func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {   guard let jsData = message.body as? [String: String],             let methodName = jsData["method"] else { return }          if let captchaState = CaptchaState(rawValue: methodName) {             switch captchaState { //  Когда капча завершилась успешно             case .captchaDidFinish: // Здесь отправляем токен                 viewModel.validateToken(jsData["data"] ?? «") // К примеру со взаимодействием UI, можно свернуть клавиатуру, кнопка далее не скрыта             case .challengeDidAppear: // Срабатывает, когда сворачивается bottom sheet, капча не закончена и пользователь вернулся к первому шагу             case .challengeDidDisappear:   // Срабатывает в первоначальном кейсе, когда капча не пройдена             }         }     } }

6.  Нужно отправить токен во viewModel. В моем случае я использую RxSwift, наблюдаю за наличием токена, и если он есть, делаю активной кнопку «Далее» (наличие токена, одна из проверок (к примеру, обычно еще есть проверка «маски» номера телефона или email). Метод validateToken вызывается в пункте 5.

  func validateToken(_ text: String) {         validateTokenCaptchaPhoneRelay.accept(text)     }

7. В метод, где происходит валидация телефона или email, вставляем проверку на наличие токена.

    func validatePhone(_ text: String) {         guard !validateTokenCaptchaPhoneRelay.value.isEmpty else {             print(“Токен не найден”)             return         }     }

8. Очищаем токен и перезапускаем капчу при каждом появлении экрана в viewWillAppear.

    private func resetCaptcha() {         webView.evaluateJavaScript("window.smartCaptcha.reset()")         viewModel.clearCaptchaToken()     }  // Очищаем токен во ViewModel   func clearCaptchaToken() {         validateTokenCaptchaPhoneRelay.accept("")     }

9. Если у вас будет такой же кейс, как у меня — нужно сделать неактивной вторую часть экрана. Придется делать градиентом, потому что подложка у WebView черная и изменить ее нельзя.

Пример реализации

Заключение

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

Спасибо за внимание! Больше авторских материалов для Mobile-разработчиков от моих коллег читайте в соцсетях SimbirSoft – ВКонтакте и Telegram.


ссылка на оригинал статьи https://habr.com/ru/articles/914178/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *