flutter_meon_kyc
A comprehensive Flutter package for handling Know Your Customer (KYC) processes in mobile applications. This package provides an advanced WebView-based KYC solution with automatic permission handling, IPV (In-Person Verification) support, payment link integration, and complete lifecycle management.
Features
- π Easy Integration - Simple API with sensible defaults
- π― Automatic Permission Management - Camera, microphone, and location permissions
- π€ IPV Support - In-Person Verification with automatic detection
- π³ Payment Link Handling - UPI and payment app integration
- π Lifecycle Management - Automatic session cleanup with logout
- β Success Detection - Intelligent detection of KYC completion
- π¨ Customizable UI - Custom styles and header configuration
- π± Platform Support - Android and iOS compatible
- π Error Handling - Comprehensive error management
- π Logging - Built-in logging for debugging
Installation
Add flutter_meon_kyc to your pubspec.yaml:
dependencies:
flutter_meon_kyc: ^2.0.1
Run:
flutter pub get
Platform Setup
Android
Add the following permissions to your android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Optional: For payment links -->
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="upi" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="phonepe" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="gpay" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="paytmmp" />
</intent>
</queries>
<application>
<!-- Your app configuration -->
</application>
</manifest>
Update android/app/build.gradle:
android {
compileSdkVersion 34 // or higher
defaultConfig {
minSdkVersion 21 // or higher
targetSdkVersion 34
}
}
iOS
Add the following to your ios/Runner/Info.plist:
<dict>
<!-- Camera permission -->
<key>NSCameraUsageDescription</key>
<string>Camera access is required for KYC verification</string>
<!-- Microphone permission -->
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for video verification</string>
<!-- Location permission -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location access is required for KYC verification</string>
<!-- Optional: Allow arbitrary loads for specific domains -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
Update ios/Podfile (minimum iOS version):
platform :ios, '12.0'
Usage
Basic Usage
import 'package:flutter/material.dart';
import 'package:flutter_meon_kyc/flutter_meon_kyc.dart';
class KYCScreen extends StatelessWidget {
const KYCScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: MeonKYC(
companyName: 'your-company-name',
onSuccess: (data) {
print('KYC Completed: $data');
// Handle success - navigate to next screen
Navigator.of(context).pop();
},
onError: (error) {
print('KYC Error: $error');
// Handle error
},
onClose: () {
print('KYC Closed');
Navigator.of(context).pop();
},
),
);
}
}
Advanced Usage
MeonKYC(
// Required
companyName: 'your-company-name',
// Optional - Workflow type
workflow: 'individual', // or 'business', 'custom-workflow'
// Optional - Callbacks
onSuccess: (data) {
// data contains:
// - status: 'completed'
// - timestamp: ISO8601 timestamp
// - url: current URL
// - message: success message
print('Success: ${data['message']}');
Navigator.of(context).pushReplacementNamed('/dashboard');
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $error')),
);
},
onClose: () {
Navigator.of(context).pop();
},
// Optional - Feature flags
enableIPV: true, // Enable In-Person Verification
enablePayments: true, // Enable payment link handling
autoRequestPermissions: true, // Auto-request permissions for IPV
// Optional - Permission control (for IPV)
enableCameraPermission: true, // Request camera permission
enableMicrophonePermission: true, // Request microphone permission
enableLocationPermission: true, // Request location permission
showHeader: true, // Show custom header bar
// Optional - Customization
headerTitle: 'Complete Your KYC',
baseURL: 'https://live.meon.co.in', // Or your custom domain
// Optional - Custom styles
customStyles: {
'container': BoxDecoration(
color: Colors.white,
),
'header': BoxDecoration(
color: Colors.blue,
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
'headerTitle': TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
},
)
Full Example with Navigation
import 'package:flutter/material.dart';
import 'package:flutter_meon_kyc/flutter_meon_kyc.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'KYC Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('KYC Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const KYCScreen(),
),
);
},
child: const Text('Start KYC Process'),
),
),
);
}
}
class KYCScreen extends StatelessWidget {
const KYCScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: MeonKYC(
companyName: 'demo-company',
workflow: 'individual',
enableIPV: true,
enablePayments: true,
autoRequestPermissions: true,
showHeader: true,
headerTitle: 'Complete KYC',
onSuccess: (data) {
// Show success dialog
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Success'),
content: Text('KYC completed at ${data['timestamp']}'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(); // Close dialog
Navigator.of(context).pop(); // Close KYC screen
},
child: const Text('OK'),
),
],
),
);
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error: $error'),
backgroundColor: Colors.red,
),
);
},
onClose: () {
Navigator.of(context).pop();
},
),
);
}
}
API Reference
MeonKYC Widget
Required Parameters
| Parameter | Type | Description |
|---|---|---|
companyName |
String |
Your company identifier (required) |
Optional Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
workflow |
String |
'individual' |
KYC workflow type ('individual', 'business', etc.) |
onSuccess |
Function(Map<String, dynamic>) |
null |
Called when KYC is completed successfully |
onError |
Function(String) |
null |
Called when an error occurs |
onClose |
Function() |
null |
Called when user closes the KYC screen |
customStyles |
Map<String, dynamic>? |
null |
Custom styles for container, header, and title |
enableIPV |
bool |
true |
Enable In-Person Verification features |
enablePayments |
bool |
true |
Enable payment link handling |
autoRequestPermissions |
bool |
true |
Auto-request permissions when IPV step is detected |
enableCameraPermission |
bool |
true |
Request camera permission for IPV (can be controlled from frontend) |
enableMicrophonePermission |
bool |
true |
Request microphone permission for IPV (can be controlled from frontend) |
enableLocationPermission |
bool |
true |
Request location permission for IPV (can be controlled from frontend) |
showHeader |
bool |
true |
Show custom header with navigation controls |
headerTitle |
String |
'KYC Process' |
Title text in the header |
baseURL |
String |
'https://live.meon.co.in' |
Base URL for the KYC service |
Callback Data Structures
onSuccess Data
{
'status': 'completed',
'timestamp': '2025-11-25T10:30:00.000Z',
'url': 'https://live.meon.co.in/company/thank-you',
'message': 'KYC process completed successfully'
}
Features in Detail
1. Automatic Permission Management
The package automatically requests and manages the following permissions:
- Camera: For document scanning and face verification
- Microphone: For video verification
- Location: For verification purposes
Dynamic Permission Control - You can control which permissions to request from the frontend:
MeonKYC(
companyName: 'your-company',
enableCameraPermission: true, // Request camera
enableMicrophonePermission: true, // Request microphone
enableLocationPermission: false, // Skip location (if not needed)
)
Permissions are requested:
- Automatically when IPV step is detected (if
autoRequestPermissionsis true) - Only the permissions you've enabled will be requested
- With proper error handling and settings navigation
- Users can retry or open device settings if denied
Permission Storage: When permissions are granted, they are stored in:
sessionStorage- For current sessionlocalStorage- For persistent storageCookies- For cross-domain persistence (7 days expiry)
This ensures that the WebView and any embedded iframes can access the permission states reliably.
2. IPV Detection & Auto-Reload
The package intelligently detects IPV (In-Person Verification) steps by monitoring URLs for:
face-finder.meon.co.in/ipvpaths- Keywords:
face,video
When detected:
- Permissions are automatically requested (if enabled)
- Header title changes to "IPV Verification"
- Permission state is injected into the WebView
White Screen Auto-Fix: If the IPV page loads with a white screen (no content detected), the package will automatically reload the page (up to 2 attempts) to ensure proper loading. This prevents users from seeing blank screens and having to manually refresh.
3. Payment Link Handling
Supports opening payment apps directly:
- UPI apps: PhonePe, Google Pay, Paytm, BHIM
- Google Pay with multiple scheme fallbacks
- Automatic detection and external app launching
- Prevents WebView from loading payment URLs
4. Success Detection
Intelligent detection of KYC completion:
- Monitors page content for success patterns
- Checks for: "Thank You" + "journey has been completed" + "Redirecting in"
- Uses MutationObserver for dynamic content
- Prevents duplicate success callbacks
- Automatically performs logout before success callback
5. Session Management
Complete lifecycle management:
- Initial Logout: Cleans up any existing session before starting
- Final Logout: Automatically logs out after successful completion
- Graceful handling of logout failures
6. Custom Styling
Customize the appearance:
customStyles: {
'container': BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.purple],
),
),
'header': BoxDecoration(
color: Color(0xFF1E88E5),
),
'headerTitle': TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.white,
),
}
7. Header Controls
The custom header provides:
- Back Button: Navigate back in WebView history (when available)
- Refresh Button: Reload current page
- Close Button: Close KYC with confirmation dialog
- Dynamic Title: Changes based on current step (IPV, etc.)
Troubleshooting
Permissions Not Working
- Ensure permissions are added to
AndroidManifest.xml(Android) andInfo.plist(iOS) - Set
autoRequestPermissions: true - Check device settings to ensure permissions are granted
WebView Not Loading
- Verify
companyNameis correct - Check network connectivity
- Ensure
baseURLis accessible - Check logs for detailed error messages
Payment Links Not Opening
- Add
<queries>section toAndroidManifest.xml - Ensure payment apps are installed on the device
- Set
enablePayments: true
Back Button Not Working
The package uses PopScope to handle Android back button. If you're wrapping the widget in another PopScope or WillPopScope, it may conflict.
Migration from SDKCall
If you're using the old SDKCall widget, migrate to MeonKYC:
Old Code:
SDKCall(
companyName: 'company',
workflowName: 'individual',
)
New Code:
MeonKYC(
companyName: 'company',
workflow: 'individual',
onSuccess: (data) => print('Success'),
onError: (error) => print('Error'),
onClose: () => Navigator.pop(context),
)
The SDKCall widget is deprecated but still available for backward compatibility.
Debugging
Enable detailed logging by checking console output. The package uses the logger package with tags:
[MeonKYC]- General messages- Look for permission, navigation, and success detection logs
Requirements
- Flutter: >= 1.17.0
- Dart SDK: >= 2.19.0 < 4.0.0
- Android: minSdkVersion 21+
- iOS: 12.0+
License
MIT License - See LICENSE file for details
Support
For issues and feature requests, please visit: GitHub Issues
Changelog
See CHANGELOG.md for version history and updates.
Note: This package requires an active Meon KYC account and valid company configuration. Contact Meon support for setup assistance.