Yandex SmartCaptcha в приложении Android на Flutter
Flutter
В этом руководстве вы создадите проект, который включает серверное и мобильное приложения:
- Серверное приложение будет предоставлять HTML-страницу для загрузки SmartCaptcha и проверять результат выполнения капчи пользователем мобильного приложения.
- Мобильное приложение покажет страницу с капчей и отправит запрос на проверку результата.
Порядок создания проекта:
- Создайте капчу.
- Подготовьте инструменты разработки.
- Создайте и запустите серверное приложение.
- Создайте мобильное приложение.
- Запустите мобильное приложение в эмуляторе и проверьте работу SmartCaptcha.
Перед началом работы
Зарегистрируйтесь в Yandex Cloud и создайте платежный аккаунт:
- Перейдите в консоль управления
, затем войдите в Yandex Cloud или зарегистрируйтесь. - На странице Yandex Cloud Billing
убедитесь, что у вас подключен платежный аккаунт, и он находится в статусеACTIVE
илиTRIAL_ACTIVE
. Если платежного аккаунта нет, создайте его и привяжите к нему облако.
Если у вас есть активный платежный аккаунт, вы можете создать или выбрать каталог, в котором будет работать ваша инфраструктура, на странице облака
Подробнее об облаках и каталогах.
Создайте капчу
- Создайте капчу.
- На вкладке Обзор получите ключи капчи:
- Ключ клиента — для загрузки страницы с капчей;
- Ключ сервера — для получения результата прохождения капчи.
Подготовьте инструменты разработки
Далее в руководстве предполагается, что все действия выполняются на вашем компьютере.
- Установите Python
. - Установите Flask
. - Установите Flutter SDK
. - Установите Android Studio
. - В Android Studio подключите плагины Dart и Flutter:
- Откройте меню File → Settings → Plugins.
- На вкладке Marketplace в поле поиска введите
Dart
. - Нажмите Install, чтобы установить плагин.
- Таким же образом найдите и установите плагин
Flutter
.
- Настройте путь к Flutter SDK:
- Откройте меню File → Settings → Languages & Frameworks → Flutter.
- В поле Flutter SDK path выберите папку, в которую вы установили Flutter SDK.
Создайте и запустите серверное приложение
-
Создайте новую папку, например,
web-captcha-app
. -
В папке
web-captcha-app
создайте файлapp.py
:Код серверного приложения
from flask import Flask, request, jsonify, render_template import requests app = Flask(__name__) SMARTCAPTCHA_SERVER_KEY = "<ключ_сервера>" # тестовый эндпоинт @app.route('/', methods=['GET']) def helo(): return "Hello from CAPTCHA App", 200 # эндпоинт, возвращающий страницу для встраивания капчи @app.route('/captcha', methods=['GET']) def render_captcha(): return render_template("captcha.html") # эндпоинт валидации результата прохождения капчи @app.route('/validate-captcha', methods=['POST']) def validate_captcha(): data = request.json token = data.get('token') if not token: return jsonify({"status": "error", "message": "Missing CAPTCHA token"}), 400 # валидация ответа response = requests.post( "https://smartcaptcha.yandexcloud.net/validate", data={ "secret": SMARTCAPTCHA_SERVER_KEY, "token": token, "ip": request.remote_addr # Optional: get user's IP }, timeout=2 ) if response.status_code != 200: return jsonify({"status": "error", "message": "Captcha validation error"}), 500 # обработка ответа captcha_result = response.json() if captcha_result.get("status") == "ok": return jsonify({"status": "ok"}), 200 else: return jsonify({"status": "robot"}), 200 if __name__ == '__main__': app.run(debug=True, port=5000)
-
В папке
web-captcha-app
создайте папкуtemplates
и в ней создайте файлcaptcha.html
:HTML-страница с кодом капчи
<!DOCTYPE html> <html lang="en"> <head> <title>SmartCaptcha Mobile</title> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <script> function onSmartCaptchaReady() { if (!window.smartCaptcha) { throw new Error("SmartCaptcha is not present"); } const params = getParameters(); const widgetId = window.smartCaptcha.render( "captcha-container", params ); window.smartCaptcha.subscribe( widgetId, "challenge-visible", handleChallengeVisible ); window.smartCaptcha.subscribe( widgetId, "challenge-hidden", handleChallengeHidden ); window.smartCaptcha.subscribe(widgetId, "success", handleSuccess); if (params.invisible) { window.smartCaptcha.execute(widgetId); } } function handleSuccess(token) { // Send the CAPTCHA token to Flutter using postMessage for webview_flutter if (window.jsBridge) { window.jsBridge.postMessage(token); } } function handleChallengeVisible() { console.log("Challenge became visible"); } function handleChallengeHidden() { console.log("Challenge hidden"); } function getParameters() { const result = {}; if (!window.location.search) { return result; } const queryParams = new URLSearchParams(window.location.search); queryParams.forEach((value, key) => { result[key] = value; }); result.test = result.test === "true"; result.invisible = result.invisible === "true"; result.hideShield = result.hideShield === "true"; result.webview = true; return result; } </script> <script> function reloadPage() { if (window.jsBridge) { window.jsBridge.postMessage('pageReloaded'); } window.location.reload(); } </script> <script src="https://smartcaptcha.yandexcloud.net/captcha.js?render=onload&onload=onSmartCaptchaReady" defer ></script> </head> <body> <noscript> You need to enable JavaScript to run this app. </noscript> <div id="captcha-container" class="smart-captcha"></div> <div style="margin:20px"><button onclick="reloadPage()">Reload</a> </body> </html>
-
В командной строке перейдите в папку
web-captcha-app
и запустите серверное приложение:cd web-captcha-app python3 app.py
Создайте мобильное приложение
-
В Android Studio создайте новый проект. Для этого откройте меню File → New → New Flutter Project.
-
Проверьте путь к Flutter SDK и нажмите Next.
-
В поле Project name укажите имя проекта, например,
mobile-captcha-app
. -
Нажмите Create.
-
После загрузки проекта замените содержимое файла
main.dart
на следующий код:Код мобильного приложения на языке Dart
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; void main() { WidgetsFlutterBinding.ensureInitialized(); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('SmartCaptcha Example'), ), body: WebViewExample(), ), ); } } class WebViewExample extends StatefulWidget { @override _WebViewExampleState createState() => _WebViewExampleState(); } class _WebViewExampleState extends State<WebViewExample> { late final WebViewController _controller; String result = ""; @override void initState() { super.initState(); _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) // разрешить выполнение скриптов ..addJavaScriptChannel( // открыть канал для ответов от приложения 'jsBridge', onMessageReceived: (message) { if (message.message == 'pageReloaded') { _handlePageReload(); } else { String token = message .message; // получение токена от капчи print("CAPTCHA token received: $token"); _sendTokenToServer(token); // отправка токена на валидацию } }, ); _loadCaptchaPageFromServer(); } @override Widget build(BuildContext context) { return Column( children: [ Expanded(child: WebViewWidget(controller: _controller)), SizedBox(height: 20), if (result.isNotEmpty) Text( result, style: TextStyle(fontSize: 20, color: result == "Passed" ? Colors.green : Colors.red), ), ], ); } void _loadCaptchaPageFromServer() { setState(() { result = "Not Done"; // Сброс статуса при первой загрузке страницы }); // Загрузка капчи _controller.loadRequest(Uri.parse('<URL_серверного_приложения>:5000/captcha?sitekey=<ключ_клиета>')); // замените плейсхолдер на полученный ключ для клиенсткой части } void _handlePageReload() { setState(() { result = "Not Done"; // Сброс статуса при перезагрузке страницы }); } Future<void> _sendTokenToServer(String token) async { const String serverValidationUrl = '<URL_серверного_приложения>:5000/validate-captcha'; // замените плейсхолдер на полученный ключ для клиенсткой части try { setState(() { result = "Checking"; // Выставление статуса валидации токена }); final response = await http.post( Uri.parse(serverValidationUrl), body: jsonEncode({'token': token}), headers: { 'Content-Type': 'application/json', }, ); if (response.statusCode == 200) { var jsonResponse = jsonDecode(response.body); setState(() { result = jsonResponse['status'] == 'ok' ? 'Passed' : 'Robot'; }); } else { setState(() { result = 'Error'; }); } } catch (e) { print('Error: $e'); setState(() { result = 'Error'; }); } } }
Важно
Если вы запустили серверное приложение на компьютере с Flutter и Android Studio, не используйте адрес
http://localhost
в качестве URL сервера. Используйте IP-адрес внутренней подсети, например,http://10.0.2.2
. -
Добавьте необходимые зависимости:
- Откройте файл
pubspec.yaml
в корне проекта. - В секцию
dependencies
добавьтеwebview_flutter
иhttp
:
dependencies: flutter: sdk: flutter # добавьте webview_flutter и http webview_flutter: ^4.0.0 http: ^0.13.5
- Откройте файл
-
Чтобы в тестовых целях использовать незащищенный HTTP-протокол:
- Откройте файл
\android\app\src\main\AndroidManifest.xml
. - Добавьте в секцию
application
опциюandroid:usesCleartextTraffic="true"
:
<application android:label="capcha_app" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" <!-- добавьте эту строку --> android:usesCleartextTraffic="true" >
- Откройте файл
Запустите приложение и проверьте работу SmartCaptcha
Чтобы запустить мобильное приложение на эмуляторе:
- В Android Studio откройте меню Tools → Device Manager и активируйте мобильное устройство. Например, предустановленный по умолчанию Medium Phone API 35.
- Запустите файл
main.dart
одним из способов:- в верхней панели рядом с именем файла нажмите кнопку запуска;
- откройте меню Run → Run 'main.dart'.
- Дождитесь, когда завершится процесс компиляции и приложение загрузится в эмулятор.
Чтобы проверить работу SmartCaptcha:
- Выполните задание капчи.
- Обратите внимание, как красный статус
Not Done
в нижней части экрана приложения кратковременно изменится на статусChecking
, а затем на зеленый статусPassed
(если задание было выполнено верно). - Чтобы повторить тест, на странице под капчей нажмите Reload.