Integrate Flutter for OpenHarmony with the V3 architecture
Use a WebView to embed Alibaba Cloud Captcha 2.0 in a Flutter for OpenHarmony app. This approach loads your existing HTML5 business page inside the app and bridges verification results back to Flutter through a JavaScript handler, so you avoid native dependency issues while keeping full access to rapid HTML5 Captcha updates.
How it works
All communication flows through three components:
HTML5 client — Your business page runs Captcha 2.0 and, on success, passes the verification parameters to Flutter via
window.flutter_inappwebview.callHandler.Flutter app — Loads the HTML5 page in an
InAppWebViewand registers a JavaScript handler (testInterface) to receive the parameters.Server — Receives the parameters from Flutter and calls
VerifyIntelligentCaptchato complete secondary authentication.
Prerequisites
Before you begin, make sure you have:
Enabled Alibaba Cloud Captcha 2.0
Created an authentication scenario with Integration Method set to Webview+H5 (Supports apps and mini-programs)
A Flutter for OpenHarmony app (this guide uses version
3.22.0-ohos-1.0.4as an example)
WebView requirements
For Captcha 2.0 to work inside a WebView, the following conditions must be met:
JavaScript enabled —
javaScriptEnabled: trueinInAppWebViewGroupOptionsNetwork access — The
ohos.permission.INTERNETandohos.permission.GET_NETWORK_INFOpermissions declared inmodule.json5Stable base URL — Load HTML content with a consistent base URL (for example,
https://localhost) so that Captcha scripts resolve correctly
Step 1: Integrate Captcha 2.0 on the HTML5 client
Integrate the Captcha 2.0 client code in your HTML5 business page. For implementation details, see Integrate the client for web and H5 pages (V3 architecture).
If your business uses the V2 architecture, see Integrate the client for web and H5 pages (V2 architecture).
In the success callback, forward the verification parameters to Flutter using the flutter_inappwebview JavaScript handler:
// success callback function
function success(captchaVerifyParam) {
// Send the verification result to Flutter (using the communication method of flutter_inappwebview)
if (window.flutter_inappwebview && window.flutter_inappwebview.callHandler) {
window.flutter_inappwebview.callHandler('testInterface', captchaVerifyParam);
}
}The handler name testInterface must match the name registered in the Flutter app (see Step 3).
Step 2: Integrate Captcha 2.0 on the server
On your server, integrate the Captcha 2.0 SDK and call VerifyIntelligentCaptcha to perform secondary authentication on the parameters received from Flutter. For implementation details, see Server-side integration.
Step 3: Load the Captcha page in Flutter
1. Add the flutter_inappwebview dependency
In pubspec.yaml, add the WebView plugin that supports the HarmonyOS platform:
dependencies:
flutter:
sdk: flutter
# Use the WebView plugin that supports the HarmonyOS platform
flutter_inappwebview:
git:
url: https://gitcode.com/openharmony-sig/flutter_inappwebview
path: "flutter_inappwebview"2. Declare network permissions
In ohos/entry/src/main/module.json5, add the following permissions under requestPermissions:
{
"module": {
"name": "entry",
"type": "entry",
// Other configurations
// ...
"requestPermissions": [
{"name": "ohos.permission.INTERNET"},
{"name": "ohos.permission.GET_NETWORK_INFO"}
]
}
}3. Create the Captcha page
Create a Flutter widget that loads the HTML5 page in an InAppWebView and registers the testInterface handler to receive verification parameters:
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter/services.dart';
class CaptchaPage extends StatefulWidget {
const CaptchaPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<CaptchaPage> createState() => _CaptchaPageState();
}
class _CaptchaPageState extends State<CaptchaPage> {
InAppWebViewController? _controller;
@override
void initState() {
super.initState();
}
// Handle the Captcha verification result
void _handleCaptchaResult(dynamic captchaVerifyParam) {
try {
print('Received Captcha parameters: $captchaVerifyParam');
// Check if the parameters are empty
if (captchaVerifyParam == null) {
throw Exception('Received empty verification parameters');
}
// Directly send the verification parameters to the server
_sendToServer(captchaVerifyParam);
} catch (e) {
print('Failed to process Captcha parameters: $e');
_showSnackBar('Failed to process verification parameters: $e', isError: true);
}
}
// Send verification parameters to the server (example)
Future<void> _sendToServer(dynamic captchaVerifyParam) async {
try {
// Call your server-side API for secondary authentication here
print('Preparing to send to the server for verification: $captchaVerifyParam');
// Simulate successful server-side verification
_showSnackBar('Server-side verification successful', isError: false);
} catch (e) {
print('Server-side verification failed: $e');
_showSnackBar('Server-side verification failed: $e', isError: true);
}
}
void _showSnackBar(String message, {bool isError = false}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: isError ? Colors.red : Colors.green,
duration: const Duration(seconds: 3),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: _buildWebViewContent(),
);
}
// Build the WebView content
Widget _buildWebViewContent() {
return Stack(
children: [
InAppWebView(
initialData: InAppWebViewInitialData(
data: "",
),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
javaScriptEnabled: true,
useShouldOverrideUrlLoading: true,
),
),
onWebViewCreated: (InAppWebViewController controller) async {
_controller = controller;
// Add a JavaScript handler
_controller!.addJavaScriptHandler(
handlerName: 'testInterface',
callback: (args) {
if (args.isNotEmpty) {
_handleCaptchaResult(args[0]);
}
},
);
// Load the HTML content
try {
String htmlContent = await rootBundle.loadString('assets/captcha.html');
await _controller!.loadData(data: htmlContent, baseUrl: WebUri('https://localhost'));
} catch (e) {
print('Failed to load HTML: $e');
_showSnackBar('Failed to load Captcha page: $e', isError: true);
}
},
),
],
);
}
}4. Register the Captcha page in main.dart
import 'package:flutter/material.dart';
import 'captcha_page.dart'; // Import the Captcha page
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Alibaba Cloud Captcha Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const CaptchaPage(title: 'Alibaba Cloud Captcha Demo'),
);
}
}5. Declare the HTML asset
In pubspec.yaml, register the HTML file as an asset:
flutter:
assets:
- assets/index.html6. Build and run
Compile and run the project:
flutter build hap --debugVerify the integration
After the app starts, trigger the Captcha challenge in your HTML5 page. A successful integration shows a green SnackBar with "Server-side verification successful" after you complete the challenge. If the SnackBar does not appear, check the console output for error messages from _handleCaptchaResult or _sendToServer.
Troubleshooting
Captcha does not load in the WebView
Check that javaScriptEnabled is set to true in InAppWebViewGroupOptions. Also confirm that both ohos.permission.INTERNET and ohos.permission.GET_NETWORK_INFO are declared in module.json5. Missing either permission prevents the WebView from reaching Captcha servers.
The JavaScript handler receives no data
Confirm that the handler name in the HTML5 success callback (window.flutter_inappwebview.callHandler('testInterface', ...)) exactly matches the name registered in addJavaScriptHandler (handlerName: 'testInterface'). A name mismatch will cause the parameters not to be received by the Flutter handler.
HTML file fails to load
Verify that the asset path in rootBundle.loadString('assets/captcha.html') matches the path declared in pubspec.yaml. After changing pubspec.yaml, run flutter pub get and rebuild.