Initializing the SDK
Before using any of the modules, you must initialize the SDK. This method needs to be called only once during the SDK lifecycle.
For standard Flutter integrations, you can initialize the SDK with initAmani.
bool initSuccess = await AmaniSDK().initAmani(
server: "https://server.example",
customerToken: "customer_token",
customerIdCardNumber: "customer_id_card_number",
lang: "tr",
useLocation: true,
sharedSecret: "optional shared secret",
apiVersion: AmaniApiVersion.v2,
).catchError((err) {
// TODO: Handle the error.
});
if (initSuccess) {
// Call any of the modules
IdCapture idCaptureModule = AmaniSDK().getIDCapture();
idCaptureModule.setType("XXX_ID_0");
} else {
throw Exception("Failed to initialize AmaniSDK");
}
Android-only Configure Usage
For Android integrations, the SDK can also be initialized with the configure-based flow.
This flow uses:
setConfigure()to configure the Android SDK.startAmaniSDKWithConfigure()to start the SDK session with the profile token and customer information.
setConfigure() and startAmaniSDKWithConfigure() are intended for Android usage.
For iOS and existing standard Flutter integrations, you can continue using initAmani().
The configure-based Android flow is useful when you want to:
- Enable only the dynamic features required by your flow.
- Reduce unnecessary module initialization.
- Improve first-load behavior by avoiding unused SDK modules.
- Prepare your integration for the newer Android SDK initialization approach.
Dynamic Features
Dynamic features are modular Android SDK components that can be initialized depending on your verification flow.
If you do not specify enabledFeatures, all available features may be enabled by default. This can increase the initial load time because unnecessary modules may also be prepared.
For better performance, we recommend enabling only the features required by your use case.
| Feature | Description |
|---|---|
AmaniAndroidDynamicFeature.idCapture | Enables ID document scanning and capture |
AmaniAndroidDynamicFeature.idHologramDetection | Enables hologram detection on the ID document |
AmaniAndroidDynamicFeature.nfcScan | Enables NFC chip reading for supported documents |
AmaniAndroidDynamicFeature.selfieAuto | Enables automatic selfie capture |
AmaniAndroidDynamicFeature.selfiePoseEstimation | Enables selfie liveness detection with pose estimation |
Usecase 1: Android Configure with All Main Features
Use this setup when your Android flow may require ID capture, hologram detection, NFC, selfie capture, and pose estimation.
import 'dart:io' show Platform;
final AmaniSDK _amaniSDK = AmaniSDK();
Future<void> initAmani() async {
if (Platform.isAndroid) {
await _amaniSDK.setConfigure(
server: "https://server.example",
enabledFeatures: const [
AmaniAndroidDynamicFeature.idCapture,
AmaniAndroidDynamicFeature.idHologramDetection,
AmaniAndroidDynamicFeature.nfcScan,
AmaniAndroidDynamicFeature.selfieAuto,
AmaniAndroidDynamicFeature.selfiePoseEstimation,
],
);
final result = await _amaniSDK.startAmaniSDKWithConfigure(
token: "profile_token",
id: "customer_id_card_number",
lang: "tr",
);
print(result.isTokenExpired);
}
}
In this use case:
setConfigure()prepares the Android SDK.enabledFeaturesdefines which dynamic modules should be used.startAmaniSDKWithConfigure()starts the SDK session.- The server URL is provided during the configure step.
- The profile token and customer ID are provided during the session start step.
Usecase 2: Android Configure with Selected Features
If your flow does not require every module, you should enable only the necessary features.
For example, if your flow only requires ID capture and automatic selfie capture:
import 'dart:io' show Platform;
final AmaniSDK _amaniSDK = AmaniSDK();
Future<void> initAmani() async {
if (Platform.isAndroid) {
await _amaniSDK.setConfigure(
server: "https://server.example",
enabledFeatures: const [
AmaniAndroidDynamicFeature.idCapture,
AmaniAndroidDynamicFeature.selfieAuto,
],
);
final result = await _amaniSDK.startAmaniSDKWithConfigure(
token: "profile_token",
id: "customer_id_card_number",
lang: "tr",
);
print(result.isTokenExpired);
}
}
This approach is recommended when your verification flow does not use NFC, hologram detection, or pose estimation.
Full Platform-based Initialization Example
The following example shows how to use the configure-based flow for Android, while keeping the existing initAmani() flow for iOS.
import 'dart:io' show Platform;
class _HomeScreenState extends State<HomeScreen> {
final AmaniSDK _amaniSDK = AmaniSDK();
Future<void> initAmani() async {
if (Platform.isAndroid) {
await _amaniSDK.setConfigure(
server: "https://server.example",
enabledFeatures: const [
AmaniAndroidDynamicFeature.idCapture,
AmaniAndroidDynamicFeature.idHologramDetection,
AmaniAndroidDynamicFeature.nfcScan,
AmaniAndroidDynamicFeature.selfieAuto,
AmaniAndroidDynamicFeature.selfiePoseEstimation,
],
);
final result = await _amaniSDK.startAmaniSDKWithConfigure(
token: "profile_token",
id: "customer_id_card_number",
lang: "tr",
);
print(result.isTokenExpired);
} else {
bool initSuccess = await _amaniSDK.initAmani(
server: "https://server.example",
customerToken: "profile_token",
customerIdCardNumber: "customer_id_card_number",
useLocation: true,
apiVersion: AmaniApiVersion.v2,
lang: "tr",
).catchError((err) {
throw Exception(err);
});
if (initSuccess) {
final customerInfo = await _amaniSDK.getCustomerInfo();
// Get customer id
print(customerInfo.id);
} else {
throw Exception("Failed to initialize AmaniSDK");
}
}
await for (final delegateEvent in _amaniSDK.getDelegateStream()) {
print("Delegate event received");
print(delegateEvent);
}
}
void initState() {
super.initState();
initAmani();
}
}
Optional Configuration Parameters
Depending on your SDK version and integration, the configure-based Android flow can also support additional configuration options.
Shared Secret
sharedSecret is used to sign and validate network requests.
- This value will be provided confidentially by the Amani team.
- If it is not provided, the SDK can still work.
- However, upload requests may be unsigned.
- For production environments, using
sharedSecretis recommended when available.
Upload Source
uploadSource is used to distinguish uploads from different sources.
Common upload source values are:
KYCVIDEOPASSWORD
If not specified, the default upload source is KYC.
Starting with version 2.2.4, you can set the upload source on Android and iOS with setUploadSource(). The init methods reset it to KYC, so call it after them.
- Android: Call it after
setConfigure()and beforestartAmaniSDKWithConfigure(). You can also passuploadSourcedirectly tosetConfigure(). - iOS: Call it after
initAmani(), and again after every re-init.
import 'package:flutter_amanisdk/amaniAndroidConfigure.dart';
// Android
await AmaniSDK().setConfigure(
server: "https://server.example",
uploadSource: AmaniUploadSource.video,
);
// Android and iOS
await AmaniSDK().setUploadSource(AmaniUploadSource.video);
SSL Pinning
SSL Pinning provides additional network security by validating SSL certificates.
If SSL Pinning is exposed by your Flutter SDK version, it should be configured before calling setConfigure().
If an invalid SSL certificate is provided, the SDK may throw an exception. Always handle SSL Pinning configuration with proper error handling.
Registering the event stream
For getting errors from this SDK, information about the KYC profile, and step results as the steps are updated, listen to the event stream.
Each event is a map with type and data fields. Start listening once, for example in initState(), and cancel the subscription in dispose().
type | Description |
|---|---|
profileStatus | The KYC profile status has changed. |
stepModel | A step result has been updated. |
error | An error occurred in the SDK. |
mrzInfoDelegate | iOS only. The MRZ data has been read from the ID. |
import 'dart:async';
class _HomeScreenState extends State<HomeScreen> {
StreamSubscription<dynamic>? _delegateSubscription;
void initState() {
super.initState();
_delegateSubscription = AmaniSDK().getDelegateStream().listen((event) {
final String? type = event["type"];
final dynamic data = event["data"];
switch (type) {
case "profileStatus":
// Handle the profile status
break;
case "stepModel":
// Handle the step result
break;
case "error":
// Handle the error
break;
}
});
}
void dispose() {
_delegateSubscription?.cancel();
super.dispose();
}
}
getDelegateStream() returns the same broadcast stream on every call. You can listen to it from more than one screen.
Understanding the module system
Each type of document has different modules that you can set the document type and capture with it.
Modules use the same pattern of containing:
startsetTypeupload
Each start method can have different parameters, with subtle differences.
Which Initialization Method Should I Use?
| Use case | Recommended method |
|---|---|
| Standard Flutter integration | initAmani() |
| iOS integration | initAmani() |
| Android integration with dynamic feature control | setConfigure() + startAmaniSDKWithConfigure() |
| Android integration where only selected modules are needed | setConfigure() + startAmaniSDKWithConfigure() |
For most existing integrations, initAmani() is enough.
For Android integrations where you want more control over dynamic features and initialization behavior, use the configure-based flow.